pull/2/head
Jeff Weston 2019-09-11 11:52:22 -04:00
parent 32c42ee9c0
commit de8a3c799b
34 changed files with 1114 additions and 510 deletions

View File

@ -1,12 +1,12 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML> <HTML>
<HEAD> <HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-15"> <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<TITLE>NORM Developer&rsquo;s Guide</TITLE> <TITLE>NORM Developers Guide</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)"> <META NAME="GENERATOR" CONTENT="NeoOffice/J 1.1 (Unix)">
<META NAME="AUTHOR" CONTENT="Robert Adamson"> <META NAME="AUTHOR" CONTENT="Robert Adamson">
<META NAME="CREATED" CONTENT="20040824;15180000"> <META NAME="CREATED" CONTENT="20040824;14180000">
<META NAME="CHANGED" CONTENT="20050621;14191600"> <META NAME="CHANGED" CONTENT="20050907;17092400">
<META NAME="DESCRIPTION" CONTENT="NORM Object Functions 42 NORM Object Functions NORM_OBJECT_STREAM NORM Sender Functions 19 NORM Sender Functions "> <META NAME="DESCRIPTION" CONTENT="NORM Object Functions 42 NORM Object Functions NORM_OBJECT_STREAM NORM Sender Functions 19 NORM Sender Functions ">
<META NAME="KEYWORDS" CONTENT="norm object value application function "> <META NAME="KEYWORDS" CONTENT="norm object value application function ">
<STYLE> <STYLE>
@ -51,7 +51,7 @@
</TD> </TD>
<TD WIDTH=371> <TD WIDTH=371>
<P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal"> <P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal">
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=6 STYLE="font-size: 28pt"><B>NORM<BR>Developer&rsquo;s <FONT FACE="Helvetica, sans-serif"><FONT SIZE=6 STYLE="font-size: 28pt"><B>NORM<BR>Developers
<BR>Guide</B></FONT></FONT></P> <BR>Guide</B></FONT></FONT></P>
</TD> </TD>
</TR> </TR>
@ -99,8 +99,6 @@ communication needs.</P>
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table <H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table
of Contents</H1> of Contents</H1>
<DIV ID="Table of Contents1" DIR="LTR"> <DIV ID="Table of Contents1" DIR="LTR">
<P STYLE="margin-top: 0.25in; font-style: normal"><BR>
</P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Overview</B></FONT></P> <P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Overview</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Initialization</B></FONT></P> Initialization</B></FONT></P>
@ -136,6 +134,10 @@ of Contents</H1>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEventType">NormEventType</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEventType">NormEventType</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEvent">NormEvent</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEvent">NormEvent</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFlushMode">NormFlushMode</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormProbingMode">NormProbingMode</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNackingMode">NormNackingMode</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRepairBoundary">NormRepairBoundary</A></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API <P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
Initialization and Operation</B></FONT></P> Initialization and Operation</B></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormCreateInstance()">NormCreateInstance()</A></FONT></P>
@ -151,6 +153,7 @@ of Contents</H1>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetUserData()">NormGetUserData()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetUserData()">NormGetUserData()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetLocalNodeId()">NormGetLocalNodeId()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormGetLocalNodeId()">NormGetLocalNodeId()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxPort()">NormSetTxPort()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTxPort()">NormSetTxPort()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetRxPortReuse()">NormSetRxPortReuse()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetMulticastInterface()">NormSetMulticastInterface()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetMulticastInterface()">NormSetMulticastInterface()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTTL()">NormSetTTL()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTTL()">NormSetTTL()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTOS()">NormSetTOS()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTOS()">NormSetTOS()</A></FONT></P>
@ -166,6 +169,9 @@ of Contents</H1>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitCacheBounds()">NormSetTransmitCacheBounds()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetTransmitCacheBounds()">NormSetTransmitCacheBounds()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetAutoParity()">NormSetAutoParity()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetAutoParity()">NormSetAutoParity()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttMax()">NormSetGrttMax()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingMode()">NormSetGrttProbingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingInterval()">NormSetGrttProbingInterval()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileEnqueue()">NormFileEnqueue()</A></FONT></P> <P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileEnqueue()">NormFileEnqueue()</A></FONT></P>
@ -252,7 +258,7 @@ can be roughly summarized with the following categories of functions:</P>
categories roughly reflects the order of function calls required to categories roughly reflects the order of function calls required to
use NORM in an application. The first step is to create and use NORM in an application. The first step is to create and
initialize, as needed, at least one instance of the NORM API. Then initialize, as needed, at least one instance of the NORM API. Then
one or more NORM transport sessions (where a &ldquo;session&rdquo; one or more NORM transport sessions (where a “session”
corresponds to data exchanges on a given multicast group and host corresponds to data exchanges on a given multicast group and host
port number) may be created and controlled. Applications may port number) may be created and controlled. Applications may
participate as senders and/or receivers within a NORM session. NORM participate as senders and/or receivers within a NORM session. NORM
@ -311,10 +317,10 @@ include the types <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT>
and <FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> which and <FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> which
represent predetermined, fixed-size application data content. The represent predetermined, fixed-size application data content. The
only differentiation with respect to these two types is the implicit only differentiation with respect to these two types is the implicit
&ldquo;hint&rdquo; to the receiver to use non-volatile (i.e. file “hint” to the receiver to use non-volatile (i.e. file system)
system) storage or memory. This &ldquo;hint&rdquo; lets the receiver storage or memory. This “hint” lets the receiver allocate
allocate appropriate storage space with no other information on the appropriate storage space with no other information on the incoming
incoming data. The NORM implementation reads/writes data for the data. The NORM implementation reads/writes data for the
<FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> type directly <FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> type directly
from/to file storage, while application memory space is accessed for from/to file storage, while application memory space is accessed for
the <FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> type. The the <FONT FACE="Courier"><I>NORM_OBJECT_DATA</I></FONT> type. The
@ -324,9 +330,9 @@ Using this transport paradigm, traditional, byte-oriented streaming
transport service (e.g. similar to that provided by a TCP socket) can transport service (e.g. similar to that provided by a TCP socket) can
be provided. Additionally, NORM has provisions for be provided. Additionally, NORM has provisions for
application-defined message-oriented transport where receivers can application-defined message-oriented transport where receivers can
recover message boundaries without any &ldquo;handshake&rdquo; with recover message boundaries without any “handshake” with the
the sender. Stream content is buffered by the NORM implementation sender. Stream content is buffered by the NORM implementation for
for transmission/retransmission and as it is received.</P> transmission/retransmission and as it is received.</P>
<H3 CLASS="western">NORM Data Transmission</H3> <H3 CLASS="western">NORM Data Transmission</H3>
<P CLASS="western" STYLE="font-style: normal">The behavior of data <P CLASS="western" STYLE="font-style: normal">The behavior of data
transport operation is largely placed in the control of the NORM transport operation is largely placed in the control of the NORM
@ -337,14 +343,13 @@ operate in a session, each with independent transmission parameters.
NORM receivers learn needed parameter values from fields in NORM NORM receivers learn needed parameter values from fields in NORM
message headers.</P> message headers.</P>
<P CLASS="western" STYLE="font-style: normal">NORM transport <P CLASS="western" STYLE="font-style: normal">NORM transport
&ldquo;objects&rdquo; (file, data, or stream) are queued for “objects” (file, data, or stream) are queued for transmission by
transmission by NORM senders. NORM senders may also cancel NORM senders. NORM senders may also cancel transmission of objects
transmission of objects at any time. The NORM sender controls the at any time. The NORM sender controls the transmission rate either
transmission rate either manually (fixed transmission rate) or manually (fixed transmission rate) or automatically when NORM
automatically when NORM congestion control operation is enabled. The congestion control operation is enabled. The NORM congestion control
NORM congestion control mechanism is designed to be &quot;friendly&quot; mechanism is designed to be &quot;friendly&quot; to other data flows
to other data flows on the network, fairly sharing available on the network, fairly sharing available bandwidth.</P>
bandwidth.</P>
<P CLASS="western" STYLE="font-style: normal">By default, the NORM <P CLASS="western" STYLE="font-style: normal">By default, the NORM
sender transmits application-enqueued data content, providing repair sender transmits application-enqueued data content, providing repair
transmissions (usually in the form of FEC messages) only when transmissions (usually in the form of FEC messages) only when
@ -427,15 +432,15 @@ application. Thus the &quot;POSIX Threads&quot; library must be
included (&quot;-'pthread&quot;) in the linking step. MacOS/BSD also included (&quot;-'pthread&quot;) in the linking step. MacOS/BSD also
requires the addition of the &quot;-lresolv&quot; (resolver) library requires the addition of the &quot;-lresolv&quot; (resolver) library
and Solaris requires the dynamic loader, network/socket, and resolver and Solaris requires the dynamic loader, network/socket, and resolver
libraries (&quot;&ndash;lnsl &ndash;lsocket &ndash;lresolv&quot;) to libraries (&quot;lnsl lsocket lresolv&quot;) to achieve
achieve successful compilation. The Makefiles in the NORM source successful compilation. The Makefiles in the NORM source code
code distribution are a reference for these requirements. Note that distribution are a reference for these requirements. Note that MacOS
MacOS 9 and earlier are not supported.</P> 9 and earlier are not supported.</P>
<P CLASS="western" STYLE="font-style: normal">Additionally, it is <P CLASS="western" STYLE="font-style: normal">Additionally, it is
critical that the _FILE_OFFSET_BITS macro be consistently defined for critical that the _FILE_OFFSET_BITS macro be consistently defined for
the NORM library build and the application build using the library. the NORM library build and the application build using the library.
The distributed NORM Makefiles have &ndash;D_FILE_OFFSET_BITS=64 set The distributed NORM Makefiles have D_FILE_OFFSET_BITS=64 set in
in the compilation to enable &quot;large file support&quot;. the compilation to enable &quot;large file support&quot;.
Applications built using NORM should have the same compilation option Applications built using NORM should have the same compilation option
set to operate correctly (The definition of the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT> set to operate correctly (The definition of the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
type in &quot;normApi.h&quot; depends upon this compilation flag).</P> type in &quot;normApi.h&quot; depends upon this compilation flag).</P>
@ -583,10 +588,10 @@ session as part of protocol operation. Typically, the application
should not need access to these values, but an API call should not need access to these values, but an API call
<FONT FACE="Courier">NormObjectGetTransportId() </FONT>is provided to <FONT FACE="Courier">NormObjectGetTransportId() </FONT>is provided to
retrieve these values if needed. (<I>Note this type may be retrieve these values if needed. (<I>Note this type may be
deprecated &ndash; it may not be needed at all if the deprecated it may not be needed at all if the NormObjectRequeue()
NormObjectRequeue() function (TBD) is implemented using handles only, function (TBD) is implemented using handles only, but _some_
but _some_ applications requiring persistence even after a system applications requiring persistence even after a system reboot may
reboot may need the ability to recall previous transport ids?</I>)</P> need the ability to recall previous transport ids?</I>)</P>
<H3 CLASS="functionheading-western"><A NAME="NormEventType">NormEventType</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormEventType">NormEventType</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormEventType">NormEventType</A></FONT> <P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormEventType">NormEventType</A></FONT>
is an enumeration of NORM API events. &quot;Events&quot; are used by is an enumeration of NORM API events. &quot;Events&quot; are used by
@ -625,6 +630,41 @@ appropriate system calls (e.g. <I>select()</I> or
NORM protocol engine for notification events (see <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> NORM protocol engine for notification events (see <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT>
description). description).
</P> </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>
<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
these values is given in the descriptions of <FONT FACE="Courier"><A HREF="#NormStreamFlush()">NormStreamFlush()</A></FONT>
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>
<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
these values is given in the description of <FONT FACE="Courier"><A HREF="#NormSetGrttProbingMode()">NormSetGrttProbingMode()</A></FONT>
function.</P>
<H3 CLASS="functionheading-western"><A NAME="NormNackingMode">NormNackingMode</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormNackingMode">NormNackingMode</A></FONT>
consist of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#NormNackingMode">NormNackingMode</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_NONE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_INFO_ONLY,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_NACK_NORMAL<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of
these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormSetDefaultNackingMode()">NormSetDefaultNackingMode()</A></FONT>,
<FONT FACE="Courier"><A HREF="#NormNodeSetNackingMode()">NormNodeSetNackingMode()</A></FONT> and
<FONT FACE="Courier"><A HREF="#NormObjectSetNackingMode()">NormObjectSetNackingMode()</A></FONT> functions.</P>
<H3 CLASS="functionheading-western"><A NAME="NormRepairBoundary">NormRepairBoundary</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormRepairBoundary">NormRepairBoundary</A></FONT>
consist of the following enumeration:</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>enum
<A HREF="#NormRepairBoundary">NormRepairBoundary</A><BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_BOUNDARY_BLOCK,<BR>&nbsp;&nbsp;&nbsp;&nbsp;NORM_BOUNDARY_OBJECT<BR>};</FONT></FONT></P>
<P CLASS="western" STYLE="font-style: normal">The interpretation of
these values is given in the descriptions of the
<FONT FACE="Courier"><A HREF="#NormSetDefaultRepairBoundary()">NormSetDefaultRepairBoundary()</A> </FONT>and
<FONT FACE="Courier"><A HREF="#NormNodeSetRepairBoundary()">NormNodeSetRepairBoundary()</A></FONT> functions.</P>
<H2 CLASS="western">API Initialization and Operation</H2> <H2 CLASS="western">API Initialization and Operation</H2>
<P CLASS="western" STYLE="font-style: normal">The first step in using <P CLASS="western" STYLE="font-style: normal">The first step in using
the NORM API is to create an &quot;instance&quot; of the NORM the NORM API is to create an &quot;instance&quot; of the NORM
@ -1220,9 +1260,57 @@ reception. However, the use of separate transmit/receive ports
allows NORM to discriminate when unicast feedback is occurring and allows NORM to discriminate when unicast feedback is occurring and
thus it is not generally recommended that the transmit port be set to thus it is not generally recommended that the transmit port be set to
the same value as the <FONT FACE="Courier"><U>session</U></FONT> the same value as the <FONT FACE="Courier"><U>session</U></FONT>
receive port. This call <I>must</I> be made <I>before</I> any calls receive port.
to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT> or </P>
<FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> to succeed.</P> <P CLASS="western" STYLE="font-style: normal">Note this call <I>must</I>
be made <I>before</I> any calls to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
or <FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> for the given
<FONT FACE="Courier"><U>session</U></FONT> to succeed.</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="NormSetRxPortReuse()">NormSetRxPortReuse()</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
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>
<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
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
on the same port number, but participating in different multicast
groups.</P>
<P CLASS="western" STYLE="font-style: normal">Note this call <I>must</I>
be made <I>before</I> any calls to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
or <FONT FACE="Courier"><A HREF="#NormStartReceiver()">NormStartReceiver()</A></FONT> for the given
<FONT FACE="Courier"><U>session</U></FONT> to succeed.</P>
<P CLASS="western" STYLE="font-style: normal">This call could also be
used in conjunction with <FONT FACE="Courier"><A HREF="#NormSetMulticastInterface()">NormSetMulticastInterface()</A></FONT>
so that multiple <I>NormSessions</I>, using the same port and
multicast address, could separately cover multiple network interfaces
(and some sort of application-layer bridging of reliable multicast
could be realized if desired).</P>
<H4 CLASS="western">Return Values</H4> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no <P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P> return values.</P>
@ -1462,7 +1550,7 @@ function call include:</P>
The maximum <FONT FACE="Courier"><U>blockSize</U></FONT> allowed The maximum <FONT FACE="Courier"><U>blockSize</U></FONT> allowed
by the 8-bit Reed-Solomon codes in NORM is 255, with the further by the 8-bit Reed-Solomon codes in NORM is 255, with the further
limitation that (<FONT FACE="Courier"><U>blockSize</U></FONT> + limitation that (<FONT FACE="Courier"><U>blockSize</U></FONT> +
<FONT FACE="Courier"><U>numParity</U></FONT>) &le; 255.</P> <FONT FACE="Courier"><U>numParity</U></FONT>) 255.</P>
</TD> </TD>
</TR> </TR>
<TR VALIGN=TOP> <TR VALIGN=TOP>
@ -1483,15 +1571,14 @@ function call include:</P>
that one parity segment can fill any one erasure (missing segment that one parity segment can fill any one erasure (missing segment
(packet)) for a coding block. For a given <FONT FACE="Courier"><U>blockSize</U></FONT>, (packet)) for a coding block. For a given <FONT FACE="Courier"><U>blockSize</U></FONT>,
the maximum <FONT FACE="Courier"><U>numParity</U></FONT> value is the maximum <FONT FACE="Courier"><U>numParity</U></FONT> value is
(255 &ndash; <FONT FACE="Courier"><U>blockSize</U></FONT>). (255 <FONT FACE="Courier"><U>blockSize</U></FONT>). However,
However, note that computational complexity increases note that computational complexity increases significantly with
significantly with increasing <FONT FACE="Courier"><U>numParity</U></FONT> increasing <FONT FACE="Courier"><U>numParity</U></FONT> values and
values and applications may wish to be conservative with respect applications may wish to be conservative with respect to <FONT FACE="Courier"><U>numParity</U></FONT>
to <FONT FACE="Courier"><U>numParity</U></FONT> selection, given selection, given anticipated network packet loss conditions and
anticipated network packet loss conditions and group size group size scalability concerns. Additional FEC code options may
scalability concerns. Additional FEC code options may be provided be provided for this NORM implementation in the future with
for this NORM implementation in the future with different different parameters, capabilities, trade-offs, and computational
parameters, capabilities, trade-offs, and computational
requirements.</P> requirements.</P>
</TD> </TD>
</TR> </TR>
@ -1516,7 +1603,7 @@ implementation.</P>
is returned upon success and <FONT FACE="Courier"><I>false</I></FONT> is returned upon success and <FONT FACE="Courier"><I>false</I></FONT>
upon failure. The reasons failure may occur include limited system upon failure. The reasons failure may occur include limited system
resources or that the network sockets required for communication resources or that the network sockets required for communication
failed to open or properly configure. <I>(TBD &ndash; Provide a failed to open or properly configure. <I>(TBD Provide a
<FONT FACE="Courier">NormGetError(<A HREF="#NormSessionHandle">NormSessionHandle</A> session)</FONT> <FONT FACE="Courier">NormGetError(<A HREF="#NormSessionHandle">NormSessionHandle</A> session)</FONT>
function to retrieve a more specific error indication for this and function to retrieve a more specific error indication for this and
other functions.)</I></P> other functions.)</I></P>
@ -1777,8 +1864,9 @@ NormSetGrttEstimate(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;sess
<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;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;grtt);</FONT></FONT></P> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;grtt);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the <P CLASS="western" STYLE="font-style: normal">This function sets the
sender's estimate of group round-trip timing (GRTT). This function sender's estimate of group round-trip timing (GRTT) for the given
is expected to most typically used to initialize the sender's GRTT NORM <FONT FACE="Courier"><U>session</U></FONT>. This function is
expected to most typically used to initialize the sender's GRTT
estimate prior to the call to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT> estimate prior to the call to <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
when the application has <I>a priori</I> confidence that the default when the application has <I>a priori</I> confidence that the default
initial GRTT value of 0.5 second is inappropriate. The sender GRTT initial GRTT value of 0.5 second is inappropriate. The sender GRTT
@ -1788,7 +1876,7 @@ is active. For experimental purposes (or very special application
needs), this API provides a mechanism to control or disable the needs), this API provides a mechanism to control or disable the
sender GRTT update process (see <FONT FACE="Courier">NormSetGrttProbing()</FONT>). sender GRTT update process (see <FONT FACE="Courier">NormSetGrttProbing()</FONT>).
The <FONT FACE="Courier"><U>grtt</U></FONT> value will be limited to The <FONT FACE="Courier"><U>grtt</U></FONT> value will be limited to
the maximum GRTT as set (see <FONT FACE="Courier">NormSetGrttMax()) the maximum GRTT as set (see <FONT FACE="Courier"><A HREF="#NormSetGrttMax()">NormSetGrttMax()</A>)
</FONT>or the default maximum of 10 seconds. </FONT>or the default maximum of 10 seconds.
</P> </P>
<P CLASS="western" STYLE="font-style: normal">The sender GRTT is <P CLASS="western" STYLE="font-style: normal">The sender GRTT is
@ -1800,7 +1888,125 @@ additional latency into the reliability process (resulting in a
larger virtual <I>delay*bandwidth</I> product for the protocol and larger virtual <I>delay*bandwidth</I> product for the protocol and
potentially requiring more buffer space to maintain reliability). An potentially requiring more buffer space to maintain reliability). An
overly-small GRTT estimate may introduce the potential for feedback overly-small GRTT estimate may introduce the potential for feedback
implosion, limiting the scalability of group size.</P> implosion, limiting the scalability of group size.
</P>
<P CLASS="western" STYLE="font-style: normal">Also note that the
advertised GRTT estimate can also be limited by transmission rate.
When the sender transmission rate is low, the GRTT is also governed
to a lower bound of the nominal packet transmission interval (i.e.,
<FONT FACE="Courier">1/txRate</FONT>). This maintains the “event
driven” nature of the NORM protocol with respect to receiver
reception of NORM sender data and commands.</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="NormSetGrttMax()">NormSetGrttMax()</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
NormSetGrttMax(<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;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;grttMax);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the
sender's maximum advertised GRTT value for the given NORM <FONT FACE="Courier"><U>session</U></FONT>.
The <FONT FACE="Courier"><U>grttMax</U></FONT> parameter, in units
of <I>seconds</I>, limits the GRTT used by the group for scaling
protocol timers, regardless of larger measured round trip times.
The default maximum for the NRL NORM library is 10 seconds. See the
<FONT FACE="Courier"><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A></FONT> function
description for the purpose of the NORM GRTT measurement process.</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="NormSetGrttProbingMode()">NormSetGrttProbingMode()</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
NormSetGrttProbingMode(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;session,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NormProbingMode&nbsp;&nbsp;&nbsp;probingMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the
sender's mode of probing for round trip timing measurement responses
from the receiver set for the given NORM <FONT FACE="Courier"><U>session</U></FONT>.
Possible values for the <FONT FACE="Courier"><U>probingMode</U></FONT>
parameter include <FONT FACE="Courier"><I>NORM_PROBE_NONE</I></FONT>,
<FONT FACE="Courier"><I>NORM_PROBE_PASSIVE</I></FONT>, and
<FONT FACE="Courier"><I>NORM_PROBE_ACTIVE</I></FONT>. The default
probing mode is <FONT FACE="Courier"><I>NORM_PROBE_ACTIVE</I></FONT>.
In this mode, the receiver set explicitly acknowledges NORM sender
GRTT probes (NORM_CMD(CC) messages) with NORM_ACK responses that are
group-wise suppressed. Note that NORM receivers also will include
their response to GRTT probing piggy-backed on any NORM_NACK messages
sent in this mode as well to minimize feedback.
</P>
<P CLASS="western" STYLE="font-style: normal">Note that the
<FONT FACE="Courier"><I>NORM_PROBE_ACTIVE</I></FONT> probing mode is
<I>required</I> and automatically set when NORM congestion control
operation is enabled (see <FONT FACE="Courier"><A HREF="#NormSetCongestionControl()">NormSetCongestionControl()</A></FONT>).
Thus, when congestion control is enabled, the
<FONT FACE="Courier"><A HREF="#NormSetGrttProbingMode()">NormSetGrttProbingMode()</A></FONT> function has no
effect.</P>
<P CLASS="western" STYLE="font-style: normal">If congestion control
operation is not enabled, the NORM applicaiton may elect to reduce
the volume of feedback traffic by setting the <FONT FACE="Courier"><U>probingMode</U></FONT>
to <FONT FACE="Courier"><I>NORM_PROBE_PASSIVE.</I></FONT> Here, the
NORM sender still transmits NORM_CMD(CC) probe messages multiplexed
with its data transmission, but the receiver set does not explicitly
acknowledge these probes. Instead the receiver set is limited to
piggy-backing responses when NORM_NACK messages are generated. Note
that this may, in some cases, introduce some opportunity for bursts
of large volume receiver feedback when the senders estimate of
GRTT is incorrect due to the reduced probing feedback. But, in some
controlled network environments, this option for passive probing may
provide some benefits in reducing protocol overhead.</P>
<P CLASS="western" STYLE="font-style: normal">Finally, the
<FONT FACE="Courier"><U>probingMode</U></FONT> can be set to
<FONT FACE="Courier"><I>NORM_PROBE_NONE</I></FONT> to eliminate the
overhead (and benefits) of NORM GRTT measurement entirely. In this
case, the sender application must explicitly set its estimate of GRTT
using the <FONT FACE="Courier"><A HREF="#NormSetGrttEstimate()">NormSetGrttEstimate()</A></FONT> function.
See this function for a description of the purpose of the NORM GRTT
measurement.</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="NormSetGrttProbingInterval()">NormSetGrttProbingInterval()</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
NormSetGrttProbingInterval(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;session,
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intervalMin,<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;double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intervalMax);</FONT></FONT></P>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function controls
the sender GRTT measurement and estimation process for the given NORM
<FONT FACE="Courier"><U>session</U></FONT>. The NORM sender
multiplexes periodic transmission of NORM_CMD(CC) messages with its
ongoing data transmission or when data transmission is idle. When
NORM congestion control operation is enabled, these probes are sent
once per RTT of the current limiting receiver (with respect to
congestion control rate). In this case the <FONT FACE="Courier"><U>intervalMin</U></FONT>
and <FONT FACE="Courier"><U>intervalMax</U></FONT> parameters (in
units of <I>seconds</I>) control the rate at which the senders
estimate of GRTT is updated. At session start, the estimate is
updated at <FONT FACE="Courier"><U>intervalMin</U></FONT> and the
update interval time is doubled until <FONT FACE="Courier"><U>intervalMax</U></FONT>
is reached. This dynamic allows for a rapid initial estimation of
GRTT and a slower, steady-state update of GRTT. When congestion
control is disabled and NORM GRTT probing is enabled
(NORM_PROBE_ACTIVE or NORM_PROBE_PASSIVE) the <FONT FACE="Courier"><U>intervalMin</U></FONT>
and <FONT FACE="Courier"><U>intervalMax</U></FONT> values also
determine the rate at which NORM_CMD(CC) probes are transmitted by
the sender. Thus by setting larger values for <FONT FACE="Courier"><U>intervalMin</U></FONT>
and <FONT FACE="Courier"><U>intervalMax</U></FONT>, the NORM sender
application can reduce the overhead of the GRTT measurement process.
However, this also reduces the ability of NORM to adapt to changes in
GRTT.</P>
<P CLASS="western" STYLE="font-style: normal">The default NORM GRTT
<FONT FACE="Courier"><U>intervalMin</U></FONT> and <FONT FACE="Courier"><U>intervalMax</U></FONT>
values are 1.0 second and 30.0 seconds, respectively.</P>
<H4 CLASS="western">Return Values</H4> <H4 CLASS="western">Return Values</H4>
<P CLASS="western" STYLE="font-style: normal">This function has no <P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P> return values.</P>
@ -2057,7 +2263,7 @@ limit.</P>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>bool <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormStreamClose(<A HREF="#NormObjectHandle">NormObjectHandle</A> NormStreamClose(<A HREF="#NormObjectHandle">NormObjectHandle</A>
streamHandle,<BR>&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;graceful streamHandle,<BR>&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;graceful
= false);</FONT></FONT></P> = false);</FONT></FONT></P>
@ -2135,7 +2341,7 @@ transmission.</P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormStreamFlush(<A HREF="#NormObjectHandle">NormObjectHandle</A> NormStreamFlush(<A HREF="#NormObjectHandle">NormObjectHandle</A>
streamHandle,<BR>&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;eom streamHandle,<BR>&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;eom
= false,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NormFlushMode&nbsp;&nbsp;&nbsp;&nbsp;flushMode = false,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormFlushMode">NormFlushMode</A>&nbsp;&nbsp;&nbsp;&nbsp;flushMode
= NORM_FLUSH_PASSIVE);</FONT></FONT></P> = NORM_FLUSH_PASSIVE);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function causes an <P CLASS="western" STYLE="font-style: normal">This function causes an
@ -2157,7 +2363,7 @@ NORM to immediately transmit all enqueued data for the stream
(subject to session transmit rate limits), even if this results in (subject to session transmit rate limits), even if this results in
NORM_DATA messages with &quot;small&quot; payloads. If the optional NORM_DATA messages with &quot;small&quot; payloads. If the optional
<FONT FACE="Courier"><U>flushMode</U></FONT> parameter is set to <FONT FACE="Courier"><U>flushMode</U></FONT> parameter is set to
<FONT FACE="Courier"><I>NORM_FLUSH_ACTIV</I></FONT>, the application <FONT FACE="Courier"><I>NORM_FLUSH_ACTIVE</I></FONT>, the application
can achieve reliable delivery of stream content up to the current can achieve reliable delivery of stream content up to the current
write position in an even more proactive fashion. In this case, the write position in an even more proactive fashion. In this case, the
sender additionally, <I>actively</I> transmits NORM_CMD(FLUSH) sender additionally, <I>actively</I> transmits NORM_CMD(FLUSH)
@ -2193,7 +2399,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormStreamSetAutoFlush(<A HREF="#NormObjectHandle">NormObjectHandle</A> NormStreamSetAutoFlush(<A HREF="#NormObjectHandle">NormObjectHandle</A>
streamHandle<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;NormFlushMode&nbsp;&nbsp;&nbsp;&nbsp;flushMode);</FONT></FONT></P> streamHandle<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormFlushMode">NormFlushMode</A>&nbsp;&nbsp;&nbsp;&nbsp;flushMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets <P CLASS="western" STYLE="font-style: normal">This function sets
&quot;<I>automated</I> flushing&quot; for the NORM transmit stream &quot;<I>automated</I> flushing&quot; for the NORM transmit stream
@ -2387,7 +2593,7 @@ does not exist in NORM's default NACK-only operation.</P>
<P CLASS="western" STYLE="font-style: normal">The function returns <P CLASS="western" STYLE="font-style: normal">The function returns
<FONT FACE="Courier"><I>true</I></FONT> upon successful establishment <FONT FACE="Courier"><I>true</I></FONT> upon successful establishment
of the watermark point. The function may return <FONT FACE="Courier"><I>false</I></FONT> of the watermark point. The function may return <FONT FACE="Courier"><I>false</I></FONT>
upon failure (<I>why would it fail? &ndash; TBD</I>).</P> upon failure (<I>why would it fail? TBD</I>).</P>
<H2 CLASS="western">NORM Receiver Functions</H2> <H2 CLASS="western">NORM Receiver Functions</H2>
<H3 CLASS="functionheading-western"><A NAME="NormStartReceiver()">NormStartReceiver()</A></H3> <H3 CLASS="functionheading-western"><A NAME="NormStartReceiver()">NormStartReceiver()</A></H3>
<H4 CLASS="western">Synopsis</H4> <H4 CLASS="western">Synopsis</H4>
@ -2552,7 +2758,7 @@ NACK-messages as well as some ACK messages such as congestion control
feedback. Explicitly solicited ACK messages, such as those used to feedback. Explicitly solicited ACK messages, such as those used to
satisfy sender watermark acknowledgement requests (see satisfy sender watermark acknowledgement requests (see
<FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>) are always unicast to <FONT FACE="Courier"><A HREF="#NormSetWatermark()">NormSetWatermark()</A></FONT>) are always unicast to
the applicable sender. (TBD &ndash; provide API option so that <I>all</I> the applicable sender. (TBD provide API option so that <I>all</I>
messages are multicast.) The default session-wide behavior for messages are multicast.) The default session-wide behavior for
unicast NACKing can be overridden via the <FONT FACE="Courier"><A HREF="#NormNodeSetUnicastNack()">NormNodeSetUnicastNack()</A></FONT> unicast NACKing can be overridden via the <FONT FACE="Courier"><A HREF="#NormNodeSetUnicastNack()">NormNodeSetUnicastNack()</A></FONT>
function for individual remote senders.</P> function for individual remote senders.</P>
@ -2583,7 +2789,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormSetDefaultNackingMode(<A HREF="#NormSessionHandle">NormSessionHandle</A> session, NormSetDefaultNackingMode(<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NormNackingMode&nbsp;&nbsp;&nbsp;nackingMode);</FONT></FONT></P> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNackingMode">NormNackingMode</A>&nbsp;&nbsp;&nbsp;nackingMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the <P CLASS="western" STYLE="font-style: normal">This function sets the
default &quot;nacking mode&quot; used when receiving objects. This default &quot;nacking mode&quot; used when receiving objects. This
@ -2650,7 +2856,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormNodeSetNackingMode(<A HREF="#NormNodeHandle">NormNodeHandle</A>&nbsp;&nbsp;nodeHandle, NormNodeSetNackingMode(<A HREF="#NormNodeHandle">NormNodeHandle</A>&nbsp;&nbsp;nodeHandle,
<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;NormNackingMode <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNackingMode">NormNackingMode</A>
nackingMode);</FONT></FONT></P> nackingMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the <P CLASS="western" STYLE="font-style: normal">This function sets the
@ -2670,7 +2876,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormObjectSetNackingMode(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle, NormObjectSetNackingMode(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle,
<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;NormNackingMode&nbsp;&nbsp;nackingMode);</FONT></FONT></P> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="#NormNackingMode">NormNackingMode</A>&nbsp;&nbsp;nackingMode);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the <P CLASS="western" STYLE="font-style: normal">This function sets the
&quot;nacking mode&quot; used for receiving a specific transport &quot;nacking mode&quot; used for receiving a specific transport
@ -2689,7 +2895,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormSetDefaultRepairBoundary(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;&nbsp;sessionHandle, NormSetDefaultRepairBoundary(<A HREF="#NormSessionHandle">NormSessionHandle</A>&nbsp;&nbsp;sessionHandle,
<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;NormRepairBoundary <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;<A HREF="#NormRepairBoundary">NormRepairBoundary</A>
repairBoundary);</FONT></FONT></P> repairBoundary);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function allows <P CLASS="western" STYLE="font-style: normal">This function allows
@ -2723,7 +2929,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P> &lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void <P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
NormNodeSetRepairBoundary(<A HREF="#NormNodeHandle">NormNodeHandle</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeHandle, NormNodeSetRepairBoundary(<A HREF="#NormNodeHandle">NormNodeHandle</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nodeHandle,
<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;NormRepairBoundary <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;<A HREF="#NormRepairBoundary">NormRepairBoundary</A>
repairBoundary);</FONT></FONT></P> repairBoundary);</FONT></FONT></P>
<H4 CLASS="western">Description</H4> <H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function allows <P CLASS="western" STYLE="font-style: normal">This function allows

Binary file not shown.

BIN
NormLogo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

View File

@ -63,7 +63,7 @@ The following items can be build from this source code release:
be provided as additional documentation in the future) be provided as additional documentation in the future)
2) norm (or norm.exe (WIN32) - command-line "demo" application 3) norm (or norm.exe (WIN32) - command-line "demo" application
built from "common/normApp.cpp" built from "common/normApp.cpp"
(The included "Norm User's Guide" provides a rough overview (The included "Norm User's Guide" provides a rough overview
@ -71,7 +71,7 @@ The following items can be build from this source code release:
updating to be accurate and complete. This demo application updating to be accurate and complete. This demo application
is useful for file transfers (and streaming on Unix)) is useful for file transfers (and streaming on Unix))
3) normTest (or normTest.exe (WIN32)) - very simple test application 4) normTest (or normTest.exe (WIN32)) - very simple test application
(The "normTest" application (see "common/normTest.cpp") is really (The "normTest" application (see "common/normTest.cpp") is really
just a simple playground for preliminary testing of the NORM just a simple playground for preliminary testing of the NORM
@ -80,6 +80,19 @@ The following items can be build from this source code release:
(and better-documented) examples of NORM API usage will be (and better-documented) examples of NORM API usage will be
provided in the future. provided in the future.
5) There is also an "examples" directory in the source code tree
that contains some simplified examples of NORM API usage. The
example set will be expanded as time progresses.
NRL also has started some apps built around NORM including:
A) A reliable multicast "chat" application (users can share files
and images, too) with a GUI. Like IRC with no server needed.
B) An application for reliably "tunneling" real-time UDP packet
streams (like RTP video or audio) using NORM's streaming
capability.
OTHER FILES: OTHER FILES:
============ ============
@ -92,6 +105,8 @@ NormDeveloperGuide.html - HTML version of NORM Developer's Guide
(nice for browsing) (nice for browsing)
NormUserGuide.pdf - Guide to "norm" demo app usage NormUserGuide.pdf - Guide to "norm" demo app usage
(this document needs corrections and
is currently incomplete)
VERSION.TXT - NORM version history notes VERSION.TXT - NORM version history notes

