v1.3b5
parent
32c42ee9c0
commit
de8a3c799b
|
|
@ -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’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 Developer’s 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’s
|
||||
<FONT FACE="Helvetica, sans-serif"><FONT SIZE=6 STYLE="font-size: 28pt"><B>NORM<BR>Developer’s
|
||||
<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 “session”
|
||||
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
|
||||
“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
|
||||
“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 “handshake” 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
|
||||
“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 "friendly"
|
||||
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 "friendly" 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 "POSIX Threads" library must be
|
|||
included ("-'pthread") in the linking step. MacOS/BSD also
|
||||
requires the addition of the "-lresolv" (resolver) library
|
||||
and Solaris requires the dynamic loader, network/socket, and resolver
|
||||
libraries ("–lnsl –lsocket –lresolv") 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 ("–lnsl –lsocket –lresolv") 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 –D_FILE_OFFSET_BITS=64 set
|
||||
in the compilation to enable "large file support".
|
||||
The distributed NORM Makefiles have –D_FILE_OFFSET_BITS=64 set in
|
||||
the compilation to enable "large file support".
|
||||
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 "normApi.h" 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 – 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. "Events" 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> NORM_FLUSH_NONE,<BR> NORM_FLUSH_PASSIVE,<BR> 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> NORM_PROBE_NONE,<BR> NORM_PROBE_PASSIVE,<BR> 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> NORM_NACK_NONE,<BR> NORM_NACK_INFO_ONLY,<BR> 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> NORM_BOUNDARY_BLOCK,<BR> 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 "instance" 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
|
||||
<normApi.h></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> 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>) ≤ 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 – <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 – 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> sess
|
|||
<BR> double 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
|
||||
<normApi.h></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> session,
|
||||
<BR> double 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
|
||||
<normApi.h></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> session,
|
||||
<BR> NormProbingMode 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 sender’s 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
|
||||
<normApi.h></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> session,
|
||||
<BR> double intervalMin,<BR> double 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 sender’s
|
||||
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
|
||||
<normApi.h></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> bool 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> bool eom
|
||||
= false,<BR> NormFlushMode flushMode
|
||||
= false,<BR> <A HREF="#NormFlushMode">NormFlushMode</A> 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 "small" 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>
|
|||
<normApi.h></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> NormFlushMode flushMode);</FONT></FONT></P>
|
||||
streamHandle<BR> <A HREF="#NormFlushMode">NormFlushMode</A> flushMode);</FONT></FONT></P>
|
||||
<H4 CLASS="western">Description</H4>
|
||||
<P CLASS="western" STYLE="font-style: normal">This function sets
|
||||
"<I>automated</I> flushing" 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? – 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 – 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>
|
|||
<normApi.h></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> NormNackingMode nackingMode);</FONT></FONT></P>
|
||||
<BR> <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
|
||||
default "nacking mode" used when receiving objects. This
|
||||
|
|
@ -2650,7 +2856,7 @@ return values.</P>
|
|||
<normApi.h></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> nodeHandle,
|
||||
<BR> NormNackingMode
|
||||
<BR> <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>
|
|||
<normApi.h></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> NormNackingMode nackingMode);</FONT></FONT></P>
|
||||
<BR> <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
|
||||
"nacking mode" used for receiving a specific transport
|
||||
|
|
@ -2689,7 +2895,7 @@ return values.</P>
|
|||
<normApi.h></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> sessionHandle,
|
||||
<BR> NormRepairBoundary
|
||||
<BR> <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>
|
|||
<normApi.h></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> nodeHandle,
|
||||
<BR> NormRepairBoundary
|
||||
<BR> <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.
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
19
README.md
19
README.md
|
|
@ -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
|
||||
|
||||
|
|
|
|||
50
VERSION.TXT
50
VERSION.TXT
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,7 +232,8 @@ NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle,
|
|||
const char* infoPtr = (const char*)0,
|
||||
unsigned int infoLen = 0);
|
||||
|
||||
bool NormDataEnqueue(const char* dataPtr,
|
||||
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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ class NormHeaderExtension
|
|||
};
|
||||
|
||||
NormHeaderExtension();
|
||||
virtual ~NormHeaderExtension() {}
|
||||
virtual void Init(UINT32* theBuffer)
|
||||
{
|
||||
buffer = theBuffer;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -196,8 +203,9 @@ class NormCCNode : public NormNode
|
|||
private:
|
||||
bool is_clr; // true if worst path representative
|
||||
bool is_plr; // true if worst path candidate
|
||||
bool is_active;
|
||||
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
|
||||
|
|
@ -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;}
|
||||
|
|
|
|||
|
|
@ -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,23 +1270,16 @@ 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);
|
||||
}
|
||||
|
|
@ -1310,7 +1305,6 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg,
|
|||
// For statistics only (TBD) #ifdef NORM_DEBUG
|
||||
server->IncrementRecvGoodput(segmentLength);
|
||||
}
|
||||
block->DetachSegment(sid);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1318,7 +1312,7 @@ 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
|
||||
|
|
@ -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,8 +2714,10 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
|
|||
return true;
|
||||
} // end NormStreamObject::WriteSegment()
|
||||
|
||||
void NormStreamObject::Prune(NormBlockId blockId)
|
||||
void NormStreamObject::Prune(NormBlockId blockId, bool updateStatus)
|
||||
{
|
||||
if (updateStatus || StreamUpdateStatus(blockId))
|
||||
{
|
||||
bool resync = false;
|
||||
NormBlock* block;
|
||||
while ((block = block_buffer.Find(block_buffer.RangeLo())))
|
||||
|
|
@ -2742,22 +2744,39 @@ void NormStreamObject::Prune(NormBlockId blockId)
|
|||
pending_mask.UnsetBits(firstId, count);
|
||||
}
|
||||
}
|
||||
bool result = StreamUpdateStatus(blockId);
|
||||
ASSERT(result);
|
||||
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();
|
||||
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)
|
||||
{
|
||||
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,45 +2841,91 @@ 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);
|
||||
// if (read_offset < segmentOffset)
|
||||
UINT32 diff = read_offset - segmentOffset;
|
||||
if ((diff > 0x80000000) || ((0x80000000 == diff) && (read_offset > segmentOffset)))
|
||||
{
|
||||
Release();
|
||||
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 = bytesRead;
|
||||
Release();
|
||||
*buflen = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 index = read_offset - segmentOffset;
|
||||
UINT16 length = NormDataMsg::ReadStreamPayloadLength(segment);
|
||||
|
||||
if ((length > 0) && (index >= length))
|
||||
{
|
||||
Release();
|
||||
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 = bytesRead;
|
||||
ASSERT(0);
|
||||
Release();
|
||||
*buflen = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UINT16 count = length - index;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
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,27 +1594,31 @@ 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));
|
||||
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 new grtt>%lf sec\n",
|
||||
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()
|
||||
|
||||
|
|
@ -1587,7 +1630,8 @@ double NormSession::CalculateRate(double size, double rtt, double loss)
|
|||
return (size / denom);
|
||||
} // end NormSession::CalculateRate()
|
||||
|
||||
void NormSession::ServerHandleCCFeedback(NormNodeId nodeId,
|
||||
void NormSession::ServerHandleCCFeedback(struct timeval currentTime,
|
||||
NormNodeId nodeId,
|
||||
UINT8 ccFlags,
|
||||
double ccRtt,
|
||||
double ccLoss,
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
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 ...
|
||||
// Note: sometimes need RepairAdv even when cc_enable is false ...
|
||||
NormCmdRepairAdvMsg adv;
|
||||
|
||||
if (advertise_repairs && (probe_proactive || (repair_timer.IsActive() &&
|
||||
repair_timer.GetRepeatCount())))
|
||||
{
|
||||
|
|
@ -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.
|
||||
|
||||
// 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();
|
||||
double ageMax = 3 * grtt_advertised;
|
||||
}
|
||||
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)//grtt_interval)
|
||||
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 (txRate != tx_rate) SetTxRateInternal(txRate);
|
||||
|
||||
if (tx_rate != oldRate)
|
||||
/*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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
@ -27,26 +28,61 @@ int main(int argc, char* argv[])
|
|||
|
||||
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 ....
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
#ifndef _NORM_VERSION
|
||||
#define _NORM_VERSION
|
||||
#define VERSION "1.3b4"
|
||||
#define VERSION "1.3b5"
|
||||
#endif // _NORM_VERSION
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
BIN
win32/Norm.suo
BIN
win32/Norm.suo
Binary file not shown.
|
|
@ -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"
|
||||
|
|
|
|||
BIN
wince/Norm.vco
BIN
wince/Norm.vco
Binary file not shown.
Loading…
Reference in New Issue