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">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-15">
<TITLE>NORM Developer&rsquo;s Guide</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)">
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<TITLE>NORM Developers Guide</TITLE>
<META NAME="GENERATOR" CONTENT="NeoOffice/J 1.1 (Unix)">
<META NAME="AUTHOR" CONTENT="Robert Adamson">
<META NAME="CREATED" CONTENT="20040824;15180000">
<META NAME="CHANGED" CONTENT="20050621;14191600">
<META NAME="CREATED" CONTENT="20040824;14180000">
<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="KEYWORDS" CONTENT="norm object value application function ">
<STYLE>
@ -51,7 +51,7 @@
</TD>
<TD WIDTH=371>
<P ALIGN=LEFT STYLE="margin-left: 0.86in; margin-top: 0.17in; font-style: normal">
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=6 STYLE="font-size: 28pt"><B>NORM<BR>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>
</TD>
</TR>
@ -99,8 +99,6 @@ communication needs.</P>
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table
of Contents</H1>
<DIV ID="Table of Contents1" DIR="LTR">
<P STYLE="margin-top: 0.25in; font-style: normal"><BR>
</P>
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Overview</B></FONT></P>
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
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="#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="#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
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>
@ -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="#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="#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="#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>
@ -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="#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="#NormSetGrttMax()">NormSetGrttMax()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingMode()">NormSetGrttProbingMode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSetGrttProbingInterval()">NormSetGrttProbingInterval()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormAddAckingNode()">NormAddAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormRemoveAckingNode()">NormRemoveAckingNode()</A></FONT></P>
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormFileEnqueue()">NormFileEnqueue()</A></FONT></P>
@ -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
use NORM in an application. The first step is to create and
initialize, as needed, at least one instance of the NORM API. Then
one or more NORM transport sessions (where a &ldquo;session&rdquo;
one or more NORM transport sessions (where a “session”
corresponds to data exchanges on a given multicast group and host
port number) may be created and controlled. Applications may
participate as senders and/or receivers within a NORM session. NORM
@ -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
represent predetermined, fixed-size application data content. The
only differentiation with respect to these two types is the implicit
&ldquo;hint&rdquo; to the receiver to use non-volatile (i.e. file
system) storage or memory. This &ldquo;hint&rdquo; lets the receiver
allocate appropriate storage space with no other information on the
incoming data. The NORM implementation reads/writes data for the
“hint” to the receiver to use non-volatile (i.e. file system)
storage or memory. This “hint” lets the receiver allocate
appropriate storage space with no other information on the incoming
data. The NORM implementation reads/writes data for the
<FONT FACE="Courier"><I>NORM_OBJECT_FILE</I></FONT> type directly
from/to file storage, while application memory space is accessed for
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
be provided. Additionally, NORM has provisions for
application-defined message-oriented transport where receivers can
recover message boundaries without any &ldquo;handshake&rdquo; with
the sender. Stream content is buffered by the NORM implementation
for transmission/retransmission and as it is received.</P>
recover message boundaries without any “handshake” with the
sender. Stream content is buffered by the NORM implementation for
transmission/retransmission and as it is received.</P>
<H3 CLASS="western">NORM Data Transmission</H3>
<P CLASS="western" STYLE="font-style: normal">The behavior of data
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
message headers.</P>
<P CLASS="western" STYLE="font-style: normal">NORM transport
&ldquo;objects&rdquo; (file, data, or stream) are queued for
transmission by NORM senders. NORM senders may also cancel
transmission of objects at any time. The NORM sender controls the
transmission rate either manually (fixed transmission rate) or
automatically when NORM congestion control operation is enabled. The
NORM congestion control mechanism is designed to be &quot;friendly&quot;
to other data flows on the network, fairly sharing available
bandwidth.</P>
“objects” (file, data, or stream) are queued for transmission by
NORM senders. NORM senders may also cancel transmission of objects
at any time. The NORM sender controls the transmission rate either
manually (fixed transmission rate) or automatically when NORM
congestion control operation is enabled. The NORM congestion control
mechanism is designed to be &quot;friendly&quot; to other data flows
on the network, fairly sharing available bandwidth.</P>
<P CLASS="western" STYLE="font-style: normal">By default, the NORM
sender transmits application-enqueued data content, providing repair
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
requires the addition of the &quot;-lresolv&quot; (resolver) library
and Solaris requires the dynamic loader, network/socket, and resolver
libraries (&quot;&ndash;lnsl &ndash;lsocket &ndash;lresolv&quot;) to
achieve successful compilation. The Makefiles in the NORM source
code distribution are a reference for these requirements. Note that
MacOS 9 and earlier are not supported.</P>
libraries (&quot;lnsl lsocket lresolv&quot;) to achieve
successful compilation. The Makefiles in the NORM source code
distribution are a reference for these requirements. Note that MacOS
9 and earlier are not supported.</P>
<P CLASS="western" STYLE="font-style: normal">Additionally, it is
critical that the _FILE_OFFSET_BITS macro be consistently defined for
the NORM library build and the application build using the library.
The distributed NORM Makefiles have &ndash;D_FILE_OFFSET_BITS=64 set
in the compilation to enable &quot;large file support&quot;.
The distributed NORM Makefiles have D_FILE_OFFSET_BITS=64 set in
the compilation to enable &quot;large file support&quot;.
Applications built using NORM should have the same compilation option
set to operate correctly (The definition of the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
type in &quot;normApi.h&quot; depends upon this compilation flag).</P>
@ -583,10 +588,10 @@ session as part of protocol operation. Typically, the application
should not need access to these values, but an API call
<FONT FACE="Courier">NormObjectGetTransportId() </FONT>is provided to
retrieve these values if needed. (<I>Note this type may be
deprecated &ndash; it may not be needed at all if the
NormObjectRequeue() function (TBD) is implemented using handles only,
but _some_ applications requiring persistence even after a system
reboot may need the ability to recall previous transport ids?</I>)</P>
deprecated it may not be needed at all if the NormObjectRequeue()
function (TBD) is implemented using handles only, but _some_
applications requiring persistence even after a system reboot may
need the ability to recall previous transport ids?</I>)</P>
<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>
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>
description).
</P>
<H3 CLASS="functionheading-western"><A NAME="NormFlushMode">NormFlushMode</A></H3>
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormFlushMode">NormFlushMode</A></FONT>
consist of the following enumeration:</P>
<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>
<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
@ -1220,9 +1260,57 @@ reception. However, the use of separate transmit/receive ports
allows NORM to discriminate when unicast feedback is occurring and
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>
receive port. 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> to succeed.</P>
receive port.
</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>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
@ -1462,7 +1550,7 @@ function call include:</P>
The maximum <FONT FACE="Courier"><U>blockSize</U></FONT> allowed
by the 8-bit Reed-Solomon codes in NORM is 255, with the further
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>
</TR>
<TR VALIGN=TOP>
@ -1483,15 +1571,14 @@ function call include:</P>
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>,
the maximum <FONT FACE="Courier"><U>numParity</U></FONT> value is
(255 &ndash; <FONT FACE="Courier"><U>blockSize</U></FONT>).
However, note that computational complexity increases
significantly with increasing <FONT FACE="Courier"><U>numParity</U></FONT>
values and applications may wish to be conservative with respect
to <FONT FACE="Courier"><U>numParity</U></FONT> selection, given
anticipated network packet loss conditions and group size
scalability concerns. Additional FEC code options may be provided
for this NORM implementation in the future with different
parameters, capabilities, trade-offs, and computational
(255 <FONT FACE="Courier"><U>blockSize</U></FONT>). However,
note that computational complexity increases significantly with
increasing <FONT FACE="Courier"><U>numParity</U></FONT> values and
applications may wish to be conservative with respect to <FONT FACE="Courier"><U>numParity</U></FONT>
selection, given anticipated network packet loss conditions and
group size scalability concerns. Additional FEC code options may
be provided for this NORM implementation in the future with
different parameters, capabilities, trade-offs, and computational
requirements.</P>
</TD>
</TR>
@ -1516,7 +1603,7 @@ implementation.</P>
is returned upon success and <FONT FACE="Courier"><I>false</I></FONT>
upon failure. The reasons failure may occur include limited system
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>
function to retrieve a more specific error indication for this and
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>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function sets the
sender's estimate of group round-trip timing (GRTT). This function
is expected to most typically used to initialize the sender's GRTT
sender's estimate of group round-trip timing (GRTT) for the given
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>
when the application has <I>a priori</I> confidence that the default
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
sender GRTT update process (see <FONT FACE="Courier">NormSetGrttProbing()</FONT>).
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.
</P>
<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
potentially requiring more buffer space to maintain reliability). An
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>
<P CLASS="western" STYLE="font-style: normal">This function has no
return values.</P>
@ -2057,7 +2263,7 @@ limit.</P>
<H4 CLASS="western">Synopsis</H4>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>bool
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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
= 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
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
= 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>
<H4 CLASS="western">Description</H4>
<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
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"><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
write position in an even more proactive fashion. In this case, the
sender additionally, <I>actively</I> transmits NORM_CMD(FLUSH)
@ -2193,7 +2399,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<P CLASS="western" STYLE="font-style: normal">This function sets
&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
<FONT FACE="Courier"><I>true</I></FONT> upon successful establishment
of the watermark point. The function may return <FONT FACE="Courier"><I>false</I></FONT>
upon failure (<I>why would it fail? &ndash; TBD</I>).</P>
upon failure (<I>why would it fail? TBD</I>).</P>
<H2 CLASS="western">NORM Receiver Functions</H2>
<H3 CLASS="functionheading-western"><A NAME="NormStartReceiver()">NormStartReceiver()</A></H3>
<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
satisfy sender watermark acknowledgement requests (see
<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
unicast NACKing can be overridden via the <FONT FACE="Courier"><A HREF="#NormNodeSetUnicastNack()">NormNodeSetUnicastNack()</A></FONT>
function for individual remote senders.</P>
@ -2583,7 +2789,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<P CLASS="western" STYLE="font-style: normal">This function sets the
default &quot;nacking mode&quot; used when receiving objects. This
@ -2650,7 +2856,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<H4 CLASS="western">Description</H4>
<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>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<P CLASS="western" STYLE="font-style: normal">This function sets the
&quot;nacking mode&quot; used for receiving a specific transport
@ -2689,7 +2895,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<H4 CLASS="western">Description</H4>
<P CLASS="western" STYLE="font-style: normal">This function allows
@ -2723,7 +2929,7 @@ return values.</P>
&lt;normApi.h&gt;</FONT></FONT></P>
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>void
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>
<H4 CLASS="western">Description</H4>
<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)
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"
(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
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
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
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:
============
@ -92,6 +105,8 @@ NormDeveloperGuide.html - HTML version of NORM Developer's Guide
(nice for browsing)
NormUserGuide.pdf - Guide to "norm" demo app usage
(this document needs corrections and
is currently incomplete)
VERSION.TXT - NORM version history notes

View File

@ -1,5 +1,51 @@
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
=============
- Added NormSetTxCacheBounds(), see NormDevGuide for details
@ -118,3 +164,7 @@ Version 1.1b3
- Started keeping version history. This release includes
some bug fixes, smoother congestion control operation, etc
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);
break;
case NORM_TX_QUEUE_VACANCY:
if (NULL != n->event.object)
static_cast<NormStreamObject*>((NormObject*)n->event.object)->ResetPostedTxQueueVacancy();
//if (NULL != n->event.object)
// static_cast<NormStreamObject*>((NormObject*)n->event.object)->ResetPostedTxQueueVacancy();
// (TBD) support session-level queue vacancy notify
break;
default:
@ -764,6 +764,21 @@ void NormSetTxPort(NormSessionHandle sessionHandle,
}
} // 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,
const char* interfaceName)
{
@ -971,6 +986,46 @@ void NormSetGrttEstimate(NormSessionHandle sessionHandle,
}
} // 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,
NormNodeId nodeId)
{
@ -1021,8 +1076,8 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle,
const char* dataPtr,
unsigned long dataLen,
const char* infoPtr = NULL,
unsigned int infoLen = 0)
const char* infoPtr,
unsigned int infoLen)
{
NormObjectHandle objectHandle = NORM_OBJECT_INVALID;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
@ -1460,7 +1515,7 @@ bool NormFileGetName(NormObjectHandle fileHandle,
static_cast<NormFileObject*>((NormObject*)fileHandle);
bufferLen = (bufferLen < PATH_MAX) ? bufferLen : PATH_MAX;
strncpy(nameBuffer, file->GetPath(), bufferLen);
nameBuffer[bufferLen=1] = '\0';
nameBuffer[bufferLen] = '\0';
result = true;
}
return result;

View File

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

View File

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

View File

@ -397,8 +397,8 @@ NormFile::Offset NormFile::GetSize() const
return ((Offset)fileSize);
#else
#ifdef WIN32
struct _stat info;
int result = _fstat(fd, &info);
struct __stat64 info; // instead of "struct _stat"
int result = _fstat64(fd, &info); // instead of "_fstat()"
#else
struct stat info;
int result = fstat(fd, &info);
@ -811,8 +811,8 @@ NormFile::Offset NormFile::GetSize(const char* path)
}
#else
#ifdef WIN32
struct _stat info;
int result = _stat(path, &info);
struct __stat64 info; // instead of "struct _stat"
int result = _stat64(path, &info); // instead of "_stat()"
#else
struct stat info;
int result = stat(path, &info);
@ -863,8 +863,8 @@ time_t NormFile::GetUpdateTime(const char* path)
}
#else
#ifdef WIN32
struct _stat info;
int result = _stat(path, &info);
struct __stat64 info; // instead of "struct _stat"
int result = _stat64(path, &info); // instead of "_stat()"
#else
struct stat info;
int result = stat(path, &info);
@ -877,9 +877,9 @@ time_t NormFile::GetUpdateTime(const char* path)
{
#ifdef WIN32
// 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);
return updateTime;
return ((time_t)updateTime);
#else
return info.st_ctime;
#endif // if/else WIN32

View File

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

View File

@ -3,7 +3,7 @@
#include "normSession.h"
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)
{
@ -323,7 +323,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime,
if (obj && (NormObject::STREAM == obj->GetType()))
{
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
// (although they will eventually get discarded anyway)
@ -614,7 +614,7 @@ void NormServerNode::HandleRepairContent(const UINT32* buffer, UINT16 bufferLen)
NormRepairRequest req;
UINT16 requestLength = 0;
bool freshObject = true;
NormObjectId prevObjectId;
NormObjectId prevObjectId(0);
NormObject* object = NULL;
bool freshBlock = true;
NormBlockId prevBlockId = 0;
@ -1005,10 +1005,9 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
}
}
if (obj)
if (NULL != obj)
{
rx_table.Insert(obj);
obj->Retain();
NormFtiExtension fti;
while (msg.GetNextExtension(fti))
{
@ -1458,7 +1457,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
if (is_clr)
ext.SetCCFlag(NormCC::CLR);
else if (is_plr)
ext.SetCCFlag(NormCC::CLR);
ext.SetCCFlag(NormCC::PLR);
if (rtt_confirmed)
ext.SetCCFlag(NormCC::RTT);
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)
{
recv_accumulator += msgSize;
double interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec);
if (currentTime.tv_usec > prev_update_time.tv_sec)
interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec);
else
interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec);
double 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
// 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;
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)
{
recv_rate = ((double)(recv_accumulator)) / interval;
prev_update_time = currentTime;
recv_accumulator = 0;
}
}*/
//TRACE("updated recv rate to %lf (accum:%lu) (cc_rate:%lf)\n", recv_rate,
// recv_accumulator, cc_rate);
}
else
{
@ -1956,6 +1991,7 @@ NormNode *NormNodeTree::FindNodeById(NormNodeId nodeId) const
void NormNodeTree::AttachNode(NormNode *node)
{
ASSERT(node);
node->Retain();
node->left = NULL;
node->right = NULL;
NormNode *x = root;
@ -1995,6 +2031,7 @@ void NormNodeTree::AttachNode(NormNode *node)
void NormNodeTree::DetachNode(NormNode* node)
{
ASSERT(node);
node->Release();
NormNode* x;
NormNode* y;
if (!node->left || !node->right)
@ -2056,7 +2093,7 @@ void NormNodeTree::Destroy()
while ((n = root))
{
DetachNode(n);
delete n;
n->Release();
}
} // end NormNodeTree::Destroy()
@ -2141,6 +2178,7 @@ NormNode* NormNodeList::FindNodeById(NormNodeId nodeId) const
void NormNodeList::Append(NormNode *theNode)
{
ASSERT(theNode);
theNode->Retain();
theNode->left = tail;
if (tail)
tail->right = theNode;
@ -2154,6 +2192,7 @@ void NormNodeList::Append(NormNode *theNode)
void NormNodeList::Remove(NormNode *theNode)
{
ASSERT(theNode);
theNode->Release();
if (theNode->right)
theNode->right->left = theNode->left;
else
@ -2171,7 +2210,7 @@ void NormNodeList::Destroy()
while ((n = head))
{
Remove(n);
delete n;
n->Release();
}
} // end NormNodeList::Destroy()

View File

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

View File

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

View File

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

View File

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

View File

@ -147,7 +147,7 @@ class NormBlock
pending_mask.SetBits(0, ndata+nparity);
repair_mask.Clear();
erasure_count = ndata;
parity_count = 0;
parity_count = 0;
parity_offset = 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_GRTT_INTERVAL_MIN = 1.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 unsigned int NormSession::DEFAULT_GRTT_DECREASE_DELAY = 3;
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),
tx_socket(&tx_socket_actual), tx_socket_actual(ProtoSocket::UDP),
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),
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0),
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
@ -28,7 +28,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
posted_tx_queue_empty(false),
acking_node_count(0), watermark_pending(false), advertise_repairs(false),
suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0),
probe_proactive(true), probe_pending(false), probe_reset(false),
probe_proactive(true), probe_pending(false), probe_reset(true),
grtt_interval(0.5),
grtt_interval_min(DEFAULT_GRTT_INTERVAL_MIN),
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.SetInterval(0.0);
probe_timer.SetRepeat(-1);
probe_time_last.tv_sec = probe_time_last.tv_usec = 0;
grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE);
grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized);
@ -107,12 +108,33 @@ bool NormSession::Open(const char* interfaceName)
}
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");
Close();
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())
@ -198,11 +220,13 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
{
if (interfaceName)
{
bool result = true;
if (rx_socket.IsOpen())
result &= rx_socket.SetMulticastInterface(interfaceName);
if (tx_socket->IsOpen())
result &= tx_socket->SetMulticastInterface(interfaceName);
strncpy(interface_name, interfaceName, 32);
return result;
}
else
@ -212,9 +236,8 @@ bool NormSession::SetMulticastInterface(const char* interfaceName)
}
} // end NormSession::SetMulticastInterface()
void NormSession::SetTxRate(double txRate)
void NormSession::SetTxRateInternal(double txRate)
{
txRate /= 8.0; // convert to bytes/sec
if (tx_timer.IsActive())
{
tx_timer.Deactivate();
@ -236,7 +259,19 @@ void NormSession::SetTxRate(double 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)
{
@ -264,7 +299,7 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
tx_rate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max;
SetTxRate(tx_rate*8.0);
SetTxRateInternal(tx_rate);
}
} // end NormSession::SetTxRateBounds()
@ -348,8 +383,6 @@ bool NormSession::StartServer(UINT16 instanceId,
nparity = numParity;
is_server = true;
flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor
//probe_timer.SetInterval(0.0);
probe_pending = probe_reset = false;
if (cc_enable)
{
@ -359,16 +392,25 @@ bool NormSession::StartServer(UINT16 instanceId,
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max;
}
OnProbeTimeout(probe_timer);
ActivateTimer(probe_timer);
grtt_age = 0.0;
probe_pending = false;
if (probe_reset)
{
probe_reset = false;
OnProbeTimeout(probe_timer);
ActivateTimer(probe_timer);
}
return true;
} // end NormSession::StartServer()
void NormSession::StopServer()
{
if (probe_timer.IsActive()) probe_timer.Deactivate();
if (probe_timer.IsActive())
{
probe_timer.Deactivate();
probe_reset = true;
}
encoder.Destroy();
acking_node_tree.Destroy();
cc_node_list.Destroy();
@ -685,7 +727,6 @@ void NormSession::ServerRemoveAckingNode(NormNodeId nodeId)
if (watermark_pending && theNode->AckReceived())
acks_collected--;
acking_node_tree.DetachNode(theNode);
delete theNode;
acking_node_count--;
}
} // end NormSession::RemoveAckingNode()
@ -863,7 +904,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
if (!file->Open(path, infoPtr, infoLen))
{
DMSG(0, "NormSession::QueueTxFile() file open error\n");
delete file;
file->Release();
return NULL;
}
if (QueueTxObject(file))
@ -873,7 +914,7 @@ NormFileObject* NormSession::QueueTxFile(const char* path,
else
{
file->Close();
delete file;
file->Release();
return NULL;
}
} // end NormSession::QueueTxFile()
@ -898,7 +939,7 @@ NormDataObject* NormSession::QueueTxData(const char* dataPtr,
if (!obj->Open((char*)dataPtr, dataLen, false, infoPtr, infoLen))
{
DMSG(0, "NormSession::QueueTxData() object open error\n");
delete obj;
obj->Release();
return NULL;
}
if (QueueTxObject(obj))
@ -908,7 +949,7 @@ NormDataObject* NormSession::QueueTxData(const char* dataPtr,
else
{
obj->Close();
delete obj;
obj->Release();
return NULL;
}
} // end NormSession::QueueTxData()
@ -934,7 +975,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
if (!stream->Open(bufferSize, doubleBuffer, infoPtr, infoLen))
{
DMSG(0, "NormSession::QueueTxStream() stream open error\n");
delete stream;
stream->Release();
return NULL;
}
if (QueueTxObject(stream))
@ -946,7 +987,7 @@ NormStreamObject* NormSession::QueueTxStream(UINT32 bufferSize,
else
{
stream->Close();
delete stream;
stream->Release();
return NULL;
}
} // end NormSession::QueueTxStream()
@ -970,7 +1011,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
if (!simObject->Open(objectSize))
{
DMSG(0, "NormSession::QueueTxSim() open error\n");
delete simObject;
simObject->Release();
return NULL;
}
if (QueueTxObject(simObject))
@ -979,7 +1020,7 @@ NormSimObject* NormSession::QueueTxSim(unsigned long objectSize)
}
else
{
delete simObject;
simObject->Release();
return NULL;
}
} // end NormSession::QueueTxSim()
@ -1024,7 +1065,6 @@ bool NormSession::QueueTxObject(NormObject* obj)
ASSERT(0);
return false;
}
obj->Retain();
tx_pending_mask.Set(obj->GetId());
ASSERT(tx_pending_mask.Test(obj->GetId()));
next_tx_object_id++;
@ -1351,11 +1391,12 @@ void NormTrace(const struct timeval& currentTime,
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
if (UniformRand(100.0) < rx_loss_rate)
{
return;
}
struct timeval currentTime;
::ProtoSystemTime(currentTime);
@ -1434,7 +1475,6 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
if (theServer->Open(msg.GetInstanceId()))
{
server_tree.AttachNode(theServer);
theServer->Retain();
DMSG(4, "NormSession::ClientHandleObjectMessage() node>%lu new remote server:%lu ...\n",
LocalNodeId(), msg.GetSourceId());
}
@ -1492,7 +1532,6 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
if (theServer->Open(cmd.GetInstanceId()))
{
server_tree.AttachNode(theServer);
theServer->Retain();
DMSG(4, "NormSession::ClientHandleCommand() node>%lu new remote server:%lu ...\n",
LocalNodeId(), cmd.GetSourceId());
}
@ -1555,28 +1594,32 @@ double NormSession::CalculateRtt(const struct timeval& currentTime,
void NormSession::ServerUpdateGrttEstimate(double clientRtt)
{
grtt_response = true;
//if ((clientRtt > grtt_current_peak) || !address.IsMulticast())
if ((clientRtt > grtt_measured) || !address.IsMulticast())
{
// Immediately incorporate bigger RTT's
grtt_current_peak = clientRtt;
//if ((clientRtt > grtt_measured) || !address.IsMulticast())
{
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
//grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
if (grtt_measured > grtt_max) grtt_measured = grtt_max;
double pktInterval = ((double)(44+segment_size))/tx_rate;
UINT8 grttQuantizedOld = grtt_quantized;
grtt_quantized = NormQuantizeRtt(MAX(pktInterval, grtt_measured));
// Calculate grtt_advertised since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu new grtt>%lf sec\n",
LocalNodeId(), grtt_advertised);
}
grtt_decrease_delay_count = DEFAULT_GRTT_DECREASE_DELAY;
//grtt_measured = 0.25 * grtt_measured + 0.75 * clientRtt;
grtt_measured = 0.9 * grtt_measured + 0.1 * clientRtt;
if (grtt_measured > grtt_max) grtt_measured = grtt_max;
UINT8 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);
// Calculate grtt_advertised since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
grtt_current_peak = grtt_measured;
if (grttQuantizedOld != grtt_quantized)
DMSG(4, "NormSession::ServerUpdateGrttEstimate() node>%lu increased to new grtt>%lf sec\n",
LocalNodeId(), grtt_advertised);
}
else if (clientRtt > grtt_current_peak)
{
grtt_current_peak = clientRtt;
}
} // end NormSession::ServerUpdateGrttEstimate()
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);
} // end NormSession::CalculateRate()
void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
UINT8 ccFlags,
double ccRtt,
double ccLoss,
double ccRate,
UINT16 ccSequence)
void NormSession::ServerHandleCCFeedback(struct timeval currentTime,
NormNodeId nodeId,
UINT8 ccFlags,
double ccRtt,
double ccLoss,
double ccRate,
UINT16 ccSequence)
{
// Keep track of current suppressing feedback
// (non-CLR, lowest rate, unconfirmed RTT)
@ -1641,6 +1685,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
double savedLoss = next->GetLoss();
double savedRate = next->GetRate();
UINT16 savedSequence = next->GetCCSequence();
struct timeval savedTime = next->GetFeedbackTime();
next->SetId(nodeId);
next->SetClrStatus(true);
@ -1649,7 +1694,8 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
next->SetRate(ccRate);
next->SetCCSequence(ccSequence);
next->SetActive(true);
if (next->GetId() == nodeId)
next->SetFeedbackTime(currentTime);
if (savedId == nodeId)
{
// This was feedback from the current CLR
AdjustRate(true);
@ -1668,6 +1714,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
ccLoss = savedLoss;
ccRate = savedRate,
ccSequence = savedSequence;
currentTime = savedTime;
}
}
else
@ -1688,12 +1735,14 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
}
next->SetId(nodeId);
next->SetClrStatus(true);
//next->SetPlrStatus(false);
next->SetRttStatus(0 != (ccFlags & NormCC::RTT));
next->SetRtt(ccRtt);
next->SetLoss(ccLoss);
next->SetRate(ccRate);
next->SetCCSequence(ccSequence);
next->SetActive(true);
next->SetFeedbackTime(currentTime);
AdjustRate(true);
return;
}
@ -1764,6 +1813,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
{
candidate->SetId(nodeId);
candidate->SetClrStatus(false);
//candidate->SetPlrStatus(true); // do this only
candidate->SetRttStatus(0 != (ccFlags & NormCC::RTT));
candidate->SetRtt(ccRtt);
candidate->SetLoss(ccLoss);
@ -1789,28 +1839,28 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons
{
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
{
ServerHandleCCFeedback(ack.GetSourceId(),
ServerHandleCCFeedback(currentTime,
ack.GetSourceId(),
ext.GetCCFlags(),
clientRtt >= 0.0 ?
clientRtt : NormUnquantizeRtt(ext.GetCCRtt()),
NormUnquantizeLoss(ext.GetCCLoss()),
NormUnquantizeRate(ext.GetCCRate()),
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())
{
case NormAck::CC:
// Everything is in the ACK header for this one
// Everything is in the ACK header or extension for this one
break;
case NormAck::FLUSH:
@ -1880,7 +1930,8 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor
{
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
{
ServerHandleCCFeedback(nack.GetSourceId(),
ServerHandleCCFeedback(currentTime,
nack.GetSourceId(),
ext.GetCCFlags(),
clientRtt >= 0.0 ?
clientRtt : NormUnquantizeRtt(ext.GetCCRtt()),
@ -2583,9 +2634,8 @@ bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/)
{
NormMsg* msg;
// (TBD) sometimes need RepairAdv even when cc_enable is false ...
NormCmdRepairAdvMsg adv;
// Note: sometimes need RepairAdv even when cc_enable is false ...
NormCmdRepairAdvMsg adv;
if (advertise_repairs && (probe_proactive || (repair_timer.IsActive() &&
repair_timer.GetRepeatCount())))
{
@ -2729,7 +2779,7 @@ bool NormSession::SendMessage(NormMsg& msg)
break;
}
// Fill in common message fields
msg.SetSourceId(local_node_id);
UINT16 msgSize = msg.GetLength();
bool result = true;
@ -2798,6 +2848,82 @@ bool NormSession::SendMessage(NormMsg& msg)
return result;
} // 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*/)
{
// 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)
{
// Sender paused, just idle probing until transmission is resumed
// Sender paused, so just skip probing until transmission is resumed
return true;
}
// 2) Update grtt_estimate _if_ sufficient time elapsed.
// This new code allows more liberal downward adjustment of
// of grtt when congestion control is enabled.
grtt_age += probe_timer.GetInterval();
double ageMax = 3 * grtt_advertised;
ageMax = ageMax > grtt_interval_min ? ageMax : grtt_interval_min;
if (grtt_age >= ageMax)//grtt_interval)
// We have to keep track of the _actual_ deltaTime instead
// of relying on the probe_timer interval because in real-
// 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)
{
@ -2844,16 +2998,18 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
grtt_measured = NORM_GRTT_MIN;
else if (grtt_measured > grtt_max)
grtt_measured = grtt_max;
UINT8 grttQuantizedOld = grtt_quantized;
double pktInterval = (double)(44+segment_size)/tx_rate;
grtt_advertised = MAX(pktInterval, grtt_measured);
double grttQuantizedOld = grtt_quantized;
grtt_quantized = NormQuantizeRtt(grtt_advertised);
if (grtt_measured < pktInterval)
grtt_quantized = NormQuantizeRtt(pktInterval);
else
grtt_quantized = NormQuantizeRtt(grtt_measured);
// Recalculate grtt_advertise since quantization rounds upward
grtt_advertised = NormUnquantizeRtt(grtt_quantized);
grtt_response = false;
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);
grtt_response = false; // reset
}
grtt_age = 0.0;
}
@ -2876,10 +3032,9 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
cmd->Init();
cmd->SetDestination(address);
cmd->SetGrtt(grtt_quantized);
cmd->SetBackoffFactor((unsigned char)backoff_factor);
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++);
if (probe_proactive)
@ -2900,7 +3055,10 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
if (next->IsActive())
{
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;
UINT8 rttQuantized = NormQuantizeRtt(next->GetRtt());
if (cc_slow_start) ccFlags |= (UINT8)NormCC::START;
@ -2911,14 +3069,26 @@ bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/)
ccFlags,
rttQuantized,
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);
// 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;
//double nominalRate = ((double)segment_size)/((double)tx_rate);
//probeInterval = MAX(probeInterval, nominalRate);
@ -2944,7 +3114,7 @@ void NormSession::AdjustRate(bool onResponse)
const NormCCNode* clr = (const NormCCNode*)cc_node_list.Head();
double ccRtt = clr ? clr->GetRtt() : grtt_measured;
double ccLoss = clr ? clr->GetLoss() : 0.0;
double oldRate = tx_rate;
double txRate = tx_rate;
if (onResponse)
{
// Adjust rate based on CLR feedback and
@ -2953,28 +3123,28 @@ void NormSession::AdjustRate(bool onResponse)
// (TBD) check feedback age
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",
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);
}
else
{
double clrRate = clr->GetRate();
if (clrRate > tx_rate)
if (clrRate > txRate)
{
double linRate = tx_rate + segment_size;
tx_rate = MIN(clrRate, linRate);
double linRate = txRate + segment_size;
txRate = MIN(clrRate, linRate);
}
else
{
tx_rate = clrRate;
txRate = clrRate;
}
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 ...
/*int feedbackAge = abs((int)cc_sequence - (int)clr->GetCCSequence());
@ -2983,33 +3153,38 @@ void NormSession::AdjustRate(bool onResponse)
if (feedbackAge > 50)
{
double linRate = tx_rate - segment_size;
double linRate = txRate - segment_size;
linRate = MAX(linRate, 0.0);
double expRate = tx_rate * 0.5;
double expRate = txRate * 0.5;
if (feedbackAge > 4)
tx_rate = MIN(linRate, expRate);
txRate = MIN(linRate, expRate);
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;
minRate = MIN((double)segment_size, minRate);
tx_rate = MAX(tx_rate, minRate);
if (minRate > ((double)(segment_size >> 2)))
minRate = (double)(segment_size >> 2);
if (txRate < minRate)
txRate = minRate;
// Keep "tx_rate" within user set rate bounds (if any)
if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min))
tx_rate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max))
tx_rate = tx_rate_max;
if ((tx_rate_min >= 0.0) && (txRate < tx_rate_min))
txRate = tx_rate_min;
if ((tx_rate_max >= 0.0) && (txRate > tx_rate_max))
txRate = tx_rate_max;
struct timeval currentTime;
::ProtoSystemTime(currentTime);
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec);
if (tx_rate != oldRate)
if (txRate != tx_rate) SetTxRateInternal(txRate);
/*if (txRate != oldRate)
{
if (tx_timer.IsActive())
{
@ -3020,8 +3195,10 @@ void NormSession::AdjustRate(bool onResponse)
tx_timer.SetInterval(txInterval);
tx_timer.Reschedule();
}
}
}*/
struct timeval currentTime;
::ProtoSystemTime(currentTime);
double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec);
DMSG(8, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n\n", theTime, tx_rate*(8.0/1000.0), ccRtt, ccLoss);
} // end NormSession::AdjustRate()

View File

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

View File

@ -13,9 +13,10 @@
#ifdef UNIX
#include <unistd.h> // for "sleep()"
#endif // UNIX
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();
@ -26,27 +27,62 @@ int main(int argc, char* argv[])
#endif // if/else WIN32/UNIX
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,
"224.1.2.3",
6003,
NORM_NODE_ANY);
localId);
// NOTE: These are debugging routines available (not for normal app use)
SetDebugLevel(2);
// Uncomment to turn on debug NORM message tracing
//NormSetMessageTrace(session, true);
// Uncomment to turn on some random packet loss
NormSetTxLoss(session, 10.0); // 10% packet loss
//NormSetTxLoss(session, 10.0); // 10% packet loss
struct timeval currentTime;
ProtoSystemTime(currentTime);
// Uncomment to get different packet loss patterns from run to run
// (and a different sender sessionId)
srand(currentTime.tv_sec); // seed random number generator
NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
//NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
NormSetTransmitRate(session, 60.0e+03); // in bits/second
NormSetTransmitRate(session, 6000.0e+03); // in bits/second
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
@ -56,25 +92,32 @@ int main(int argc, char* argv[])
// possible!
//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
NormSetLoopback(session, true);
// Uncomment this line to participate as a receiver
NormStartReceiver(session, 1024*1024);
//NormStartReceiver(session, 1024*1024);
// Uncomment to set large rx socket buffer size
// (might be needed for high rate sessions)
// NormSetRxSocketBuffer(session, 512000);
NormSetRxSocketBuffer(session, 512000);
// Uncomment to enable TCP-friendly congestion control
//NormSetCongestionControl(session, true);
NormSetCongestionControl(session, true);
// We use a random "sessionId"
NormSessionId sessionId = (NormSessionId)rand();
// 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
// (might be needed for high rate sessions)
@ -87,7 +130,7 @@ int main(int argc, char* argv[])
const char* fileName = "ferrari.jpg";
// 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
// the stream.
@ -115,7 +158,7 @@ int main(int argc, char* argv[])
// TRACE("NORM_TX_QUEUE_VACANCY ...\n");
case NORM_TX_QUEUE_EMPTY:
//TRACE("NORM_TX_QUEUE_EMPTY ...\n");
if (sendCount >= sendMax) break;
//if (sendCount >= sendMax) break;
if (NORM_OBJECT_INVALID != stream)
{
// We loop here to keep stream buffer full ....
@ -150,7 +193,7 @@ int main(int argc, char* argv[])
// after "sendMax" messages
//NormStreamClose(stream, true);
//keepWriting = false;
}
}
}
}
}
@ -251,6 +294,8 @@ int main(int argc, char* argv[])
// TRACE("validated recv msg len:%d\n", len);
}
recvCount = value;
//if (0 == msgCount % 100)
// TRACE("recv stream msg count: %d\n", msgCount);
}
else
{

View File

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

View File

@ -13,7 +13,7 @@ NS = ../ns
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)
@ -44,12 +44,14 @@ NORM_OBJ = $(NORM_SRC:.cpp=.o)
LIB_SRC = $(NORM_SRC)
LIB_OBJ = $(LIB_SRC:.cpp=.o)
# NORM as a static library
libnorm.a: $(LIB_OBJ)
$(AR) rcv $@ $(LIB_OBJ)
$(RANLIB) $@
.cpp-sim.o:
$(CC) -c $(CFLAGS) -DSIMULATE -o $*-sim.o $*.cpp
# NORM as a shared library
libnorm.so: $(LIB_OBJ)
$(CC) $(SYSTEM_SOFLAGS) $(LIB_OBJ) $(LIBS) -o $@
SIM_SRC = $(NORM_SRC) $(COMMON)/normSimAgent.cpp
SIM_OBJ = $(SIM_SRC:.cpp=-sim.o)
@ -82,7 +84,8 @@ raft: $(RAFT_OBJ) $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(RAFT_OBJ) $(LDFLAGS) $(LIBPROTO) $(LIBS)
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
# 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()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# 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_SRC = bsdRouteMgr.cpp
SYSTEM_SRC =
SYSTEM = freebsd
CC = gcc
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = ranlib
AR = ar