View File

@ -1,5 +1,51 @@
NORM Version History NORM Version History
Version 1.3b5
=============
- Changed ProtoSocket::GetInterfaceAddress() and related methods on Win32
to use different system APIs depending on Windows version.
- Fixed some details related to compilation with g++ 4.x.
- Various issues fixed thanks to input from Timothy Chaplin.
- Fixed some issues where attempt to resync rx stream after long
outages (at high data rates) called assertion failures
(Thanks to Charlie Davis for finding this one)
- Fixed problem where, on Win32, the sender GRTT estimate was not
being updated (in the downward direction) properly.
- Changes to Protolib & Norm to support build of shared libraries
(Thanks to Dave Talmage & Timothy Mann)
- Added "NormSetRxPortReuse()" API and code support to allow
(with care) multiple NORM instances on the same host.
- Fixes to NORM congestion control including:
1) measurement of "recv_rate" at low transmission rates
fixed (made sure measurement was over sufficient
interval at low rates including cc startup)
2) Re-instated code to reduce rate when feedback stopped
being received.
3) Changed to time-based aging of feedback to "deactivate"
stale congestion control feedback representative state
kept by sender.
4) Fixed mis-set of PLR flag as CLR flag and fixed bug
in updating CC node list upon CC feedback reception.
(Thanks to Praveen Gopala for prompting all of this)
- Fixes for Win32 large file support "in normFile.cpp"
(Thanks to Titze Stefan for this fix).
- Added "NormSetGrttMax()", "NormSetGrttProbingMode()",
and "NormSetGrttProbingInterval()" APIs to control
NORM GRTT measurement/estimation process.
(Thanks to Dave Lucas for prompting me here)
- Changed posting of NORM_TX_QUEUE_VACANCY for streams such
that new postings of this event are made, _only_ after a
successful call to NormStreamWrite() ... This results in
reduced posting of unnecessary vacancy events, but now the
onus is on the app to pay attention to this event, since
another of it's type won't be posted until the app calls
NormStreamWrite() with non-zero content length.
(Thanks to Charlie Davis for bringing this to my attention)
- Made sure messages from self are ignored unless loopback
is explicitly enabled (see NormSetLoopback()) even for
operating systems whose ProtoSocket::SetLoopback() doesn't
work properly.
Version 1.3b4 Version 1.3b4
============= =============
- Added NormSetTxCacheBounds(), see NormDevGuide for details - Added NormSetTxCacheBounds(), see NormDevGuide for details
@ -118,3 +164,7 @@ Version 1.1b3
- Started keeping version history. This release includes - Started keeping version history. This release includes
some bug fixes, smoother congestion control operation, etc some bug fixes, smoother congestion control operation, etc
over some of the earlier releases. over some of the earlier releases.
Please address bug reports, suggestions etc to the email list:
mailto:norm-dev@pf.itd.nrl.navy.mil

View File

@ -460,8 +460,8 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent)
((NormObject*)n->event.object)->SetNotifyOnUpdate(true); ((NormObject*)n->event.object)->SetNotifyOnUpdate(true);
break; break;
case NORM_TX_QUEUE_VACANCY: case NORM_TX_QUEUE_VACANCY:
if (NULL != n->event.object) //if (NULL != n->event.object)
static_cast<NormStreamObject*>((NormObject*)n->event.object)->ResetPostedTxQueueVacancy(); // static_cast<NormStreamObject*>((NormObject*)n->event.object)->ResetPostedTxQueueVacancy();
// (TBD) support session-level queue vacancy notify // (TBD) support session-level queue vacancy notify
break; break;
default: default:
@ -764,6 +764,21 @@ void NormSetTxPort(NormSessionHandle sessionHandle,
} }
} // end NormSetTxPort() } // end NormSetTxPort()
void NormSetRxPortReuse(NormSessionHandle sessionHandle,
bool state)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (NULL != instance)
{
if (instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetRxPortReuse(state);
instance->dispatcher.ResumeThread();
}
}
} // end NormSetTxPort()
bool NormSetMulticastInterface(NormSessionHandle sessionHandle, bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
const char* interfaceName) const char* interfaceName)
{ {
@ -971,6 +986,46 @@ void NormSetGrttEstimate(NormSessionHandle sessionHandle,
} }
} // end NormSetGrttEstimate() } // end NormSetGrttEstimate()
void NormSetGrttMax(NormSessionHandle sessionHandle,
double grttMax)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetGrttMax(grttMax);
instance->dispatcher.ResumeThread();
}
} // end NormSetGrttMax()
void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
NormProbingMode probingMode)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session)
session->SetGrttProbingMode((NormSession::ProbingMode)probingMode);
instance->dispatcher.ResumeThread();
}
} // end NormSetGrttProbingMode()
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin,
double intervalMax)
{
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
if (session) session->SetGrttProbingInterval(intervalMin, intervalMax);
instance->dispatcher.ResumeThread();
}
} // end NormSetGrttProbingInterval()
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId) NormNodeId nodeId)
{ {
@ -1021,8 +1076,8 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle, NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
const char* dataPtr, const char* dataPtr,
unsigned long dataLen, unsigned long dataLen,
const char* infoPtr = NULL, const char* infoPtr,
unsigned int infoLen = 0) unsigned int infoLen)
{ {
NormObjectHandle objectHandle = NORM_OBJECT_INVALID; NormObjectHandle objectHandle = NORM_OBJECT_INVALID;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -1460,7 +1515,7 @@ bool NormFileGetName(NormObjectHandle fileHandle,
static_cast<NormFileObject*>((NormObject*)fileHandle); static_cast<NormFileObject*>((NormObject*)fileHandle);
bufferLen = (bufferLen < PATH_MAX) ? bufferLen : PATH_MAX; bufferLen = (bufferLen < PATH_MAX) ? bufferLen : PATH_MAX;
strncpy(nameBuffer, file->GetPath(), bufferLen); strncpy(nameBuffer, file->GetPath(), bufferLen);
nameBuffer[bufferLen=1] = '\0'; nameBuffer[bufferLen] = '\0';
result = true; result = true;
} }
return result; return result;

View File

@ -19,12 +19,7 @@
// C++ code continues to evolve. But, until this notice // C++ code continues to evolve. But, until this notice
// is removed, the API shouldn't be considered final. // is removed, the API shouldn't be considered final.
// NORM API control
/** NORM API Data Types and Constants
* These are data types and constants defined
* for the NORM API
*/
typedef const void* NormInstanceHandle; typedef const void* NormInstanceHandle;
extern const NormInstanceHandle NORM_INSTANCE_INVALID; extern const NormInstanceHandle NORM_INSTANCE_INVALID;
@ -71,6 +66,13 @@ enum NormNackingMode
NORM_NACK_NORMAL NORM_NACK_NORMAL
}; };
enum NormProbingMode
{
NORM_PROBE_NONE,
NORM_PROBE_PASSIVE,
NORM_PROBE_ACTIVE
};
enum NormRepairBoundary enum NormRepairBoundary
{ {
NORM_BOUNDARY_BLOCK, NORM_BOUNDARY_BLOCK,
@ -154,6 +156,9 @@ NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle);
void NormSetTxPort(NormSessionHandle sessionHandle, void NormSetTxPort(NormSessionHandle sessionHandle,
unsigned short txPortNumber); unsigned short txPortNumber);
void NormSetRxPortReuse(NormSessionHandle sessionHandle,
bool state);
bool NormSetMulticastInterface(NormSessionHandle sessionHandle, bool NormSetMulticastInterface(NormSessionHandle sessionHandle,
const char* interfaceName); const char* interfaceName);
@ -206,6 +211,16 @@ void NormSetAutoParity(NormSessionHandle sessionHandle,
void NormSetGrttEstimate(NormSessionHandle sessionHandle, void NormSetGrttEstimate(NormSessionHandle sessionHandle,
double grttEstimate); double grttEstimate);
void NormSetGrttMax(NormSessionHandle sessionHandle,
double grttMax);
void NormSetGrttProbingMode(NormSessionHandle sessionHandle,
NormProbingMode probingMode);
void NormSetGrttProbingInterval(NormSessionHandle sessionHandle,
double intervalMin,
double intervalMax);
bool NormAddAckingNode(NormSessionHandle sessionHandle, bool NormAddAckingNode(NormSessionHandle sessionHandle,
NormNodeId nodeId); NormNodeId nodeId);
@ -217,10 +232,11 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
const char* infoPtr = (const char*)0, const char* infoPtr = (const char*)0,
unsigned int infoLen = 0); unsigned int infoLen = 0);
bool NormDataEnqueue(const char* dataPtr, NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
unsigned long dataLen, const char* dataPtr,
const char* infoPtr = (const char*)0, unsigned long dataLen,
unsigned int infoLen = 0); const char* infoPtr = (const char*)0,
unsigned int infoLen = 0);
@ -243,16 +259,15 @@ void NormStreamSetAutoFlush(NormObjectHandle streamHandle,
void NormStreamSetPushEnable(NormObjectHandle streamHandle, void NormStreamSetPushEnable(NormObjectHandle streamHandle,
bool pushEnable); bool pushEnable);
bool NormStreamHasVacancy(NormObjectHandle streamHandle); bool NormStreamHasVacancy(NormObjectHandle streamHandle);
NormSize NormGetObjectSize(NormObjectHandle objectHandle);
void NormStreamMarkEom(NormObjectHandle streamHandle); void NormStreamMarkEom(NormObjectHandle streamHandle);
bool NormSetWatermark(NormSessionHandle sessionHandle, bool NormSetWatermark(NormSessionHandle sessionHandle,
NormObjectHandle objectHandle); NormObjectHandle objectHandle);
/** NORM Receiver Functions */
bool NormStartReceiver(NormSessionHandle sessionHandle, bool NormStartReceiver(NormSessionHandle sessionHandle,
unsigned long bufferSpace); unsigned long bufferSpace);
@ -329,6 +344,7 @@ char* NormDataDetachData(NormObjectHandle objectHandle);
NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle); NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle);
char* NormGetData(NormObjectHandle dataHandle);
/** NORM Node Functions */ /** NORM Node Functions */

View File

@ -1624,7 +1624,7 @@ void NormApp::OnShutdown()
} // end NormApp::OnShutdown() } // end NormApp::OnShutdown()
// Out application instance // Out application instance
PROTO_INSTANTIATE_APP(NormApp); PROTO_INSTANTIATE_APP(NormApp)
#ifdef UNIX #ifdef UNIX
void NormApp::SignalHandler(int sigNum) void NormApp::SignalHandler(int sigNum)

View File