View File

@ -1,35 +1,13 @@
#
# 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
# (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
# System specific additional libraries, include paths, etc
# (Where to find X11 libraries, etc)
#
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\
-Xlinker +s -L/home/macker/mdp/X11R5/lib
SYSTEM_LDFLAGS =
SYTSTEM_LIBS =
# 6) System specific capabilities
@ -48,10 +26,6 @@ SYTSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -62,10 +36,12 @@ SYTSTEM_LIBS =
# (We export these for other Makefiles as needed)
#
export SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
SYSTEM_HAVES = -DHAVE_CUSERID -DHAVE_LOCKF
export CC = gcc
export RANLIB = touch
export AR = ar
CC = gcc
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = touch
AR = ar
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
# (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()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -70,6 +43,8 @@ SYSTEM_SRC =
SYSTEM = linux
export CC = g++
export SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export SYSTEM_SOFLAGS = -shared
export RANLIB = ranlib
export AR = ar

View File

@ -37,14 +37,16 @@ SYSTEM_LIBS = -lresolv
#
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
SYSTEM = macosx
CC = g++
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = ranlib
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
# (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()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# 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 CC = gcc
export SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
export SYSTEM_SOFLAGS = -shared
export RANLIB = ranlib
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
# (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()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -62,10 +35,12 @@ SYSTEM_LIBS =
# (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
export RANLIB = ranlib
export AR = ar
CC = gcc
SYSTEM_CFLAGS = -fPIC -Wall -pedantic -Wcast-align
SYSTEM_SOFLAGS = -shared
RANLIB = ranlib
AR = ar
include Makefile.common

View File

@ -26,10 +26,6 @@ SYSTEM_LIBS =
# D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT()
# 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
# some #ifdefs to avoid compiler warnings ... so you might need
# to specify -DSOLARIS or -DSUNOS depending on your OS.
@ -46,7 +42,15 @@ SYSTEM_SRC =
SYSTEM = sgi
# g++
#CC = g++
#SYSTEM_CFLAGS = -Wall -Wcast-align -pedantic -fPIC
# SGI CC
CC = CC
SYSTEM_CFLAGS = -KPIC -pedantic
SYSTEM_SOFLAGS = -shared
RANLIB = touch
AR = ar

View File

@ -35,15 +35,16 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv
# (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
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
AR = ar
include Makefile.common

View File

@ -60,11 +60,16 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket
# (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
export RANLIB = touch
export AR = ar
SYSTEM = solaris
SYSTEM_CFLAGS = -PIC -Wall -Wcast-align
CC = gcc
SYSTEM_SOFLAGS = -shared
RANLIB = touch
AR = ar
include Makefile.common

Binary file not shown.

View File

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

Binary file not shown.