@ -397,8 +397,8 @@ NormFile::Offset NormFile::GetSize() const
return ((Offset)fileSize); return ((Offset)fileSize);
#else #else
#ifdef WIN32 #ifdef WIN32
struct _stat info; struct __stat64 info; // instead of "struct _stat"
int result = _fstat(fd, &info); int result = _fstat64(fd, &info); // instead of "_fstat()"
#else #else
struct stat info; struct stat info;
int result = fstat(fd, &info); int result = fstat(fd, &info);
@ -811,8 +811,8 @@ NormFile::Offset NormFile::GetSize(const char* path)
} }
#else #else
#ifdef WIN32 #ifdef WIN32
struct _stat info; struct __stat64 info; // instead of "struct _stat"
int result = _stat(path, &info); int result = _stat64(path, &info); // instead of "_stat()"
#else #else
struct stat info; struct stat info;
int result = stat(path, &info); int result = stat(path, &info);
@ -863,8 +863,8 @@ time_t NormFile::GetUpdateTime(const char* path)
} }
#else #else
#ifdef WIN32 #ifdef WIN32
struct _stat info; struct __stat64 info; // instead of "struct _stat"
int result = _stat(path, &info); int result = _stat64(path, &info); // instead of "_stat()"
#else #else
struct stat info; struct stat info;
int result = stat(path, &info); int result = stat(path, &info);
@ -877,9 +877,9 @@ time_t NormFile::GetUpdateTime(const char* path)
{ {
#ifdef WIN32 #ifdef WIN32
// Hack because Win2K and Win98 seem to work differently // Hack because Win2K and Win98 seem to work differently
time_t updateTime = MAX(info.st_ctime, info.st_atime); __time64_t updateTime = MAX(info.st_ctime, info.st_atime);
updateTime = MAX(updateTime, info.st_mtime); updateTime = MAX(updateTime, info.st_mtime);
return updateTime; return ((time_t)updateTime);
#else #else
return info.st_ctime; return info.st_ctime;
#endif // if/else WIN32 #endif // if/else WIN32

View File

@ -231,6 +231,7 @@ class NormHeaderExtension
}; };
NormHeaderExtension(); NormHeaderExtension();
virtual ~NormHeaderExtension() {}
virtual void Init(UINT32* theBuffer) virtual void Init(UINT32* theBuffer)
{ {
buffer = theBuffer; buffer = theBuffer;

View File

@ -3,7 +3,7 @@
#include "normSession.h" #include "normSession.h"
NormNode::NormNode(class NormSession& theSession, NormNodeId nodeId) NormNode::NormNode(class NormSession& theSession, NormNodeId nodeId)
: session(theSession), id(nodeId), reference_count(0), : session(theSession), id(nodeId), reference_count(1),
parent(NULL), right(NULL), left(NULL) parent(NULL), right(NULL), left(NULL)
{ {
@ -323,7 +323,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
if (obj && (NormObject::STREAM == obj->GetType())) if (obj && (NormObject::STREAM == obj->GetType()))
{ {
NormBlockId blockId = squelch.GetFecBlockId(); NormBlockId blockId = squelch.GetFecBlockId();
static_cast<NormStreamObject*>(obj)->Prune(blockId); static_cast<NormStreamObject*>(obj)->Prune(blockId, true);
} }
// 3) (TBD) Go ahead and discard any invalidated objects // 3) (TBD) Go ahead and discard any invalidated objects
// (although they will eventually get discarded anyway) // (although they will eventually get discarded anyway)
@ -614,7 +614,7 @@ void NormServerNode::HandleRepairContent(const UINT32* buffer, UINT16 bufferLen)
NormRepairRequest req; NormRepairRequest req;
UINT16 requestLength = 0; UINT16 requestLength = 0;
bool freshObject = true; bool freshObject = true;
NormObjectId prevObjectId; NormObjectId prevObjectId(0);
NormObject* object = NULL; NormObject* object = NULL;
bool freshBlock = true; bool freshBlock = true;
NormBlockId prevBlockId = 0; NormBlockId prevBlockId = 0;
@ -1005,10 +1005,9 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
} }
} }
if (obj) if (NULL != obj)
{ {
rx_table.Insert(obj); rx_table.Insert(obj);
obj->Retain();
NormFtiExtension fti; NormFtiExtension fti;
while (msg.GetNextExtension(fti)) while (msg.GetNextExtension(fti))
{ {
@ -1458,7 +1457,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
if (is_clr) if (is_clr)
ext.SetCCFlag(NormCC::CLR); ext.SetCCFlag(NormCC::CLR);
else if (is_plr) else if (is_plr)
ext.SetCCFlag(NormCC::CLR); ext.SetCCFlag(NormCC::PLR);
if (rtt_confirmed) if (rtt_confirmed)
ext.SetCCFlag(NormCC::RTT); ext.SetCCFlag(NormCC::RTT);
ext.SetCCRtt(rtt_quantized); ext.SetCCRtt(rtt_quantized);
@ -1675,22 +1674,58 @@ void NormServerNode::UpdateRecvRate(const struct timeval& currentTime, unsigned
{ {
if (prev_update_time.tv_sec || prev_update_time.tv_usec) if (prev_update_time.tv_sec || prev_update_time.tv_usec)
{ {
recv_accumulator += msgSize;
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec); double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
if (currentTime.tv_usec > prev_update_time.tv_sec) if (currentTime.tv_usec > prev_update_time.tv_sec)
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec); interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
else else
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec); interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
double rttEstimate = rtt_confirmed ? rtt_estimate : grtt_estimate; double measurementInterval = rtt_confirmed ? rtt_estimate : grtt_estimate;
// Here, we put a 0.100 sec lower bound on our measurementInterval for the
// 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 (interval > 0.0)
{
double currentRecvRate = ((double)(recv_accumulator)) / interval;
if (currentRecvRate < recv_rate)
{
// Make sure we've allowed sufficient time for a measurement
double minInterval = 4.0 * ((double)nominal_packet_size) / recv_rate;
if (measurementInterval < minInterval)
measurementInterval = minInterval;
}
if (interval >= measurementInterval)
{
recv_rate = currentRecvRate; //((double)(recv_accumulator)) / interval;
prev_update_time = currentTime;
recv_accumulator = 0;
}
}
/*
// We put a 0.100 sec lower bound on our rttEstimate for the recv_rate measurement // 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 // 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; rttEstimate = rttEstimate < 0.1 ? 0.1 : rttEstimate;
recv_accumulator += msgSize;
// 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) if (interval >= rttEstimate)
{ {
recv_rate = ((double)(recv_accumulator)) / interval; recv_rate = ((double)(recv_accumulator)) / interval;
prev_update_time = currentTime; prev_update_time = currentTime;
recv_accumulator = 0; recv_accumulator = 0;
} }*/
//TRACE("updated recv rate to %lf (accum:%lu) (cc_rate:%lf)\n", recv_rate,
// recv_accumulator, cc_rate);
} }
else else
{ {
@ -1956,6 +1991,7 @@ NormNode *NormNodeTree::FindNodeById(NormNodeId nodeId) const
void NormNodeTree::AttachNode(NormNode *node) void NormNodeTree::AttachNode(NormNode *node)
{ {
ASSERT(node); ASSERT(node);
node->Retain();
node->left = NULL; node->left = NULL;
node->right = NULL; node->right = NULL;
NormNode *x = root; NormNode *x = root;
@ -1995,6 +2031,7 @@ void NormNodeTree::AttachNode(NormNode *node)
void NormNodeTree::DetachNode(NormNode* node) void NormNodeTree::DetachNode(NormNode* node)
{ {
ASSERT(node); ASSERT(node);
node->Release();
NormNode* x; NormNode* x;
NormNode* y; NormNode* y;
if (!node->left || !node->right) if (!node->left || !node->right)
@ -2056,7 +2093,7 @@ void NormNodeTree::Destroy()
while ((n = root)) while ((n = root))
{ {
DetachNode(n); DetachNode(n);
delete n; n->Release();
} }
} // end NormNodeTree::Destroy() } // end NormNodeTree::Destroy()
@ -2141,6 +2178,7 @@ NormNode* NormNodeList::FindNodeById(NormNodeId nodeId) const
void NormNodeList::Append(NormNode *theNode) void NormNodeList::Append(NormNode *theNode)
{ {
ASSERT(theNode); ASSERT(theNode);
theNode->Retain();
theNode->left = tail; theNode->left = tail;
if (tail) if (tail)
tail->right = theNode; tail->right = theNode;
@ -2154,6 +2192,7 @@ void NormNodeList::Append(NormNode *theNode)
void NormNodeList::Remove(NormNode *theNode) void NormNodeList::Remove(NormNode *theNode)
{ {
ASSERT(theNode); ASSERT(theNode);
theNode->Release();
if (theNode->right) if (theNode->right)
theNode->right->left = theNode->left; theNode->right->left = theNode->left;
else else
@ -2171,7 +2210,7 @@ void NormNodeList::Destroy()
while ((n = head)) while ((n = head))
{ {
Remove(n); Remove(n);
delete n; n->Release();
} }
} // end NormNodeList::Destroy() } // end NormNodeList::Destroy()

View File

@ -171,7 +171,10 @@ class NormCCNode : public NormNode
NormCCNode(class NormSession& theSession, NormNodeId nodeId); NormCCNode(class NormSession& theSession, NormNodeId nodeId);
~NormCCNode(); ~NormCCNode();
enum {ACTIVE_MAX = 7};
bool IsClr() const {return is_clr;} bool IsClr() const {return is_clr;}
bool IsPlr() const {return is_plr;}
bool IsActive() const {return is_active;} bool IsActive() const {return is_active;}
bool HasRtt() const {return rtt_confirmed;} bool HasRtt() const {return rtt_confirmed;}
@ -179,9 +182,13 @@ class NormCCNode : public NormNode
double GetLoss() const {return loss;} double GetLoss() const {return loss;}
double GetRate() const {return rate;} double GetRate() const {return rate;}
UINT16 GetCCSequence() const {return cc_sequence;} UINT16 GetCCSequence() const {return cc_sequence;}
const struct timeval& GetFeedbackTime()
{return feedback_time;}
void SetFeedbackTime(struct timeval& theTime)
{feedback_time = theTime;}
void SetActive(bool state) {is_active = state;} void SetActive(bool state) {is_active = state;}
void SetClrStatus(bool state) {is_clr = state;} void SetClrStatus(bool state) {is_clr = state;}
void SetPlrStatus(bool state) {is_plr = state;}
void SetRttStatus(bool state) {rtt_confirmed = state;} void SetRttStatus(bool state) {rtt_confirmed = state;}
void SetRtt(double value) {rtt = value;} void SetRtt(double value) {rtt = value;}
double UpdateRtt(double value) double UpdateRtt(double value)
@ -194,14 +201,15 @@ class NormCCNode : public NormNode
void SetCCSequence(UINT16 value) {cc_sequence = value;} void SetCCSequence(UINT16 value) {cc_sequence = value;}
private: private:
bool is_clr; // true if worst path representative bool is_clr; // true if worst path representative
bool is_plr; // true if worst path candidate bool is_plr; // true if worst path candidate
bool is_active; bool rtt_confirmed;
bool rtt_confirmed; bool is_active;
double rtt; // in seconds struct timeval feedback_time; // time of last received feedback
double loss; // loss fraction double rtt; // in seconds
double rate; // in bytes per second double loss; // loss fraction
UINT16 cc_sequence; double rate; // in bytes per second
UINT16 cc_sequence;
}; // end class NormCCNode }; // end class NormCCNode
class NormServerNode : public NormNode class NormServerNode : public NormNode
@ -496,7 +504,7 @@ class NormNodeList
{ {
ASSERT(theNode); ASSERT(theNode);
Remove(theNode); Remove(theNode);
delete theNode; theNode->Release();
} }
void Destroy(); // delete all nodes in list void Destroy(); // delete all nodes in list
const NormNode* Head() {return head;} const NormNode* Head() {return head;}

View File

@ -11,7 +11,7 @@ NormObject::NormObject(NormObject::Type theType,
class NormSession& theSession, class NormSession& theSession,
class NormServerNode* theServer, class NormServerNode* theServer,
const NormObjectId& transportId) const NormObjectId& transportId)
: type(theType), session(theSession), server(theServer), reference_count(0), : type(theType), session(theSession), server(theServer), reference_count(1),
transport_id(transportId), segment_size(0), pending_info(false), repair_info(false), transport_id(transportId), segment_size(0), pending_info(false), repair_info(false),
current_block_id(0), next_segment_id(0), current_block_id(0), next_segment_id(0),
max_pending_block(0), max_pending_segment(0), max_pending_block(0), max_pending_segment(0),
@ -132,8 +132,6 @@ bool NormObject::Open(const NormObjectSize& objectSize,
Close(); Close();
return false; return false;
} }
pending_mask.Clear();
pending_mask.SetBits(0, numBlocks.LSB());
// Init repair_mask // Init repair_mask
if (!repair_mask.Init(numBlocks.LSB(), 0xffffffff)) if (!repair_mask.Init(numBlocks.LSB(), 0xffffffff))
@ -151,10 +149,13 @@ bool NormObject::Open(const NormObjectSize& objectSize,
small_block_count = large_block_count = numBlocks.LSB(); small_block_count = large_block_count = numBlocks.LSB();
final_segment_size = segmentSize; final_segment_size = segmentSize;
NormStreamObject* stream = static_cast<NormStreamObject*>(this); NormStreamObject* stream = static_cast<NormStreamObject*>(this);
stream->StreamResync(numBlocks.LSB()); stream->StreamResync(NormBlockId(0));
} }
else else
{ {
// Set everything pending
pending_mask.Clear();
pending_mask.SetBits(0, numBlocks.LSB());
// Compute FEC block structure per NORM Protocol Spec Section 5.1.1 // Compute FEC block structure per NORM Protocol Spec Section 5.1.1
// (Note NormObjectSize divide operator always rounds _up_) // (Note NormObjectSize divide operator always rounds _up_)
NormObjectSize largeBlockSize = numSegments / numBlocks; NormObjectSize largeBlockSize = numSegments / numBlocks;
@ -1136,7 +1137,8 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
} }
else else
{ {
stream->StreamResync(blockId);// - NormBlockId(pending_mask.Size())); stream->StreamResync(blockId);
break;
} }
} }
} }
@ -1268,25 +1270,18 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
} }
else if (!block->GetSegment(nextSegment)) else if (!block->GetSegment(nextSegment))
{ {
// "tempRetrieval" is set to "true" if the retrieved segment if (!(segment = RetrieveSegment(blockId, nextSegment)))
// comes from the "server" temp retrieval pool
bool tempRetrieval = false;
if (!(segment = RetrieveSegment(blockId, nextSegment, tempRetrieval)))
{ {
ASSERT(IsStream()); ASSERT(IsStream());
block->SetPending(nextSegment); block->SetPending(nextSegment);
block->IncrementErasureCount(); block->IncrementErasureCount();
// Clear any erasure/retrieval segments // Clear block of any retrieval (temp) segments
UINT16 i; for (UINT16 i = 0; i < retrievalCount; i++)
for (i = 0; i < erasureCount; i++)
block->DetachSegment(server->GetErasureLoc(i));
for (i = 0; i < retrievalCount; i++)
block->DetachSegment(server->GetRetrievalLoc(i)); block->DetachSegment(server->GetRetrievalLoc(i));
return; return;
} }
if (tempRetrieval) server->SetRetrievalLoc(retrievalCount++, nextSegment);
server->SetRetrievalLoc(retrievalCount++, nextSegment); block->SetSegment(nextSegment, segment);
block->SetSegment(nextSegment, segment);
} }
} }
nextErasure = numData; nextErasure = numData;
@ -1309,8 +1304,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
objectUpdated = true; objectUpdated = true;
// For statistics only (TBD) #ifdef NORM_DEBUG // For statistics only (TBD) #ifdef NORM_DEBUG
server->IncrementRecvGoodput(segmentLength); server->IncrementRecvGoodput(segmentLength);
} }
block->DetachSegment(sid);
} }
else else
{ {
@ -1318,13 +1312,13 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
} }
} }
} }
// Clear any temporarily retrieved (non-cached) segments for the block // Clear any temporarily retrieved segments for the block
for (UINT16 i = 0; i < retrievalCount; i++) for (UINT16 i = 0; i < retrievalCount; i++)
block->DetachSegment(server->GetRetrievalLoc(i)); block->DetachSegment(server->GetRetrievalLoc(i));
// OK, we're done with this block // OK, we're done with this block
pending_mask.Unset(blockId); pending_mask.Unset(blockId);
block_buffer.Remove(block); block_buffer.Remove(block);
server->PutFreeBlock(block); server->PutFreeBlock(block);
} }
// Notify application of new data available // Notify application of new data available
// (TBD) this could be improved for stream objects // (TBD) this could be improved for stream objects
@ -1958,8 +1952,7 @@ UINT16 NormFileObject::ReadSegment(NormBlockId blockId,
} // end NormFileObject::ReadSegment() } // end NormFileObject::ReadSegment()
char* NormFileObject::RetrieveSegment(NormBlockId blockId, char* NormFileObject::RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId)
bool& tempRetrieval)
{ {
if (server) if (server)
{ {
@ -1970,7 +1963,6 @@ char* NormFileObject::RetrieveSegment(NormBlockId blockId,
// zeroize remainder for proper decodes // zeroize remainder for proper decodes
if (len < segment_size) if (len < segment_size)
memset(segment+len, 0, segment_size-len); memset(segment+len, 0, segment_size-len);
tempRetrieval = true;
return segment; return segment;
} }
else else
@ -2057,7 +2049,6 @@ bool NormDataObject::Open(char* dataPtr,
bool NormDataObject::Accept(char* dataPtr, UINT32 dataMax, bool dataRelease) bool NormDataObject::Accept(char* dataPtr, UINT32 dataMax, bool dataRelease)
{ {
ASSERT(NULL == server);
if (Open(dataPtr, dataMax, dataRelease)) if (Open(dataPtr, dataMax, dataRelease))
{ {
NormObject::Accept(); NormObject::Accept();
@ -2167,8 +2158,7 @@ UINT16 NormDataObject::ReadSegment(NormBlockId blockId,
} // end NormDataObject::ReadSegment() } // end NormDataObject::ReadSegment()
char* NormDataObject::RetrieveSegment(NormBlockId blockId, char* NormDataObject::RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId)
bool& tempRetrieval)
{ {
if (NULL == data_ptr) if (NULL == data_ptr)
{ {
@ -2210,7 +2200,6 @@ char* NormDataObject::RetrieveSegment(NormBlockId blockId,
char* segment = server->GetRetrievalSegment(); char* segment = server->GetRetrievalSegment();
len = ReadSegment(blockId, segmentId, segment); len = ReadSegment(blockId, segmentId, segment);
memset(segment+len, 0, segment_size-len); memset(segment+len, 0, segment_size-len);
tempRetrieval = true;
return segment; return segment;
} }
else else
@ -2221,7 +2210,6 @@ char* NormDataObject::RetrieveSegment(NormBlockId blockId,
} }
else else
{ {
tempRetrieval = false;
return (data_ptr + segmentOffset.LSB()); return (data_ptr + segmentOffset.LSB());
} }
} // end NormDataObject::RetrieveSegment() } // end NormDataObject::RetrieveSegment()
@ -2442,7 +2430,7 @@ bool NormStreamObject::StreamUpdateStatus(NormBlockId blockId)
{ {
pending_mask.SetBits(stream_next_id, blockId - stream_next_id + 1); pending_mask.SetBits(stream_next_id, blockId - stream_next_id + 1);
stream_next_id = blockId + 1; stream_next_id = blockId + 1;
// Handle potential sync block id wrap // Handle potential stream_sync_id wrap
NormBlockId delta = stream_next_id - stream_sync_id; NormBlockId delta = stream_next_id - stream_sync_id;
if (delta > NormBlockId(2*pending_mask.GetSize())) if (delta > NormBlockId(2*pending_mask.GetSize()))
GetFirstPending(stream_sync_id); GetFirstPending(stream_sync_id);
@ -2468,8 +2456,8 @@ bool NormStreamObject::StreamUpdateStatus(NormBlockId blockId)
{ {
pending_mask.SetBits(blockId, pending_mask.GetSize()); pending_mask.SetBits(blockId, pending_mask.GetSize());
stream_next_id = blockId + NormBlockId(pending_mask.GetSize()); stream_next_id = blockId + NormBlockId(pending_mask.GetSize());
// Handle potential sync block id wrap // Handle potential stream_sync_id wrap
delta = stream_next_id - stream_sync_id; NormBlockId delta = stream_next_id - stream_sync_id;
if (delta > NormBlockId(2*pending_mask.GetSize())) if (delta > NormBlockId(2*pending_mask.GetSize()))
stream_sync_id = blockId; stream_sync_id = blockId;
return true; return true;
@ -2481,20 +2469,35 @@ bool NormStreamObject::StreamUpdateStatus(NormBlockId blockId)
else else
{ {
// For now, let stream begin anytime // For now, let stream begin anytime
// First, clean out block_buffer
NormBlock* block;
while (NULL != (block = block_buffer.Find(block_buffer.RangeLo())))
{
block_buffer.Remove(block);
server->PutFreeBlock(block);
}
pending_mask.Clear(); pending_mask.Clear();
pending_mask.SetBits(blockId, pending_mask.GetSize()); pending_mask.SetBits(blockId, pending_mask.GetSize());
stream_sync = true; stream_sync = true;
stream_sync_id = blockId; stream_sync_id = blockId;
stream_next_id = blockId + pending_mask.GetSize(); stream_next_id = blockId + pending_mask.GetSize();
read_init = true; // Since we're doing a resync including "read_init", dump any buffered data
// (TBD) this may not be necessary and is thus currently commented-out code
/*read_init = true;
NormBlock* block;
while (NULL != (block = stream_buffer.Find(stream_buffer.RangeLo())))
{
stream_buffer.Remove(block);
block->EmptyToPool(segment_pool);
block_pool.Put(block);
}*/
return true; return true;
} }
} // end NormStreamObject::StreamUpdateStatus() } // end NormStreamObject::StreamUpdateStatus()
char* NormStreamObject::RetrieveSegment(NormBlockId blockId, char* NormStreamObject::RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId)
bool& tempRetrieval)
{ {
NormBlock* block = stream_buffer.Find(blockId); NormBlock* block = stream_buffer.Find(blockId);
if (!block) if (!block)
@ -2505,7 +2508,6 @@ char* NormStreamObject::RetrieveSegment(NormBlockId blockId,
char* segment = block->GetSegment(segmentId); char* segment = block->GetSegment(segmentId);
if (NULL == segment) if (NULL == segment)
DMSG(0, "NormStreamObject::RetrieveSegment() segment unavailable\n"); DMSG(0, "NormStreamObject::RetrieveSegment() segment unavailable\n");
tempRetrieval = false;
return segment; return segment;
} // end NormStreamObject::RetrieveSegment() } // end NormStreamObject::RetrieveSegment()
@ -2581,8 +2583,6 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
read_index.block = blockId; read_index.block = blockId;
read_index.segment = segmentId; read_index.segment = segmentId;
read_offset = segmentOffset; read_offset = segmentOffset;
TRACE("norm stream read init read_index.segment:%hu read_offset:%lu\n",
read_index.segment, read_offset);
} }
if ((blockId < read_index.block) || if ((blockId < read_index.block) ||
@ -2649,7 +2649,7 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
block->EmptyToPool(segment_pool); block->EmptyToPool(segment_pool);
block_pool.Put(block); block_pool.Put(block);
block = NULL; block = NULL;
Prune(read_index.block); Prune(read_index.block, false);
break; break;
} }
} }
@ -2667,7 +2667,7 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
{ {
read_index.block++; read_index.block++;
read_index.segment = 0; read_index.segment = 0;
Prune(read_index.block); Prune(read_index.block, false);
} }
stream_buffer.Remove(block); stream_buffer.Remove(block);
block->EmptyToPool(segment_pool); block->EmptyToPool(segment_pool);
@ -2714,50 +2714,69 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
return true; return true;
} // end NormStreamObject::WriteSegment() } // end NormStreamObject::WriteSegment()
void NormStreamObject::Prune(NormBlockId blockId) void NormStreamObject::Prune(NormBlockId blockId, bool updateStatus)
{ {
bool resync = false; if (updateStatus || StreamUpdateStatus(blockId))
NormBlock* block;
while ((block = block_buffer.Find(block_buffer.RangeLo())))
{ {
if (block->GetId() < blockId) bool resync = false;
NormBlock* block;
while ((block = block_buffer.Find(block_buffer.RangeLo())))
{ {
resync = true; if (block->GetId() < blockId)
pending_mask.Unset(block->GetId()); {
block_buffer.Remove(block); resync = true;
server->PutFreeBlock(block); pending_mask.Unset(block->GetId());
} block_buffer.Remove(block);
else server->PutFreeBlock(block);
{ }
break; else
{
break;
}
} }
} NormBlockId firstId;
NormBlockId firstId; if (GetFirstPending(firstId))
if (GetFirstPending(firstId))
{
if (firstId < blockId)
{ {
resync = true; if (firstId < blockId)
UINT32 count = blockId - firstId; {
pending_mask.UnsetBits(firstId, count); resync = true;
UINT32 count = blockId - firstId;
pending_mask.UnsetBits(firstId, count);
}
} }
while (!StreamUpdateStatus(blockId))
{
// Server is too far ahead of me ...
resync = true;
NormBlockId firstId;
if (GetFirstPending(firstId))
{
NormBlock* block = block_buffer.Find(firstId);
if (block)
{
block_buffer.Remove(block);
server->PutFreeBlock(block);
}
pending_mask.Unset(firstId);
}
else
{
StreamResync(blockId);
break;
}
}
if (resync) server->IncrementResyncCount();
} }
bool result = StreamUpdateStatus(blockId);
ASSERT(result);
if (resync) server->IncrementResyncCount();
result = GetFirstPending(firstId);
} // end NormStreamObject::Prune() } // end NormStreamObject::Prune()
// Sequential (in order) read/write routines (TBD) Add a "Seek()" method // Sequential (in order) read/write routines (TBD) Add a "Seek()" method
bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStart) bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStart)
{ {
SetDebugLevel(4); if (stream_closing || read_init)
TRACE("NormStreamObject::Read(seekMsgStart:%d) read_offset:%lu\n", seekMsgStart, read_offset);
if (stream_closing)
{ {
DMSG(4, "NormStreamObject::Read() attempted to read from closed stream\n"); if (stream_closing)
DMSG(4, "NormStreamObject::Read() attempted to read from closed stream\n");
*buflen = 0; *buflen = 0;
TRACE("return 1\n");
return seekMsgStart ? false : true; return seekMsgStart ? false : true;
} }
Retain(); Retain();
@ -2766,16 +2785,14 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
unsigned int bytesToRead = *buflen; unsigned int bytesToRead = *buflen;
do do
{ {
TRACE("do top ...\n");
NormBlock* block = stream_buffer.Find(read_index.block); NormBlock* block = stream_buffer.Find(read_index.block);
if (!block) if (!block)
{ {
DMSG(0, "NormStreamObject::Read() stream buffer empty (1) (sbEmpty:%d)\n", stream_buffer.IsEmpty()); //DMSG(0, "NormStreamObject::Read() stream buffer empty (1) (sbEmpty:%d)\n", stream_buffer.IsEmpty());
*buflen = bytesRead; *buflen = bytesRead;
if (bytesRead > 0) if (bytesRead > 0)
{ {
Release(); Release();
TRACE("return 2\n");
return true; return true;
} }
else else
@ -2787,14 +2804,13 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
{ {
read_index.block++; read_index.block++;
read_index.segment = 0; read_index.segment = 0;
Prune(read_index.block); Prune(read_index.block, false);
} }
continue; continue;
} }
else else
{ {
Release(); Release();
TRACE("return 3\n");
return seekMsgStart ? false : true; return seekMsgStart ? false : true;
} }
} }
@ -2805,13 +2821,12 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
if (!segment) if (!segment)
{ {
DMSG(0, "NormStreamObject::Read(%lu:%hu) stream buffer empty (2)\n", //DMSG(0, "NormStreamObject::Read(%lu:%hu) stream buffer empty (2)\n",
(UINT32)read_index.block, read_index.segment); // (UINT32)read_index.block, read_index.segment);
*buflen = bytesRead; *buflen = bytesRead;
if (bytesRead > 0) if (bytesRead > 0)
{ {
Release(); Release();
TRACE("return 4\n");
return true; return true;
} }
else else
@ -2826,17 +2841,45 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
block_pool.Put(block); block_pool.Put(block);
read_index.block++; read_index.block++;
read_index.segment = 0; read_index.segment = 0;
Prune(read_index.block); Prune(read_index.block, false); // prevents repair requests for data we
} } // no longer care about
continue; continue;
} }
else else
{ {
Release(); Release();
TRACE("return 5\n");
return seekMsgStart ? false : true; return seekMsgStart ? false : true;
} }
} }
} // end if (!segment)
UINT16 length = NormDataMsg::ReadStreamPayloadLength(segment);
if (length > segment_size)
{
Release();
if (bytesRead > 0)
{
// Go ahead and return data read thus so far
*buflen = bytesRead;
return true;
}
else
{
// Skip this invalid segment
DMSG(0, "NormStreamObject::Read() node>%lu obj>%hu blk>%lu seg>%hu invalid stream segment! (read_offset>%lu length>%hu)\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)read_index.block, read_index.segment, read_offset, length);
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);
}
*buflen = 0;
return false;
}
} }
UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment); UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment);
@ -2844,26 +2887,44 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
UINT32 diff = read_offset - segmentOffset; UINT32 diff = read_offset - segmentOffset;
if ((diff > 0x80000000) || ((0x80000000 == diff) && (read_offset > segmentOffset))) if ((diff > 0x80000000) || ((0x80000000 == diff) && (read_offset > segmentOffset)))
{ {
DMSG(4, "NormStreamObject::Read() node>%lu obj>%hu blk>%lu seg>%hu broken stream! (read_offset>%lu segmentOffset>%lu)\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)read_index.block, read_index.segment, read_offset, segmentOffset);
read_offset = segmentOffset;
*buflen = bytesRead;
Release(); Release();
return false; if (bytesRead > 0)
{
// Go ahead and return data read thus so far
*buflen = bytesRead;
return true;
}
else
{
DMSG(4, "NormStreamObject::Read() node>%lu obj>%hu blk>%lu seg>%hu broken stream! (read_offset>%lu segmentOffset>%lu)\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)read_index.block, read_index.segment, read_offset, segmentOffset);
read_offset = segmentOffset;
*buflen = 0;
return false;
}
} }
UINT32 index = read_offset - segmentOffset; UINT32 index = read_offset - segmentOffset;
UINT16 length = NormDataMsg::ReadStreamPayloadLength(segment);
if ((length > 0) && (index >= length)) if ((length > 0) && (index >= length))
{ {
DMSG(0, "NormStreamObject::Read() node>%lu obj>%hu blk>%lu seg>%hu mangled stream! index:%hu length:%hu "
"read_offset:%lu segmentOffset:%lu\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)read_index.block, read_index.segment, index, length, read_offset, segmentOffset);
read_offset = segmentOffset;
*buflen = bytesRead;
ASSERT(0);
Release(); Release();
return false; if (bytesRead > 0)
{
// Go ahead and return data read thus so far
*buflen = bytesRead;
return true;
}
else
{
DMSG(0, "NormStreamObject::Read() node>%lu obj>%hu blk>%lu seg>%hu mangled stream! index:%hu length:%hu "
"read_offset:%lu segmentOffset:%lu\n",
LocalNodeId(), (UINT16)transport_id, (UINT32)read_index.block, read_index.segment, index, length, read_offset, segmentOffset);
// Reset our read_offset ...
read_offset = segmentOffset;
*buflen = 0;
return false;
}
} }
@ -2895,9 +2956,8 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
block_pool.Put(block); block_pool.Put(block);
read_index.block++; read_index.block++;
read_index.segment = 0; read_index.segment = 0;
Prune(read_index.block); Prune(read_index.block, false);
} }
TRACE("continue ...\n");
continue; continue;
} }
else else
@ -2934,7 +2994,7 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
block_pool.Put(block); block_pool.Put(block);
read_index.block++; read_index.block++;
read_index.segment = 0; read_index.segment = 0;
Prune(read_index.block); Prune(read_index.block, false);
} }
if (streamEnded) if (streamEnded)
{ {
@ -2947,7 +3007,6 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool seekMsgStar
} while ((bytesToRead > 0) || seekMsgStart); // end while (len > 0) } while ((bytesToRead > 0) || seekMsgStart); // end while (len > 0)
*buflen = bytesRead; *buflen = bytesRead;
Release(); Release();
TRACE("return 7\n");
return true; return true;
} // end NormStreamObject::Read() } // end NormStreamObject::Read()
@ -3205,8 +3264,8 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
if (0 != nBytes) if (0 != nBytes)
session.TouchServer(); session.TouchServer();
} }
//if ((0 != nBytes) && posted_tx_queue_vacancy) if ((0 != nBytes) && posted_tx_queue_vacancy)
// posted_tx_queue_vacancy = false; posted_tx_queue_vacancy = false;
return nBytes; return nBytes;
} // end NormStreamObject::Write() } // end NormStreamObject::Write()
@ -3262,10 +3321,8 @@ UINT16 NormSimObject::ReadSegment(NormBlockId blockId,
} // end NormSimObject::ReadSegment() } // end NormSimObject::ReadSegment()
char* NormSimObject::RetrieveSegment(NormBlockId blockId, char* NormSimObject::RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId)
bool& tempRetrieval)
{ {
tempRetrieval = true;
return server ? server->GetRetrievalSegment() : NULL; return server ? server->GetRetrievalSegment() : NULL;
} // end NormSimObject::RetrieveSegment() } // end NormSimObject::RetrieveSegment()
@ -3313,7 +3370,7 @@ void NormObjectTable::Destroy()
while((obj = Find(range_lo))) while((obj = Find(range_lo)))
{ {
Remove(obj); Remove(obj);
delete obj; // (TBD - make this obj->Release() ??? obj->Release();
} }
delete []table; delete []table;
table = (NormObject**)NULL; table = (NormObject**)NULL;
@ -3405,10 +3462,11 @@ bool NormObjectTable::Insert(NormObject* theObject)
theObject->next = entry; theObject->next = entry;
count++; count++;
size = size + theObject->GetSize(); size = size + theObject->GetSize();
theObject->Retain();
return true; return true;
} // end NormObjectTable::Insert() } // end NormObjectTable::Insert()
bool NormObjectTable::Remove(const NormObject* theObject) bool NormObjectTable::Remove(NormObject* theObject)
{ {
ASSERT(theObject); ASSERT(theObject);
const NormObjectId& objectId = theObject->GetId(); const NormObjectId& objectId = theObject->GetId();
@ -3508,6 +3566,7 @@ bool NormObjectTable::Remove(const NormObject* theObject)
} }
count--; count--;
size = size - theObject->GetSize(); size = size - theObject->GetSize();
theObject->Release();
return true; return true;
} }
else else

View File

@ -36,7 +36,7 @@ class NormObject
NACK_INFO_ONLY, NACK_INFO_ONLY,
NACK_NORMAL NACK_NORMAL
}; };
virtual ~NormObject(); virtual ~NormObject();
void Retain(); void Retain();
void Release(); void Release();
@ -93,8 +93,7 @@ class NormObject
char* buffer) = 0; char* buffer) = 0;
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId) = 0;
bool& tempRetrieval) = 0;
NackingMode GetNackingMode() const {return nacking_mode;} NackingMode GetNackingMode() const {return nacking_mode;}
void SetNackingMode(NackingMode nackingMode) void SetNackingMode(NackingMode nackingMode)
@ -304,8 +303,7 @@ class NormFileObject : public NormObject
char* buffer); char* buffer);
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId);
bool& tempRetrieval);
private: private:
char path[PATH_MAX]; char path[PATH_MAX];
@ -348,8 +346,7 @@ class NormDataObject : public NormObject
char* buffer); char* buffer);
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId);
bool& tempRetrieval);
private: private:
NormObjectSize large_block_length; NormObjectSize large_block_length;
@ -407,9 +404,12 @@ class NormStreamObject : public NormObject
UINT32 GetCurrentReadOffset() {return read_offset;} UINT32 GetCurrentReadOffset() {return read_offset;}
bool StreamUpdateStatus(NormBlockId blockId); bool StreamUpdateStatus(NormBlockId blockId);
void StreamResync(NormBlockId nextBlockId) // Note that the "pending_mask" should be cleared and the
// "block_buffer" emptied before "StreamResync()" is invoked
void StreamResync(NormBlockId blockId)
{ {
stream_next_id = nextBlockId; stream_sync = false;
StreamUpdateStatus(blockId);
} }
void StreamAdvance(); void StreamAdvance();
@ -422,8 +422,7 @@ class NormStreamObject : public NormObject
char* buffer); char* buffer);
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId);
bool& tempRetrieval);
// For receive stream, we can rewind to earliest buffered offset // For receive stream, we can rewind to earliest buffered offset
@ -433,7 +432,7 @@ class NormStreamObject : public NormObject
bool LockSegments(NormBlockId blockId, NormSegmentId firstId, bool LockSegments(NormBlockId blockId, NormSegmentId firstId,
NormSegmentId lastId); NormSegmentId lastId);
NormBlockId StreamBufferLo() {return stream_buffer.RangeLo();} NormBlockId StreamBufferLo() {return stream_buffer.RangeLo();}
void Prune(NormBlockId blockId); void Prune(NormBlockId blockId, bool updateStatus);
bool IsFlushPending() {return flush_pending;} bool IsFlushPending() {return flush_pending;}
NormBlockId FlushBlockId() NormBlockId FlushBlockId()
@ -518,8 +517,7 @@ class NormSimObject : public NormObject
char* buffer); char* buffer);
virtual char* RetrieveSegment(NormBlockId blockId, virtual char* RetrieveSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId);
bool& tempRetrieval);
}; // end class NormSimObject }; // end class NormSimObject
#endif // SIMULATE #endif // SIMULATE
@ -537,7 +535,7 @@ class NormObjectTable
bool IsInited() const {return (NULL != table);} bool IsInited() const {return (NULL != table);}
bool CanInsert(NormObjectId objectId) const; bool CanInsert(NormObjectId objectId) const;
bool Insert(NormObject* theObject); bool Insert(NormObject* theObject);
bool Remove(const NormObject* theObject); bool Remove(NormObject* theObject);
NormObject* Find(const NormObjectId& objectId) const; NormObject* Find(const NormObjectId& objectId) const;
NormObjectId RangeLo() const {return range_lo;} NormObjectId RangeLo() const {return range_lo;}

View File

@ -155,7 +155,7 @@ void NormBlock::EmptyToPool(NormSegmentPool& segmentPool)
ASSERT(segment_table); ASSERT(segment_table);
for (unsigned int i = 0; i < size; i++) for (unsigned int i = 0; i < size; i++)
{ {
if (segment_table[i]) if (NULL != segment_table[i])
{ {
segmentPool.Put(segment_table[i]); segmentPool.Put(segment_table[i]);
segment_table[i] = (char*)NULL; segment_table[i] = (char*)NULL;

View File

@ -147,7 +147,7 @@ class NormBlock
pending_mask.SetBits(0, ndata+nparity); pending_mask.SetBits(0, ndata+nparity);
repair_mask.Clear(); repair_mask.Clear();
erasure_count = ndata; erasure_count = ndata;
parity_count = 0; parity_count = 0;
parity_offset = 0; parity_offset = 0;
flags = 0; flags = 0;
} }

View File

@ -6,7 +6,7 @@ const UINT8 NormSession::DEFAULT_TTL = 255; // bits/sec
const double NormSession::DEFAULT_TRANSMIT_RATE = 64000.0; // bits/sec const double NormSession::DEFAULT_TRANSMIT_RATE = 64000.0; // bits/sec
const double NormSession::DEFAULT_GRTT_INTERVAL_MIN = 1.0; // sec const double NormSession::DEFAULT_GRTT_INTERVAL_MIN = 1.0; // sec
const double NormSession::DEFAULT_GRTT_INTERVAL_MAX = 30.0; // sec const double NormSession::DEFAULT_GRTT_INTERVAL_MAX = 30.0; // sec
const double NormSession::DEFAULT_GRTT_ESTIMATE = 0.5; // sec const double NormSession::DEFAULT_GRTT_ESTIMATE = 0.25; // sec
const double NormSession::DEFAULT_GRTT_MAX = 10.0; // sec const double NormSession::DEFAULT_GRTT_MAX = 10.0; // sec
const unsigned int NormSession::DEFAULT_GRTT_DECREASE_DELAY = 3; const unsigned int NormSession::DEFAULT_GRTT_DECREASE_DELAY = 3;
const double NormSession::DEFAULT_BACKOFF_FACTOR = 4.0; const double NormSession::DEFAULT_BACKOFF_FACTOR = 4.0;
@ -18,7 +18,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
: session_mgr(sessionMgr), notify_pending(false), tx_port(0), : session_mgr(sessionMgr), notify_pending(false), tx_port(0),
tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP), tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP),
rx_socket(ProtoSocket::UDP), local_node_id(localNodeId), rx_socket(ProtoSocket::UDP), local_node_id(localNodeId),
ttl(DEFAULT_TTL), loopback(false), ttl(DEFAULT_TTL), loopback(false), rx_port_reuse(false),
tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0), tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0), backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0),
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0), ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
@ -28,7 +28,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
posted_tx_queue_empty(false), posted_tx_queue_empty(false),
acking_node_count(0), watermark_pending(false), advertise_repairs(false), acking_node_count(0), watermark_pending(false), advertise_repairs(false),
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0), suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
probe_proactive(true), probe_pending(false), probe_reset(false), probe_proactive(true), probe_pending(false), probe_reset(true),
grtt_interval(0.5), grtt_interval(0.5),
grtt_interval_min(DEFAULT_GRTT_INTERVAL_MIN), grtt_interval_min(DEFAULT_GRTT_INTERVAL_MIN),
grtt_interval_max(DEFAULT_GRTT_INTERVAL_MAX), grtt_interval_max(DEFAULT_GRTT_INTERVAL_MAX),
@ -64,6 +64,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
probe_timer.SetListener(this, &NormSession::OnProbeTimeout); probe_timer.SetListener(this, &NormSession::OnProbeTimeout);
probe_timer.SetInterval(0.0); probe_timer.SetInterval(0.0);
probe_timer.SetRepeat(-1); probe_timer.SetRepeat(-1);
probe_time_last.tv_sec = probe_time_last.tv_usec = 0;
grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE); grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE);
grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized);
@ -107,12 +108,33 @@ bool NormSession::Open(const char* interfaceName)
} }
if (!rx_socket.IsOpen()) if (!rx_socket.IsOpen())
{ {
if (!rx_socket.Open(address.GetPort(), address.GetType())) if (!rx_socket.Open(0, address.GetType(), false))
{ {
DMSG(0, "NormSession::Open() rx_socket open error\n"); DMSG(0, "NormSession::Open() rx_socket open error\n");
Close(); Close();
return false; return false;
} }
const ProtoAddress* bindAddr = NULL;
if (rx_port_reuse)
{
// Enable port/addr reuse and bind socket to destination address
if (!rx_socket.SetReuse(true))
{
DMSG(0, "NormSession::Open() rx_socket reuse error\n");
Close();
return false;
}
#ifndef WIN32
if (address.IsMulticast()) // Win32 doesn't like to bind to multicast addr ???
bindAddr = &address;
#endif // !WIN32
}
if(!rx_socket.Bind(address.GetPort(), bindAddr))
{
DMSG(0, "NormSession::Open() rx_socket bind error\n");
Close();
return false;
}
} }
if (address.IsMulticast()) if (address.IsMulticast())
@ -198,11 +220,13 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
{ {
if (interfaceName) if (interfaceName)
{ {
bool result = true; bool result = true;
if (rx_socket.IsOpen()) if (rx_socket.IsOpen())
result &= rx_socket.SetMulticastInterface(interfaceName); result &= rx_socket.SetMulticastInterface(interfaceName);
if (tx_socket->IsOpen()) if (tx_socket->IsOpen())
result &= tx_socket->SetMulticastInterface(interfaceName); result &= tx_socket->SetMulticastInterface(interfaceName);
strncpy(interface_name, interfaceName, 32);
return result; return result;
} }
else else
@ -212,9 +236,8 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
} }
} // end NormSession::SetMulticastInterface() } // end NormSession::SetMulticastInterface()
void NormSession::SetTxRate(double txRate) void NormSession::SetTxRateInternal(double txRate)
{ {
txRate /= 8.0; // convert to bytes/sec
if (tx_timer.IsActive()) if (tx_timer.IsActive())
{ {
tx_timer.Deactivate(); tx_timer.Deactivate();
@ -236,7 +259,19 @@ void NormSession::SetTxRate(double txRate)
{ {
tx_rate = txRate; tx_rate = txRate;
} }
} // end NormSession::SetTxRate() 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) void NormSession::SetTxRateBounds(double rateMin, double rateMax)
{ {
@ -264,7 +299,7 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
tx_rate = tx_rate_min; tx_rate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max; tx_rate = tx_rate_max;
SetTxRate(tx_rate*8.0); SetTxRateInternal(tx_rate);
} }
} // end NormSession::SetTxRateBounds() } // end NormSession::SetTxRateBounds()
@ -348,8 +383,6 @@ bool NormSession::StartServer(UINT16 instanceId,
nparity = numParity; nparity = numParity;
is_server = true; is_server = true;
flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor
//probe_timer.SetInterval(0.0);
probe_pending = probe_reset = false;
if (cc_enable) if (cc_enable)
{ {
@ -359,16 +392,25 @@ bool NormSession::StartServer(UINT16 instanceId,
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max; tx_rate = tx_rate_max;
} }
grtt_age = 0.0;
OnProbeTimeout(probe_timer); probe_pending = false;
ActivateTimer(probe_timer); if (probe_reset)
{
probe_reset = false;
OnProbeTimeout(probe_timer);
ActivateTimer(probe_timer);
}
return true; return true;
} // end NormSession::StartServer() } // end NormSession::StartServer()
void NormSession::StopServer() void NormSession::StopServer()
{ {
if (probe_timer.IsActive()) probe_timer.Deactivate(); if (probe_timer.IsActive())
{
probe_timer.Deactivate();
probe_reset = true;
}
encoder.Destroy(); encoder.Destroy();
acking_node_tree.Destroy(); acking_node_tree.Destroy();
cc_node_list.Destroy(); cc_node_list.Destroy();
@ -685,7 +727,6 @@ void NormSession::ServerRemoveAckingNode(NormNodeId nodeId)
if (watermark_pending && theNode->AckReceived()) if (watermark_pending && theNode->AckReceived())
acks_collected--; acks_collected--;
acking_node_tree.DetachNode(theNode); acking_node_tree.DetachNode(theNode);
delete theNode;
acking_node_count--; acking_node_count--;
} }
} // end NormSession::RemoveAckingNode() } // end NormSession::RemoveAckingNode()
@ -863,7 +904,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
if (!file->Open(path, infoPtr, infoLen)) if (!file->Open(path, infoPtr, infoLen))
{ {
DMSG(0, "NormSession::QueueTxFile() file open error\n"); DMSG(0, "NormSession::QueueTxFile() file open error\n");
delete file; file->Release();
return NULL; return NULL;
} }
if (QueueTxObject(file)) if (QueueTxObject(file))
@ -873,7 +914,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
else else
{ {
file->Close(); file->Close();
delete file; file->Release();
return NULL; return NULL;
} }
} // end NormSession::QueueTxFile() } // end NormSession::QueueTxFile()
@ -898,7 +939,7 @@ NormDataObject* NormSession::QueueTxData(const char* dataPtr,
if (!obj->Open((char*)dataPtr, dataLen, false, infoPtr, infoLen)) if (!obj->Open((char*)dataPtr, dataLen, false, infoPtr, infoLen))
{ {
DMSG(0, "NormSession::QueueTxData() object open error\n"); DMSG(0, "NormSession::QueueTxData() object open error\n");
delete obj; obj->Release();
return NULL; return NULL;
} }
if (QueueTxObject(obj)) if (QueueTxObject(obj))
@ -908,7 +949,7 @@ NormDataObject* NormSession::QueueTxData(const char* dataPtr,
else else
{ {
obj->Close(); obj->Close();
delete obj; obj->Release();
return NULL; return NULL;
} }
} // end NormSession::QueueTxData() } // end NormSession::QueueTxData()
@ -934,7 +975,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
if (!stream->Open(bufferSize, doubleBuffer, infoPtr, infoLen)) if (!stream->Open(bufferSize, doubleBuffer, infoPtr, infoLen))
{ {
DMSG(0, "NormSession::QueueTxStream() stream open error\n"); DMSG(0, "NormSession::QueueTxStream() stream open error\n");
delete stream; stream->Release();
return NULL; return NULL;
} }
if (QueueTxObject(stream)) if (QueueTxObject(stream))
@ -946,7 +987,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
else else
{ {
stream->Close(); stream->Close();
delete stream; stream->Release();
return NULL; return NULL;
} }
} // end NormSession::QueueTxStream() } // end NormSession::QueueTxStream()
@ -970,7 +1011,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
if (!simObject->Open(objectSize)) if (!simObject->Open(objectSize))
{ {
DMSG(0, "NormSession::QueueTxSim() open error\n"); DMSG(0, "NormSession::QueueTxSim() open error\n");
delete simObject; simObject->Release();
return NULL; return NULL;
} }
if (QueueTxObject(simObject)) if (QueueTxObject(simObject))
@ -979,7 +1020,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
} }
else else
{ {
delete simObject; simObject->Release();
return NULL; return NULL;
} }
} // end NormSession::QueueTxSim() } // end NormSession::QueueTxSim()
@ -1024,7 +1065,6 @@ bool NormSession::QueueTxObject(NormObject* obj)
ASSERT(0); ASSERT(0);
return false; return false;
} }
obj->Retain();
tx_pending_mask.Set(obj->GetId()); tx_pending_mask.Set(obj->GetId());
ASSERT(tx_pending_mask.Test(obj->GetId())); ASSERT(tx_pending_mask.Test(obj->GetId()));
next_tx_object_id++; next_tx_object_id++;
@ -1351,11 +1391,12 @@ void NormTrace(const struct timeval& currentTime,
void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast) void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast)
{ {
// Ignore messages from ourself unless "loopback" is enabled
if ((msg.GetSourceId() == LocalNodeId()) && !loopback)
return;
// Drop some rx messages for testing // Drop some rx messages for testing
if (UniformRand(100.0) < rx_loss_rate) if (UniformRand(100.0) < rx_loss_rate)
{
return; return;
}
struct timeval currentTime; struct timeval currentTime;
::ProtoSystemTime(currentTime); ::ProtoSystemTime(currentTime);
@ -1434,7 +1475,6 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
if (theServer->Open(msg.GetInstanceId())) if (theServer->Open(msg.GetInstanceId()))
{ {
server_tree.AttachNode(theServer); server_tree.AttachNode(theServer);
theServer->Retain();
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n", DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
LocalNodeId(), msg.GetSourceId()); LocalNodeId(), msg.GetSourceId());
} }
@ -1492,7 +1532,6 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
if (theServer->Open(cmd.GetInstanceId())) if (theServer->Open(cmd.GetInstanceId()))
{ {
server_tree.AttachNode(theServer); server_tree.AttachNode(theServer);
theServer->Retain();
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n", DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
LocalNodeId(), cmd.GetSourceId()); LocalNodeId(), cmd.GetSourceId());
} }
@ -1555,28 +1594,32 @@ double NormSession::CalculateRtt(const struct timeval& currentTime,
void NormSession::ServerUpdateGrttEstimate(double clientRtt) void NormSession::ServerUpdateGrttEstimate(double clientRtt)
{ {
grtt_response = true; grtt_response = true;
//if ((clientRtt > grtt_current_peak) || !address.IsMulticast())
if ((clientRtt > grtt_measured) || !address.IsMulticast()) if ((clientRtt > grtt_measured) || !address.IsMulticast())
{ {
// Immediately incorporate bigger RTT's // Immediately incorporate bigger RTT's
grtt_current_peak = clientRtt; grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
//if ((clientRtt > grtt_measured) || !address.IsMulticast()) //grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
{ grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY; if (grtt_measured > grtt_max) grtt_measured = grtt_max;
//grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt; UINT8 grttQuantizedOld = grtt_quantized;
grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt; double pktInterval = ((double)(44+segment_size))/tx_rate;
if (grtt_measured > grtt_max) grtt_measured = grtt_max; if (grtt_measured < pktInterval)
double pktInterval = ((double)(44+segment_size))/tx_rate; grtt_quantized = NormQuantizeRtt(pktInterval);
UINT8 grttQuantizedOld = grtt_quantized; else
grtt_quantized = NormQuantizeRtt(MAX(pktInterval, grtt_measured)); grtt_quantized = NormQuantizeRtt(grtt_measured);
// Calculate grtt_advertised since quantization rounds upward // Calculate grtt_advertised since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_advertised = NormUnquantizeRtt(grtt_quantized);
grtt_current_peak = grtt_measured;
if (grttQuantizedOld != grtt_quantized) if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu new grtt>%lf sec\n", DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu increased to new grtt>%lf sec\n",
LocalNodeId(), grtt_advertised); LocalNodeId(), grtt_advertised);
}
} }
else if (clientRtt > grtt_current_peak)
{
grtt_current_peak = clientRtt;
}
} // end NormSession::ServerUpdateGrttEstimate() } // end NormSession::ServerUpdateGrttEstimate()
double NormSession::CalculateRate(double size, double rtt, double loss) double NormSession::CalculateRate(double size, double rtt, double loss)
@ -1587,12 +1630,13 @@ double NormSession::CalculateRate(double size, double rtt, double loss)
return (size / denom); return (size / denom);
} // end NormSession::CalculateRate() } // end NormSession::CalculateRate()
void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, void NormSession::ServerHandleCCFeedback(struct timeval currentTime,
UINT8 ccFlags, NormNodeId nodeId,
double ccRtt, UINT8 ccFlags,
double ccLoss, double ccRtt,
double ccRate, double ccLoss,
UINT16 ccSequence) double ccRate,
UINT16 ccSequence)
{ {
// Keep track of current suppressing feedback // Keep track of current suppressing feedback
// (non-CLR, lowest rate, unconfirmed RTT) // (non-CLR, lowest rate, unconfirmed RTT)
@ -1641,6 +1685,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
double savedLoss = next->GetLoss(); double savedLoss = next->GetLoss();
double savedRate = next->GetRate(); double savedRate = next->GetRate();
UINT16 savedSequence = next->GetCCSequence(); UINT16 savedSequence = next->GetCCSequence();
struct timeval savedTime = next->GetFeedbackTime();
next->SetId(nodeId); next->SetId(nodeId);
next->SetClrStatus(true); next->SetClrStatus(true);
@ -1649,7 +1694,8 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
next->SetRate(ccRate); next->SetRate(ccRate);
next->SetCCSequence(ccSequence); next->SetCCSequence(ccSequence);
next->SetActive(true); next->SetActive(true);
if (next->GetId() == nodeId) next->SetFeedbackTime(currentTime);
if (savedId == nodeId)
{ {
// This was feedback from the current CLR // This was feedback from the current CLR
AdjustRate(true); AdjustRate(true);
@ -1668,6 +1714,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
ccLoss = savedLoss; ccLoss = savedLoss;
ccRate = savedRate, ccRate = savedRate,
ccSequence = savedSequence; ccSequence = savedSequence;
currentTime = savedTime;
} }
} }
else else
@ -1688,12 +1735,14 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
} }
next->SetId(nodeId); next->SetId(nodeId);
next->SetClrStatus(true); next->SetClrStatus(true);
//next->SetPlrStatus(false);
next->SetRttStatus(0 != (ccFlags & NormCC::RTT)); next->SetRttStatus(0 != (ccFlags & NormCC::RTT));
next->SetRtt(ccRtt); next->SetRtt(ccRtt);
next->SetLoss(ccLoss); next->SetLoss(ccLoss);
next->SetRate(ccRate); next->SetRate(ccRate);
next->SetCCSequence(ccSequence); next->SetCCSequence(ccSequence);
next->SetActive(true); next->SetActive(true);
next->SetFeedbackTime(currentTime);
AdjustRate(true); AdjustRate(true);
return; return;
} }
@ -1764,6 +1813,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
{ {
candidate->SetId(nodeId); candidate->SetId(nodeId);
candidate->SetClrStatus(false); candidate->SetClrStatus(false);
//candidate->SetPlrStatus(true); // do this only
candidate->SetRttStatus(0 != (ccFlags & NormCC::RTT)); candidate->SetRttStatus(0 != (ccFlags & NormCC::RTT));
candidate->SetRtt(ccRtt); candidate->SetRtt(ccRtt);
candidate->SetLoss(ccLoss); candidate->SetLoss(ccLoss);
@ -1789,28 +1839,28 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
{ {
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType()) if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
{ {
ServerHandleCCFeedback(ack.GetSourceId(), ServerHandleCCFeedback(currentTime,
ack.GetSourceId(),
ext.GetCCFlags(), ext.GetCCFlags(),
clientRtt >= 0.0 ? clientRtt >= 0.0 ?
clientRtt : NormUnquantizeRtt(ext.GetCCRtt()), clientRtt : NormUnquantizeRtt(ext.GetCCRtt()),
NormUnquantizeLoss(ext.GetCCLoss()), NormUnquantizeLoss(ext.GetCCLoss()),
NormUnquantizeRate(ext.GetCCRate()), NormUnquantizeRate(ext.GetCCRate()),
ext.GetCCSequence()); ext.GetCCSequence());
if (wasUnicast && probe_proactive && Address().IsMulticast())
{
// for suppression of unicast cc feedback
advertise_repairs = true;
QueueMessage(NULL);
}
break;
} }
break;
}
if (wasUnicast && probe_proactive && Address().IsMulticast())
{
// for suppression of unicast feedback
advertise_repairs = true;
QueueMessage(NULL);
} }
switch (ack.GetAckType()) switch (ack.GetAckType())
{ {
case NormAck::CC: case NormAck::CC:
// Everything is in the ACK header for this one // Everything is in the ACK header or extension for this one
break; break;
case NormAck::FLUSH: case NormAck::FLUSH:
@ -1880,7 +1930,8 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
{ {
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType()) if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
{ {
ServerHandleCCFeedback(nack.GetSourceId(), ServerHandleCCFeedback(currentTime,
nack.GetSourceId(),
ext.GetCCFlags(), ext.GetCCFlags(),
clientRtt >= 0.0 ? clientRtt >= 0.0 ?
clientRtt : NormUnquantizeRtt(ext.GetCCRtt()), clientRtt : NormUnquantizeRtt(ext.GetCCRtt()),
@ -2583,9 +2634,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
{ {
NormMsg* msg; NormMsg* msg;
// (TBD) sometimes need RepairAdv even when cc_enable is false ... // Note: sometimes need RepairAdv even when cc_enable is false ...
NormCmdRepairAdvMsg adv; NormCmdRepairAdvMsg adv;
if (advertise_repairs && (probe_proactive || (repair_timer.IsActive() && if (advertise_repairs && (probe_proactive || (repair_timer.IsActive() &&
repair_timer.GetRepeatCount()))) repair_timer.GetRepeatCount())))
{ {
@ -2729,7 +2779,7 @@ bool NormSession::SendMessage(NormMsg& msg)
break; break;
} }
// Fill in common message fields // Fill in common message fields
msg.SetSourceId(local_node_id); msg.SetSourceId(local_node_id);
UINT16 msgSize = msg.GetLength(); UINT16 msgSize = msg.GetLength();
bool result = true; bool result = true;
@ -2798,6 +2848,82 @@ bool NormSession::SendMessage(NormMsg& msg)
return result; return result;
} // end NormSession::SendMessage() } // end NormSession::SendMessage()
void NormSession::SetGrttProbingInterval(double intervalMin, double intervalMax)
{
if ((intervalMin < 0.0) || (intervalMax < 0.0)) return;
double temp = intervalMin;
if (temp > intervalMax)
{
intervalMin = intervalMax;
intervalMax = temp;
}
if (intervalMin < 0.100) intervalMin = 0.100;
if (intervalMax < 0.100) intervalMax = 0.100;
grtt_interval_min = intervalMin;
grtt_interval_max = intervalMax;
if (grtt_interval < grtt_interval_min)
grtt_interval = grtt_interval_min;
if (grtt_interval > grtt_interval_max)
{
grtt_interval = grtt_interval_max;
if (probe_timer.IsActive() && !cc_enable)
{
double elapsed = probe_timer.GetInterval() - probe_timer.GetTimeRemaining();
if (elapsed < 0.0) elapsed = 0.0;
probe_timer.Deactivate();
if (elapsed > grtt_interval)
probe_timer.SetInterval(0.0);
else
probe_timer.SetInterval(grtt_interval - elapsed);
ActivateTimer(probe_timer);
}
}
} // end NormSession::SetGrttProbingInterval()
void NormSession::SetGrttProbingMode(ProbingMode probingMode)
{
if (cc_enable) return; // can't change probing mode when cc is enabled!
// (cc _requires_ probing mode == PROBE_ACTIVE)
switch (probingMode)
{
case PROBE_NONE:
probe_reset = false;
if (probe_timer.IsActive())
probe_timer.Deactivate();
break;
case PROBE_PASSIVE:
probe_proactive = false;
if (IsServer())
{
if (!probe_timer.IsActive())
{
probe_timer.SetInterval(0.0);
ActivateTimer(probe_timer);
}
}
else
{
probe_reset = true;
}
break;
case PROBE_ACTIVE:
probe_proactive = true;
if (IsServer())
{
if (!probe_timer.IsActive())
{
probe_timer.SetInterval(0.0);
ActivateTimer(probe_timer);
}
}
else
{
probe_reset = true;
}
break;
}
} // end NormSession::SetGrttProbingMode()
bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/) bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
{ {
// 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd // 1) Temporarily kill probe_timer if CMD(CC) not yet tx'd
@ -2809,17 +2935,45 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
} }
else if (0.0 == tx_rate) else if (0.0 == tx_rate)
{ {
// Sender paused, just idle probing until transmission is resumed // Sender paused, so just skip probing until transmission is resumed
return true; return true;
} }
// 2) Update grtt_estimate _if_ sufficient time elapsed. // 2) Update grtt_estimate _if_ sufficient time elapsed.
// This new code allows more liberal downward adjustment of // This new code allows more liberal downward adjustment of
// of grtt when congestion control is enabled. // of grtt when congestion control is enabled.
grtt_age += probe_timer.GetInterval();
double ageMax = 3 * grtt_advertised; // We have to keep track of the _actual_ deltaTime instead
ageMax = ageMax > grtt_interval_min ? ageMax : grtt_interval_min; // of relying on the probe_timer interval because in real-
if (grtt_age >= ageMax)//grtt_interval) // world operating systems, they're aren't the same and
// sometimes not even close.
struct timeval currentTime;
ProtoSystemTime(currentTime);
if ((0 == probe_time_last.tv_sec) && (0 == probe_time_last.tv_usec))
{
grtt_age += probe_timer.GetInterval();
}
else
{
double deltaTime = currentTime.tv_sec - probe_time_last.tv_sec;
if (currentTime.tv_usec > probe_time_last.tv_usec)
deltaTime += 1.0e-06*((double)(currentTime.tv_usec - probe_time_last.tv_usec));
else
deltaTime -= 1.0e-06*((double)(probe_time_last.tv_usec - currentTime.tv_usec));
grtt_age += deltaTime;
}
probe_time_last = currentTime;
// (TBD) We need to revisit the whole set of issues surrounding dynamic
// estimation of grtt, particularly when congestion control is involved.
// The main issue is when the rate increases rapidly with respect to
// how the grtt estimate is descreasing ... this is most notable at
// startup and thus the hack here to allow the grtt estimate to more
// rapidly decrease during "slow start"
double ageMax = grtt_advertised;
if (!cc_enable && !cc_slow_start)
ageMax = ageMax > grtt_interval_min ? ageMax : grtt_interval_min;
if (grtt_age >= ageMax)
{ {
if (grtt_response) if (grtt_response)
{ {
@ -2844,16 +2998,18 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
grtt_measured = NORM_GRTT_MIN; grtt_measured = NORM_GRTT_MIN;
else if (grtt_measured > grtt_max) else if (grtt_measured > grtt_max)
grtt_measured = grtt_max; grtt_measured = grtt_max;
UINT8 grttQuantizedOld = grtt_quantized;
double pktInterval = (double)(44+segment_size)/tx_rate; double pktInterval = (double)(44+segment_size)/tx_rate;
grtt_advertised = MAX(pktInterval, grtt_measured); if (grtt_measured < pktInterval)
double grttQuantizedOld = grtt_quantized; grtt_quantized = NormQuantizeRtt(pktInterval);
grtt_quantized = NormQuantizeRtt(grtt_advertised); else
grtt_quantized = NormQuantizeRtt(grtt_measured);
// Recalculate grtt_advertise since quantization rounds upward // Recalculate grtt_advertise since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized); grtt_advertised = NormUnquantizeRtt(grtt_quantized);
grtt_response = false;
if (grttQuantizedOld != grtt_quantized) if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::OnProbeTimeout() node>%lu new grtt: %lf\n", DMSG(4, "NormSession::OnProbeTimeout() node>%lu decreased to new grtt to: %lf sec\n",
LocalNodeId(), grtt_advertised); LocalNodeId(), grtt_advertised);
grtt_response = false; // reset
} }
grtt_age = 0.0; grtt_age = 0.0;
} }
@ -2876,10 +3032,9 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
cmd->Init(); cmd->Init();
cmd->SetDestination(address); cmd->SetDestination(address);
cmd->SetGrtt(grtt_quantized); cmd->SetGrtt(grtt_quantized);
cmd->SetBackoffFactor((unsigned char)backoff_factor); cmd->SetBackoffFactor((unsigned char)backoff_factor);
cmd->SetGroupSize(gsize_quantized); cmd->SetGroupSize(gsize_quantized);
// SetSendTime() when message is being sent (in OnTxTimeout()) // defer SetSendTime() to when message is being sent (in OnTxTimeout())
cmd->SetCCSequence(cc_sequence++); cmd->SetCCSequence(cc_sequence++);
if (probe_proactive) if (probe_proactive)
@ -2900,7 +3055,10 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
if (next->IsActive()) if (next->IsActive())
{ {
UINT8 ccFlags = 0; UINT8 ccFlags = 0;
if (next->IsClr()) ccFlags |= (UINT8)NormCC::CLR; if (next->IsClr())
ccFlags |= (UINT8)NormCC::CLR;
else if (next->IsPlr())
ccFlags |= (UINT8)NormCC::PLR;
ccFlags |= (UINT8)NormCC::RTT; ccFlags |= (UINT8)NormCC::RTT;
UINT8 rttQuantized = NormQuantizeRtt(next->GetRtt()); UINT8 rttQuantized = NormQuantizeRtt(next->GetRtt());
if (cc_slow_start) ccFlags |= (UINT8)NormCC::START; if (cc_slow_start) ccFlags |= (UINT8)NormCC::START;
@ -2911,14 +3069,26 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
ccFlags, ccFlags,
rttQuantized, rttQuantized,
rateQuantized); rateQuantized);
if (!next->IsClr()) next->SetActive(false); //if (!next->IsClr()) next->SetActive(false);
// Deactivate any nodes who have stopped providing feedback
struct timeval feedbackTime = next->GetFeedbackTime();
double feedbackAge = currentTime.tv_sec - feedbackTime.tv_sec;
if (currentTime.tv_usec > feedbackTime.tv_usec)
feedbackAge += 1.0e-06*((double)(currentTime.tv_usec - feedbackTime.tv_usec));
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
if (feedbackAge > maxFeedbackAge)
next->SetActive(false);
} }
} }
AdjustRate(false); AdjustRate(false);
// Determine next probe_interval // Determine next probe_interval
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head(); const NormCCNode* clr = static_cast<const NormCCNode*>(cc_node_list.Head());
probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised; probeInterval = clr ? MIN(grtt_advertised, clr->GetRtt()) : grtt_advertised;
//double nominalRate = ((double)segment_size)/((double)tx_rate); //double nominalRate = ((double)segment_size)/((double)tx_rate);
//probeInterval = MAX(probeInterval, nominalRate); //probeInterval = MAX(probeInterval, nominalRate);
@ -2944,7 +3114,7 @@ void NormSession::AdjustRate(bool onResponse)
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head(); const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
double ccRtt = clr ? clr->GetRtt() : grtt_measured; double ccRtt = clr ? clr->GetRtt() : grtt_measured;
double ccLoss = clr ? clr->GetLoss() : 0.0; double ccLoss = clr ? clr->GetLoss() : 0.0;
double oldRate = tx_rate; double txRate = tx_rate;
if (onResponse) if (onResponse)
{ {
// Adjust rate based on CLR feedback and // Adjust rate based on CLR feedback and
@ -2953,28 +3123,28 @@ void NormSession::AdjustRate(bool onResponse)
// (TBD) check feedback age // (TBD) check feedback age
if (cc_slow_start) if (cc_slow_start)
{ {
tx_rate = clr->GetRate(); txRate = clr->GetRate();
DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n", DMSG(6, "NormSession::AdjustRate(slow start) clr>%lu newRate>%lf (oldRate>%lf sentRate>%lf clrRate>%lf\n",
clr->GetId(), tx_rate*8.0/1000.0, oldRate*8.0/1000.0, sent_rate*8.0/1000.0, 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); clr->GetRate()*8.0/1000.0);
} }
else else
{ {
double clrRate = clr->GetRate(); double clrRate = clr->GetRate();
if (clrRate > tx_rate) if (clrRate > txRate)
{ {
double linRate = tx_rate + segment_size; double linRate = txRate + segment_size;
tx_rate = MIN(clrRate, linRate); txRate = MIN(clrRate, linRate);
} }
else else
{ {
tx_rate = clrRate; txRate = clrRate;
} }
DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n", DMSG(6, "NormSession::AdjustRate(stdy state) clr>%lu newRate>%lf (rtt>%lf loss>%lf)\n",
clr->GetId(), tx_rate*8.0/1000.0, clr->GetRtt(), clr->GetLoss()); clr->GetId(), txRate*8.0/1000.0, clr->GetRtt(), clr->GetLoss());
} }
} }
else if (clr) else if (clr && clr->IsActive())
{ {
// (TBD) fix CC feedback aging ... // (TBD) fix CC feedback aging ...
/*int feedbackAge = abs((int)cc_sequence - (int)clr->GetCCSequence()); /*int feedbackAge = abs((int)cc_sequence - (int)clr->GetCCSequence());
@ -2983,33 +3153,38 @@ void NormSession::AdjustRate(bool onResponse)
if (feedbackAge > 50) if (feedbackAge > 50)
{ {
double linRate = tx_rate - segment_size; double linRate = txRate - segment_size;
linRate = MAX(linRate, 0.0); linRate = MAX(linRate, 0.0);
double expRate = tx_rate * 0.5; double expRate = txRate * 0.5;
if (feedbackAge > 4) if (feedbackAge > 4)
tx_rate = MIN(linRate, expRate); txRate = MIN(linRate, expRate);
else else
tx_rate = MAX(linRate, expRate); txRate = MAX(linRate, expRate);
}*/ }*/
} }
else
{
// reduce rate if no active clr
txRate *= 0.5;
}
// Don't let tx_rate below MIN(one segment per grtt, one segment per second) // Don't let txRate below MIN(one segment per grtt, one segment per 4 seconds)
double minRate = ((double)segment_size) / grtt_measured; double minRate = ((double)segment_size) / grtt_measured;
minRate = MIN((double)segment_size, minRate); if (minRate > ((double)(segment_size >> 2)))
tx_rate = MAX(tx_rate, minRate); minRate = (double)(segment_size >> 2);
if (txRate < minRate)
txRate = minRate;
// Keep "tx_rate" within user set rate bounds (if any) // Keep "tx_rate" within user set rate bounds (if any)
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) if ((tx_rate_min >= 0.0) && (txRate < tx_rate_min))
tx_rate = tx_rate_min; txRate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max))
tx_rate = tx_rate_max; txRate = tx_rate_max;
struct timeval currentTime; if (txRate != tx_rate) SetTxRateInternal(txRate);
::ProtoSystemTime(currentTime);
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec); /*if (txRate != oldRate)
if (tx_rate != oldRate)
{ {
if (tx_timer.IsActive()) if (tx_timer.IsActive())
{ {
@ -3020,8 +3195,10 @@ void NormSession::AdjustRate(bool onResponse)
tx_timer.SetInterval(txInterval); tx_timer.SetInterval(txInterval);
tx_timer.Reschedule(); 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, tx_rate*(8.0/1000.0), ccRtt, ccLoss);
} // end NormSession::AdjustRate() } // end NormSession::AdjustRate()

View File

@ -11,6 +11,7 @@
class NormController class NormController
{ {
public: public:
virtual ~NormController() {}
enum Event enum Event
{ {
EVENT_INVALID = 0, EVENT_INVALID = 0,
@ -96,6 +97,7 @@ class NormSession
static const double DEFAULT_GSIZE_ESTIMATE; static const double DEFAULT_GSIZE_ESTIMATE;
static const UINT16 DEFAULT_NDATA; static const UINT16 DEFAULT_NDATA;
static const UINT16 DEFAULT_NPARITY; static const UINT16 DEFAULT_NPARITY;
enum ProbingMode {PROBE_NONE, PROBE_PASSIVE, PROBE_ACTIVE};
// General methods // General methods
const NormNodeId& LocalNodeId() const {return local_node_id;} const NormNodeId& LocalNodeId() const {return local_node_id;}
@ -118,6 +120,7 @@ class NormSession
return result; return result;
} }
void SetTxPort(UINT16 txPort) {tx_port = txPort;} void SetTxPort(UINT16 txPort) {tx_port = txPort;}
void SetRxPortReuse(bool state) {rx_port_reuse = state;}
static double CalculateRate(double size, double rtt, double loss); static double CalculateRate(double size, double rtt, double loss);
NormSessionMgr& GetSessionMgr() {return session_mgr;} NormSessionMgr& GetSessionMgr() {return session_mgr;}
@ -130,11 +133,23 @@ class NormSession
// Session parameters // Session parameters
double TxRate() {return (tx_rate * 8.0);} double TxRate() {return (tx_rate * 8.0);}
// (TBD) watch timer scheduling and min/max bounds // (TBD) watch timer scheduling and min/max bounds
void SetTxRate(double txRate); void SetTxRate(double txRate)
{
txRate /= 8.0; // convert to bytes/sec
SetTxRateInternal(txRate);
}
double BackoffFactor() {return backoff_factor;} double BackoffFactor() {return backoff_factor;}
void SetBackoffFactor(double value) {backoff_factor = value;} void SetBackoffFactor(double value) {backoff_factor = value;}
bool CongestionControl() {return cc_enable;} bool CongestionControl() {return cc_enable;}
void SetCongestionControl(bool state) {cc_enable = state;} void SetCongestionControl(bool state)
{
cc_enable = state;
}
// GRTT measurement management
void SetGrttProbingMode(ProbingMode probingMode);
void SetGrttProbingInterval(double intervalMin, double intervalMax);
void SetGrttMax(double grttMax) {grtt_max = grttMax;}
void SetTxRateBounds(double rateMin, double rateMax); void SetTxRateBounds(double rateMin, double rateMax);
void SetTxCacheBounds(NormObjectSize sizeMax, void SetTxCacheBounds(NormObjectSize sizeMax,
unsigned long countMin, unsigned long countMin,
@ -321,13 +336,15 @@ class NormSession
void ServerUpdateGrttEstimate(double clientRtt); void ServerUpdateGrttEstimate(double clientRtt);
double CalculateRtt(const struct timeval& currentTime, double CalculateRtt(const struct timeval& currentTime,
const struct timeval& grttResponse); const struct timeval& grttResponse);
void ServerHandleCCFeedback(NormNodeId nodeId, void ServerHandleCCFeedback(struct timeval currentTime,
UINT8 ccFlags, NormNodeId nodeId,
double ccRtt, UINT8 ccFlags,
double ccLoss, double ccRtt,
double ccRate, double ccLoss,
UINT16 ccSequence); double ccRate,
UINT16 ccSequence);
void AdjustRate(bool onResponse); void AdjustRate(bool onResponse);
void SetTxRateInternal(double txRate); // here, txRate is bytes/sec
bool ServerQueueSquelch(NormObjectId objectId); bool ServerQueueSquelch(NormObjectId objectId);
void ServerQueueFlush(); void ServerQueueFlush();
bool ServerQueueWatermarkFlush(); bool ServerQueueWatermarkFlush();
@ -359,6 +376,7 @@ class NormSession
ProtoAddress address; // session destination address & port ProtoAddress address; // session destination address & port
UINT8 ttl; // session multicast ttl UINT8 ttl; // session multicast ttl
bool loopback; // to receive own traffic bool loopback; // to receive own traffic
bool rx_port_reuse; // enable port reuse
char interface_name[32]; char interface_name[32];
double tx_rate; // bytes per second double tx_rate; // bytes per second
double tx_rate_min; double tx_rate_min;
@ -409,6 +427,7 @@ class NormSession
bool probe_proactive; bool probe_proactive;
bool probe_pending; // true while CMD(CC) enqueued bool probe_pending; // true while CMD(CC) enqueued
bool probe_reset; bool probe_reset;
struct timeval probe_time_last;
double grtt_interval; // current GRTT update interval double grtt_interval; // current GRTT update interval
double grtt_interval_min; // minimum GRTT update interval double grtt_interval_min; // minimum GRTT update interval

View File

@ -13,9 +13,10 @@
#ifdef UNIX #ifdef UNIX
#include <unistd.h> // for "sleep()" #include <unistd.h> // for "sleep()"
#endif // UNIX #endif // UNIX
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
printf("normTest starting (sizeof(NormSize) = %d)...\n", sizeof(NormSize)); printf("normTest starting (sizeof(NormSize) = %d)...\n", (int)sizeof(NormSize));
NormInstanceHandle instance = NormCreateInstance(); NormInstanceHandle instance = NormCreateInstance();
@ -26,27 +27,62 @@ int main(int argc, char* argv[])
#endif // if/else WIN32/UNIX #endif // if/else WIN32/UNIX
NormSetCacheDirectory(instance, cachePath); NormSetCacheDirectory(instance, cachePath);
// Here's a trick to generate a _hopefully_ unique NormNodeId
// based on an XOR of the system's IP address and the process id.
// (We use ProtoAddress::GetEndIdentifier() to get the local
// "default" IP address for the system)
// (Note that passing "NORM_NODE_ANY" to the last arg of
// NormCreateSession() does a similar thing but without
// the process id ... perhaps we should add the process id
// hack to that default NormNodeId picker?
ProtoAddress localAddr;
if (!localAddr.ResolveLocalAddress())
{
fprintf(stderr, "normTest: error resolving local IP address\n");
NormDestroyInstance(instance);
return -1;
}
NormNodeId localId = localAddr.EndIdentifier();
#ifdef WIN32
DWORD processId = GetCurrentProcessId();
#else
pid_t processId = getpid();
#endif // if/else WIN32/UNIX
localId ^= (NormNodeId)processId;
// If needed, permutate to a valid, random NormNodeId
while ((NORM_NODE_ANY == localId) ||
(NORM_NODE_NONE == localId))
{
localId ^= (NormNodeId)rand();
}
NormSessionHandle session = NormCreateSession(instance, NormSessionHandle session = NormCreateSession(instance,
"224.1.2.3", "224.1.2.3",
6003, 6003,
NORM_NODE_ANY); localId);
// NOTE: These are debugging routines available (not for normal app use) // NOTE: These are debugging routines available (not for normal app use)
SetDebugLevel(2); SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing // Uncomment to turn on debug NORM message tracing
//NormSetMessageTrace(session, true); //NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss // Uncomment to turn on some random packet loss
NormSetTxLoss(session, 10.0); // 10% packet loss //NormSetTxLoss(session, 10.0); // 10% packet loss
struct timeval currentTime; struct timeval currentTime;
ProtoSystemTime(currentTime); ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run // Uncomment to get different packet loss patterns from run to run
// (and a different sender sessionId) // (and a different sender sessionId)
srand(currentTime.tv_sec); // seed random number generator srand(currentTime.tv_sec); // seed random number generator
NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt //NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
NormSetTransmitRate(session, 60.0e+03); // in bits/second NormSetTransmitRate(session, 6000.0e+03); // in bits/second
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK); NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
@ -56,25 +92,32 @@ int main(int argc, char* argv[])
// possible! // possible!
//NormSetTxPort(session, 6001); //NormSetTxPort(session, 6001);
// Uncomment to allow reuse of rx port
// (This allows multiple "normTest" instances on the same machine
// for the same NormSession - note those instances must use
// unique local NormNodeIds (see NormCreateSession() above).
NormSetRxPortReuse(session, true);
// Uncomment to receive your own traffic // Uncomment to receive your own traffic
NormSetLoopback(session, true); NormSetLoopback(session, true);
// Uncomment this line to participate as a receiver // Uncomment this line to participate as a receiver
NormStartReceiver(session, 1024*1024); //NormStartReceiver(session, 1024*1024);
// Uncomment to set large rx socket buffer size // Uncomment to set large rx socket buffer size
// (might be needed for high rate sessions) // (might be needed for high rate sessions)
// NormSetRxSocketBuffer(session, 512000); NormSetRxSocketBuffer(session, 512000);
// Uncomment to enable TCP-friendly congestion control // Uncomment to enable TCP-friendly congestion control
//NormSetCongestionControl(session, true); NormSetCongestionControl(session, true);
// We use a random "sessionId" // We use a random "sessionId"
NormSessionId sessionId = (NormSessionId)rand(); NormSessionId sessionId = (NormSessionId)rand();
// Uncomment the following line to start sender // Uncomment the following line to start sender
NormStartSender(session, sessionId, 4096*1024, 1400, 64, 0); NormStartSender(session, sessionId, 1024*1024, 1420, 64, 0);
// Uncomment to set large tx socket buffer size // Uncomment to set large tx socket buffer size
// (might be needed for high rate sessions) // (might be needed for high rate sessions)
@ -87,7 +130,7 @@ int main(int argc, char* argv[])
const char* fileName = "ferrari.jpg"; const char* fileName = "ferrari.jpg";
// Uncomment this line to send a stream instead of the file // Uncomment this line to send a stream instead of the file
//stream = NormStreamOpen(session, 4096*1024); stream = NormStreamOpen(session, 10*1024*1024);
// NORM_FLUSH_PASSIVE automatically flushes full writes to // NORM_FLUSH_PASSIVE automatically flushes full writes to
// the stream. // the stream.
@ -115,7 +158,7 @@ int main(int argc, char* argv[])
// TRACE("NORM_TX_QUEUE_VACANCY ...\n"); // TRACE("NORM_TX_QUEUE_VACANCY ...\n");
case NORM_TX_QUEUE_EMPTY: case NORM_TX_QUEUE_EMPTY:
//TRACE("NORM_TX_QUEUE_EMPTY ...\n"); //TRACE("NORM_TX_QUEUE_EMPTY ...\n");
if (sendCount >= sendMax) break; //if (sendCount >= sendMax) break;
if (NORM_OBJECT_INVALID != stream) if (NORM_OBJECT_INVALID != stream)
{ {
// We loop here to keep stream buffer full .... // We loop here to keep stream buffer full ....
@ -150,7 +193,7 @@ int main(int argc, char* argv[])
// after "sendMax" messages // after "sendMax" messages
//NormStreamClose(stream, true); //NormStreamClose(stream, true);
//keepWriting = false; //keepWriting = false;
} }
} }
} }
} }
@ -251,6 +294,8 @@ int main(int argc, char* argv[])
// TRACE("validated recv msg len:%d\n", len); // TRACE("validated recv msg len:%d\n", len);
} }
recvCount = value; recvCount = value;
//if (0 == msgCount % 100)
// TRACE("recv stream msg count: %d\n", msgCount);
} }
else else
{ {

View File

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

View File

@ -13,7 +13,7 @@ NS = ../ns
INCLUDES = $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common INCLUDES = $(SYSTEM_INCLUDES) -I$(UNIX) -I$(COMMON) -I$(PROTOLIB)/common
CFLAGS = -g -DPROTO_DEBUG -DUNIX -D_FILE_OFFSET_BITS=64 -O -fPIC -Wall -pedantic -Wcast-align $(SYSTEM_HAVES) $(INCLUDES) CFLAGS = -g -DPROTO_DEBUG -DUNIX -D_FILE_OFFSET_BITS=64 -O $(SYSTEM_CFLAGS) $(SYSTEM_HAVES) $(INCLUDES)
LDFLAGS = $(SYSTEM_LDFLAGS) LDFLAGS = $(SYSTEM_LDFLAGS)
@ -44,12 +44,14 @@ NORM_OBJ = $(NORM_SRC:.cpp=.o)
LIB_SRC = $(NORM_SRC) LIB_SRC = $(NORM_SRC)
LIB_OBJ = $(LIB_SRC:.cpp=.o) LIB_OBJ = $(LIB_SRC:.cpp=.o)
# NORM as a static library
libnorm.a: $(LIB_OBJ) libnorm.a: $(LIB_OBJ)
$(AR) rcv $@ $(LIB_OBJ) $(AR) rcv $@ $(LIB_OBJ)
$(RANLIB) $@ $(RANLIB) $@
.cpp-sim.o: # NORM as a shared library
$(CC) -c $(CFLAGS) -DSIMULATE -o $*-sim.o $*.cpp libnorm.so: $(LIB_OBJ)
$(CC) $(SYSTEM_SOFLAGS) $(LIB_OBJ) $(LIBS) -o $@
SIM_SRC = $(NORM_SRC) $(COMMON)/normSimAgent.cpp SIM_SRC = $(NORM_SRC) $(COMMON)/normSimAgent.cpp
SIM_OBJ = $(SIM_SRC:.cpp=-sim.o) SIM_OBJ = $(SIM_SRC:.cpp=-sim.o)
@ -82,7 +84,8 @@ raft: $(RAFT_OBJ) $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(RAFT_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS) $(CC) $(CFLAGS) -o $@ $(RAFT_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS)
clean: clean:
rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/libnorm.a $(UNIX)/norm $(NS)/*.o; rm -f $(COMMON)/*.o $(UNIX)/*.o $(UNIX)/libnorm.a \
$(UNIX)/libnorm.so $(UNIX)/norm $(NS)/*.o;
cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) clean cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) clean
# DO NOT DELETE THIS LINE -- mkdep uses it. # DO NOT DELETE THIS LINE -- mkdep uses it.

View File

@ -25,10 +25,6 @@ SYSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The PROTOLIB code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -41,10 +37,12 @@ SYSTEM_LIBS =
SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
SYSTEM_SRC = bsdRouteMgr.cpp SYSTEM_SRC =
SYSTEM = freebsd SYSTEM = freebsd
CC = gcc CC = gcc
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = ranlib RANLIB = ranlib
AR = ar AR = ar

View File

@ -1,35 +1,13 @@
# #
# HPUX Protean Makefile definitions # HPUX Protean Makefile definitions
# # (This file is likely out of date)
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
# ITEMS AS NEEDED FOR YOUR SYSTEM
# (This has only been tested with TCL/TK 8.0 but it probably
# will work with Tcl7.x/Tk4.x with a little tweaking to
# the list of TCL_SCRIPTS (library scripts) given below)
# 1) Where to find the Tcl standard library scripts # System specific additional libraries, include paths, etc
# (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /opt/tcl-8.0/lib
# 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /opt/tk-8.0/lib/X11
# 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/opt/tcl-8.0/include -I/opt/tk-8.0/include/X11
# 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = ./hpux-libtcl8.0.a
TK_LIB = ./hpux-libtk8.0.a
# 5) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc) # (Where to find X11 libraries, etc)
# #
SYSTEM_INCLUDES = SYSTEM_INCLUDES =
SYSTEM_LDFLAGS = -Xlinker +b -Xlinker /usr/lib/X11R5:/usr/lib/X11R6:/usr/local/X11R5/lib:/usr/local/X11R6/lib:/usr/lib:/usr/lib/X11R4\ SYSTEM_LDFLAGS =
-Xlinker +s -L/home/macker/mdp/X11R5/lib
SYTSTEM_LIBS = SYTSTEM_LIBS =
# 6) System specific capabilities # 6) System specific capabilities
@ -48,10 +26,6 @@ SYTSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -62,10 +36,12 @@ SYTSTEM_LIBS =
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
export CC = gcc CC = gcc
export RANLIB = touch SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export AR = ar SYSTEM_SOFLAGS = -shared
RANLIB = touch
AR = ar
include Makefile.common include Makefile.common

View File

@ -1,30 +1,7 @@
# #
# Linux Protean Makefile definitions # Linux NORM Makefile definitions
# #
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
# ITEMS AS NEEDED FOR YOUR SYSTEM
# (This has only been tested with TCL/TK 8.0 but it probably
# will work with Tcl7.x/Tk4.x with a little tweaking to
# the list of TCL_SCRIPTS (library scripts) given below)
# 1) Where to find the Tcl standard library scripts
# (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /usr/lib/tcl
# 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /usr/lib/tk
# 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/usr/local/include
# 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = -ltcl #/usr/local/lib/libtcl8.0.a
TK_LIB = -ltk #/usr/local/lib/libtk8.0.a
# 5) System specific additional libraries, include paths, etc # 5) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc) # (Where to find X11 libraries, etc)
# #
@ -48,10 +25,6 @@ SYSTEM_LIBS = -ldl
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -70,6 +43,8 @@ SYSTEM_SRC =
SYSTEM = linux SYSTEM = linux
export CC = g++ export CC = g++
export SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export SYSTEM_SOFLAGS = -shared
export RANLIB = ranlib export RANLIB = ranlib
export AR = ar export AR = ar

View File

@ -37,14 +37,16 @@ SYSTEM_LIBS = -lresolv
# #
SYSTEM_HAVES = -DMACOSX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK \ SYSTEM_HAVES = -DMACOSX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK \
-D_FILE_OFFSET_BITS=64 -DHAVE_DIRFD -DSOCKLEN_T=int -D_FILE_OFFSET_BITS=64 -DHAVE_DIRFD
SYSTEM_SRC = bsdRouteMgr.cpp SYSTEM_SRC =
# The "SYSTEM" keyword can be used for dependent makes # The "SYSTEM" keyword can be used for dependent makes
SYSTEM = macosx SYSTEM = macosx
CC = g++ CC = g++
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = ranlib RANLIB = ranlib
AR = ar AR = ar

View File

@ -1,29 +1,7 @@
# #
# MDPv2 NetBSD Makefile # NORM mklinux Makefile
# #
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
# ITEMS AS NEEDED FOR YOUR SYSTEM
# (This has only been tested with TCL/TK 8.0 but it probably
# will work with Tcl7.x/Tk4.x with a little tweaking to
# the list of TCL_SCRIPTS (library scripts) given below)
# 1) Where to find the Tcl standard library scripts
# (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
# 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
# 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/usr/local/include
# 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = /usr/local/lib/libtcl8.0.a
TK_LIB = /usr/local/lib/libtk8.0.a
# 5) System specific additional libraries, include paths, etc # 5) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc) # (Where to find X11 libraries, etc)
@ -49,10 +27,6 @@ SYSTEM_LIBS = -ldl
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -66,6 +40,8 @@ SYSTEM_LIBS = -ldl
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC) export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF -DHAVE_DIRFD $(NETSEC)
export CC = gcc export CC = gcc
export SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export SYSTEM_SOFLAGS = -shared
export RANLIB = ranlib export RANLIB = ranlib
export AR = ar export AR = ar

View File

@ -1,30 +1,7 @@
# #
# MDPv2 NetBSD Makefile # NORM NetBSD Makefile
# #
# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED
# ITEMS AS NEEDED FOR YOUR SYSTEM
# (This has only been tested with TCL/TK 8.0 but it probably
# will work with Tcl7.x/Tk4.x with a little tweaking to
# the list of TCL_SCRIPTS (library scripts) given below)
# 1) Where to find the Tcl standard library scripts
# (e.g. init.tcl, ...)
TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0
# 2) Where to find the Tk standard library scripts
# (e.g. button.tcl, entry.tcl, ...)
TK_SCRIPT_PATH = /usr/local/lib/tk8.0
# 3) Where to find Tcl/Tk header files
# (e.g. tcl.h, tk.h, ...)
TCL_INCL_PATH = -I/usr/local/include
# 4) Point to specific libtcl.a and libtk.a to use
TCL_LIB = /usr/local/lib/libtcl80.a
TK_LIB = /usr/local/lib/libtk80.a
# 5) System specific additional libraries, include paths, etc # 5) System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc) # (Where to find X11 libraries, etc)
# #
@ -48,10 +25,6 @@ SYSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -62,10 +35,12 @@ SYSTEM_LIBS =
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_ASSERT -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_ASSERT -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC)
export CC = gcc CC = gcc
export RANLIB = ranlib SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export AR = ar SYSTEM_SOFLAGS = -shared
RANLIB = ranlib
AR = ar
include Makefile.common include Makefile.common

View File

@ -26,10 +26,6 @@ SYSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# routine. # routine.
# #
# E) The MDP code's use of offset pointers requires special treatment
# for some different compilers. Set -DUSE_INHERITANCE for some
# to keep some compilers (gcc 2.7.2) happy.
#
# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require # F) Some systems (SOLARIS/SUNOS) have a few gotchas which require
# some #ifdefs to avoid compiler warnings ... so you might need # some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS. # to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -46,7 +42,15 @@ SYSTEM_SRC =
SYSTEM = sgi SYSTEM = sgi
# g++
#CC = g++
#SYSTEM_CFLAGS = -Wall -Wcast-align -pedantic -fPIC
# SGI CC
CC = CC CC = CC
SYSTEM_CFLAGS = -KPIC -pedantic
SYSTEM_SOFLAGS = -shared
RANLIB = touch RANLIB = touch
AR = ar AR = ar

View File

@ -35,15 +35,16 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF \ SYSTEM_HAVES = -DHAVE_DIRFD -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DSOLARIS -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DSOLARIS
SYSTEM = solaris SYSTEM = solaris
CC = g++ CC = CC
# -xarch=v9 makes the output run only on 64-bit Solaris
SYSTEM_CFLAGS = -KPIC -Wall -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = touch RANLIB = touch
AR = ar AR = ar
include Makefile.common include Makefile.common

View File

@ -60,11 +60,16 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
# (We export these for other Makefiles as needed) # (We export these for other Makefiles as needed)
# #
export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS SYSTEM_HAVES = -DHAVE_DIRFD -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF \
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DSOLARIS
export CC = gcc SYSTEM = solaris
export RANLIB = touch
export AR = ar SYSTEM_CFLAGS = -PIC -Wall -Wcast-align
CC = gcc
SYSTEM_SOFLAGS = -shared
RANLIB = touch
AR = ar
include Makefile.common include Makefile.common

Binary file not shown.

View File

@ -26,6 +26,7 @@
PreprocessorDefinitions="_DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_CONSOLE" PreprocessorDefinitions="_DEBUG;PROTO_DEBUG;HAVE_IPV6;HAVE_ASSERT;WIN32;_CONSOLE"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
UsePrecompiledHeader="2" UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Debug/normTest.pch" PrecompiledHeaderFile=".\Debug/normTest.pch"
AssemblerListingLocation=".\Debug/" AssemblerListingLocation=".\Debug/"
@ -41,7 +42,7 @@
Name="VCLinkerTool" Name="VCLinkerTool"
AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib" AdditionalDependencies="iphlpapi.lib ws2_32.lib odbc32.lib odbccp32.lib"
OutputFile=".\Debug/normTest.exe" OutputFile=".\Debug/normTest.exe"
LinkIncremental="1" LinkIncremental="0"
SuppressStartupBanner="TRUE" SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE" GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/normTest.pdb" ProgramDatabaseFile=".\Debug/normTest.pdb"

Binary file not shown.