v1.3b3
parent
9c3ea04ba8
commit
14d4ab80c6
|
|
@ -3,10 +3,10 @@
|
|||
<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.2 (Linux)">
|
||||
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.3 (Linux)">
|
||||
<META NAME="AUTHOR" CONTENT="Robert Adamson">
|
||||
<META NAME="CREATED" CONTENT="20040824;15180000">
|
||||
<META NAME="CHANGED" CONTENT="20050427;11094100">
|
||||
<META NAME="CHANGED" CONTENT="20050609;13321500">
|
||||
<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>
|
||||
|
|
@ -70,7 +70,7 @@ Engineering Task Force RFC 3940.</P>
|
|||
<P CLASS="western" STYLE="font-style: normal">The NORM protocol is
|
||||
designed to provide end-to-end reliable transport of bulk data
|
||||
objects or streams over generic IP multicast routing and forwarding
|
||||
services. NORM uses a selective, negative acknowledgment (NACK)
|
||||
services. NORM uses a selective, negative acknowledgement (NACK)
|
||||
mechanism for transport reliability and offers additional protocol
|
||||
mechanisms to conduct reliable multicast sessions with limited "a
|
||||
priori" coordination among senders and receivers. A congestion
|
||||
|
|
@ -84,6 +84,18 @@ to allow different types of applications or possibly other higher
|
|||
level transport protocols to utilize its service in different ways.
|
||||
The protocol leverages the use of FEC-based repair and other proven
|
||||
reliable multicast transport techniques in its design.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">The NRL NORM library
|
||||
attempts to provide a general useful capability for development of
|
||||
reliable multicast applications for bulk file or other data delivery
|
||||
as well as support of stream-based transport with possible real-time
|
||||
delivery requirements. The API allows access to many NORM protocol
|
||||
parameters and control functions to tailor performance for specific
|
||||
applications. While default parameters, where provided, can be
|
||||
useful to a potential wide range of requirements, the many different
|
||||
possible group communication paradigms dictate different needs for
|
||||
different applications. Even with NORM, the developer should have a
|
||||
thorough understanding of the specific application's group
|
||||
communication needs.</P>
|
||||
<H1 CLASS="western" ALIGN=CENTER STYLE="page-break-before: always">Table
|
||||
of Contents</H1>
|
||||
<DIV ID="Table of Contents1" DIR="LTR">
|
||||
|
|
@ -100,19 +112,28 @@ of Contents</H1>
|
|||
Data Reception</FONT></P>
|
||||
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
|
||||
Event Notification</B></FONT></P>
|
||||
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>Build
|
||||
Notes</B></FONT></P>
|
||||
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Unix
|
||||
Platforms</B></FONT></P>
|
||||
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>Win32/WiNCE
|
||||
Platforms</B></FONT></P>
|
||||
<P STYLE="margin-top: 0.25in; font-style: normal"><FONT FACE="Helvetica, sans-serif"><B>API
|
||||
Reference</B></FONT></P>
|
||||
<P STYLE="margin-top: 0.17in; font-style: normal"><FONT SIZE=2><B>API
|
||||
Variable Types and Constants</B></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionHandle">NormSessionHandle</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSessionId">NormSessionId</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeHandle">NormNodeHandle</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormNodeId">NormNodeId</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectType">NormObjectType</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormSize">NormSize</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectTransportId">NormObjectTransportId</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEventType">NormEventType</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormEvent">NormEvent</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</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>
|
||||
|
|
@ -178,6 +199,7 @@ of Contents</H1>
|
|||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfoLength()">NormObjectGetInfoLength()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetInfo()">NormObjectGetInfo()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetSize()">NormObjectGetSize()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectGetBytesPending()">NormObjectGetBytesPending()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectCancel()">NormObjectCancel()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRetain()">NormObjectRetain()</A></FONT></P>
|
||||
<P STYLE="margin-left: 0.17in; margin-top: 0in; font-style: normal"><FONT SIZE=2><A HREF="#NormObjectRelease()">NormObjectRelease()</A></FONT></P>
|
||||
|
|
@ -358,7 +380,76 @@ disabling receiver feedback (silent receiver operation) entirely.</P>
|
|||
<H2 CLASS="western">API Event Notification</H2>
|
||||
<P CLASS="western" STYLE="font-style: normal">An asynchronous event
|
||||
dispatching mechanism is provided to notify the application of
|
||||
significant NORM protocol events ...</P>
|
||||
significant NORM protocol events. The centerpiece of this is the
|
||||
<FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> function which can be
|
||||
used to retrieve the next NORM protocol engine event in the form of a
|
||||
<FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> structure. This function will
|
||||
typically block until a <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> occurs.
|
||||
However, non-blocking operation may be achieved by using the
|
||||
<FONT FACE="Courier"><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT> call to get a value
|
||||
(file descriptor (Unix) or HANDLE (Win32) suitable for use in a
|
||||
asynchronous I/O monitoring functions such as <I>select()</I> (Unix)
|
||||
or <I>MsgWaitForMultipleObjects()</I> (Win32). The descriptor will
|
||||
be signaled when a <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT> is
|
||||
available. For Win32 platforms, dispatching of a user-defined
|
||||
Windows message for NORM event notification is also planned for a
|
||||
future update to the API.</P>
|
||||
<H1 CLASS="western">Build Notes</H1>
|
||||
<P CLASS="western" STYLE="font-style: normal">To build applications
|
||||
that use the NORM library, a path to the "normApi.h" header
|
||||
file must be provided and the linker step needs to reference the NORM
|
||||
library file ("libnorm.a" for Unix platforms and "Norm.lib"
|
||||
for Win32 platforms). NORM also depends upon the NRL Protean
|
||||
Protocol Prototyping toolkit"Protokit" library (a.k.a
|
||||
"Protolib") (static library files "libProtokit.a"
|
||||
for Unix and "Protokit.lib" for Win32). Depending upon the
|
||||
platform, some additional library dependencies may be required to
|
||||
support the needs of NORM and/or Protokit. These are described
|
||||
below.</P>
|
||||
<H2 CLASS="western">Unix Platforms</H2>
|
||||
<P CLASS="western" STYLE="font-style: normal">NORM has been built and
|
||||
tested on Linux (various architectures), MacOS (BSD), Solaris, and
|
||||
IRIX (SGI) platforms. The code should be readily portable to other
|
||||
Unix platforms.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">To support IPv6
|
||||
operation, the NORM and the Protokit library must be compiled with
|
||||
the "HAVE_IPV6" macro defined. This is default in the NORM
|
||||
and Protokit Makefiles for platforms that support IPv6. It is
|
||||
important that NORM and Protokit be built with this macro defined the
|
||||
same. With NORM, it is recommended that "large file support"
|
||||
options be enabled when possible.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">The NORM API uses
|
||||
threading so that the NORM protocol engine may run independent of the
|
||||
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 ("-ldl –lnsl –lsocket –lresolv")
|
||||
to achieve successful compilation. The Makefiles in the NORM source
|
||||
code distribution are a reference for these requirements.</P>
|
||||
<H2 CLASS="western">Win32/WiNCE Platforms</H2>
|
||||
<P CLASS="western" STYLE="font-style: normal">NORM has been built
|
||||
using Microsoft's Visual C++ (6.0 and .NET) and Embedded VC++ 4.2
|
||||
environments. In addition to proper macro definitions (e.g.,
|
||||
HAVE_IPV6, etc) that are included in the respective "Protokit"
|
||||
and "NORM" project files, it is important that common code
|
||||
generation settings be used when building the NORM application. The
|
||||
NORM and Protokit projects are built with the "Multithreading
|
||||
DLL" library usage set. The NORM API requires multithreading
|
||||
support. This is a critical setting and numerous compiler and linker
|
||||
errors will result if this is not properly set for your application
|
||||
project.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">NORM and Protokit also
|
||||
depend on the Winsock 2.0 ("ws2_32.lib" (or "ws2.lib"
|
||||
(WinCE)) and the IP Helper API ("iphlpapi.lib") libraries
|
||||
and these must be included in the project "Link"
|
||||
attributes.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">An additional note is
|
||||
that a bug in VC++ 6.0 and earlier compilers (includes embedded VC++
|
||||
4.x compilers) prevent compilation of Protokit-based code with
|
||||
debugging capabilities enabled. However, this has been resolved in
|
||||
VC++ .NET and is hoped to be resolved in the future for the WinCE
|
||||
build tools.</P>
|
||||
<H1 CLASS="western">API Reference</H1>
|
||||
<P CLASS="western" STYLE="font-style: normal">This section provides a
|
||||
reference to the NORM API variable types, constants and functions.</P>
|
||||
|
|
@ -388,6 +479,22 @@ call. Multiple <FONT FACE="Courier">NormSessionHandles</FONT> may be
|
|||
associated with a given <FONT FACE="Courier"><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT>.
|
||||
The special value <FONT FACE="Courier">NORM_SESSION_INVALID </FONT>is
|
||||
used to refer to invalid session references.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormSessionId">NormSessionId</A></H3>
|
||||
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT>
|
||||
type is used by applications to uniquely identify their instance of
|
||||
participation as a sender within a <I>NormSession</I>. This type is
|
||||
a parameter to the <FONT FACE="Courier"><A HREF="#NormStartSender()">NormStartSender()</A></FONT>
|
||||
function. Robust applications can use different <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT>
|
||||
values when initiating sender operation so that receivers can
|
||||
discriminate when a sender has terminated and restarted (whether
|
||||
intentional or due to system failure). For example, an application
|
||||
could cache its prior <FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT> value
|
||||
in non-volatile storage which could then be recovered and incremented
|
||||
(for example) upon system restart to produce a new value. The
|
||||
<FONT FACE="Courier"><A HREF="#NormSessionId">NormSessionId</A></FONT> value is used for the value
|
||||
of the <I>instance_id</I> field in NORM protocol sender messages (see
|
||||
the NORM protocol specification) and receivers use this field to
|
||||
detect sender restart within a <I>NormSession</I>.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormNodeHandle">NormNodeHandle</A></H3>
|
||||
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormNodeHandle">NormNodeHandle</A>
|
||||
</FONT>type is used to reference state kept by the NORM
|
||||
|
|
@ -441,6 +548,17 @@ function call. A special <FONT FACE="Courier"><A HREF="#NormObjectType">NormObj
|
|||
value, <I><FONT FACE="Courier">NORM_OBJECT_NONE</FONT></I>, indicates
|
||||
an invalid object type.
|
||||
</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormSize">NormSize</A></H3>
|
||||
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
|
||||
is the type used for <I>NormObject</I> size information. For
|
||||
example, the <FONT FACE="Courier"><A HREF="#NormObjectGetSize()">NormObjectGetSize()</A></FONT> function
|
||||
returns a value of type <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>. The
|
||||
range of <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT> values depends upon the
|
||||
operating system and NORM library compilation settings. With "large
|
||||
file support" enabled, as is the case with distributed NORM
|
||||
library "Makefiles", the <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
|
||||
type is a 64-bit integer. However, some platforms may support only
|
||||
32-bit object sizes.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormObjectTransportId">NormObjectTransportId</A></H3>
|
||||
<P CLASS="western" STYLE="font-style: normal">The
|
||||
<FONT FACE="Courier"><A HREF="#NormObjectTransportId">NormObjectTransportId</A></FONT> type is a 16-bit
|
||||
|
|
@ -452,7 +570,7 @@ values in a monotonically increasing fashion during the course of a
|
|||
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 function may be
|
||||
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
|
||||
|
|
@ -483,7 +601,17 @@ and <FONT FACE="Courier">object</FONT> fields indicate the applicable
|
|||
and <FONT FACE="Courier"><A HREF="#NormObjectHandle">NormObjectHandle</A></FONT>, respectively, to
|
||||
which the event applies. NORM protocol events are made available to
|
||||
the application via the <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>
|
||||
function call.
|
||||
function call.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormDescriptor">NormDescriptor</A></H3>
|
||||
<P CLASS="western" STYLE="font-style: normal">The <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT>
|
||||
type provides reference to a file descriptor (Unix) or HANDLE
|
||||
(Win32). For a given <FONT FACE="Courier"><A HREF="#NormInstanceHandle">NormInstanceHandle</A></FONT>,
|
||||
the <FONT FACE="Courier"><A HREF="#NormGetDescriptor()">NormGetDescriptor()</A></FONT> function can be
|
||||
used to retrieve a <A HREF="#NormDescriptor">NormDescriptor</A> value that may, in turn, used in
|
||||
appropriate system calls (e.g. <I>select()</I> or
|
||||
<I>MsgWaitForMultipleObjects()</I>) to asynchronously monitor the
|
||||
NORM protocol engine for notification events (see <FONT FACE="Courier"><A HREF="#NormEvent">NormEvent</A></FONT>
|
||||
description).
|
||||
</P>
|
||||
<H2 CLASS="western">API Initialization and Operation</H2>
|
||||
<P CLASS="western" STYLE="font-style: normal">The first step in using
|
||||
|
|
@ -640,6 +768,26 @@ function call.</P>
|
|||
objects for transmission.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=269>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><I>NORM_TX_FLUSH_COMPLETED</I></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=293>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This event indicates that the flushing process the NORM sender
|
||||
observes when it no longer has data ready for transmission has
|
||||
completed. The completion of the flushing process is a reasonable
|
||||
indicator (with a sufficient NORM "robust factor" value)
|
||||
that the receiver set no longer has any pending repair requests.
|
||||
Note the use of NORM's optional positive acknowledgement feature
|
||||
is more deterministic in this regards, but this notification is
|
||||
useful when there are non-acking (NACK-only) receivers. The
|
||||
default NORM robust factor of 20 (20 flush messages are sent at
|
||||
end-of-transmission) provides a high assurance of reliable
|
||||
transmission, even with packet loss rates of 50%.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=269>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
|
|
@ -843,14 +991,14 @@ events if undesired)).</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>NormDescriptor
|
||||
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2><A HREF="#NormDescriptor">NormDescriptor</A>
|
||||
NormGetDescriptor(<A HREF="#NormInstanceHandle">NormInstanceHandle</A> instance);</FONT></FONT></P>
|
||||
<H4 CLASS="western">Description</H4>
|
||||
<P CLASS="western" STYLE="font-style: normal">This function is used
|
||||
to retrieve a <FONT FACE="Courier">NormDescriptor</FONT> (integer
|
||||
to retrieve a <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT> (integer
|
||||
file descriptor (UNIX) or HANDLE (WIN32)) suitable for asynchronous
|
||||
I/O notification to avoid blocking calls to <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT>.
|
||||
A <FONT FACE="Courier">NormDescriptor</FONT> is available for each
|
||||
A <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT> is available for each
|
||||
protocol engine <U><FONT FACE="Courier">instance</FONT></U>. The
|
||||
descriptor (or WIN32 HANDLE) is suitable for use as an input (or
|
||||
"read") descriptor which is signaled when a NORM protocol
|
||||
|
|
@ -858,7 +1006,7 @@ event is ready for retrieval via <FONT FACE="Courier"><A HREF="#NormGetNextEvent
|
|||
Hence, a call to <FONT FACE="Courier"><A HREF="#NormGetNextEvent()">NormGetNextEvent()</A></FONT> will
|
||||
not block when the descriptor has been signaled. The <I><FONT FACE="Courier">select()</FONT></I>
|
||||
system call (UNIX) (or <I><FONT FACE="Courier">WaitForMultipleObjects()</FONT></I>
|
||||
(WIN32)) can be used to detect when the returned <FONT FACE="Courier">NormDescriptor</FONT>
|
||||
(WIN32)) can be used to detect when the returned <FONT FACE="Courier"><A HREF="#NormDescriptor">NormDescriptor</A></FONT>
|
||||
is signaled. For the <FONT FACE="Courier">select()</FONT> call
|
||||
usage, the NORM descriptor should be treated as a "read"
|
||||
descriptor.</P>
|
||||
|
|
@ -1186,7 +1334,7 @@ Functions</H2>
|
|||
<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
|
||||
NormStartSender(<A HREF="#NormSessionHandle">NormSessionHandle</A> session<BR> unsigned
|
||||
NormStartSender(<A HREF="#NormSessionHandle">NormSessionHandle</A> sessionHandle<BR> <A HREF="#NormSessionId">NormSessionId</A> sessionId<BR> unsigned
|
||||
long bufferSpace<BR> unsigned
|
||||
short segmentSize,<BR> unsigned
|
||||
char blockSize,<BR> unsigned
|
||||
|
|
@ -1200,25 +1348,44 @@ feedback collection and application API activity such as posting of
|
|||
sender-related <I>NormEvents</I>. The parameters required for this
|
||||
function call include:</P>
|
||||
<TABLE WIDTH=590 BORDER=0 CELLPADDING=7 CELLSPACING=0>
|
||||
<COL WIDTH=106>
|
||||
<COL WIDTH=456>
|
||||
<COL WIDTH=125>
|
||||
<COL WIDTH=437>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=106>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>session</U></FONT></P>
|
||||
<FONT FACE="Courier"><U>sessionHandle</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=456>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This must be a valid <FONT FACE="Courier"><A HREF="#NormSessionHandle">NormSessionHandle</A></FONT>
|
||||
previously obtained with a call to <FONT FACE="Courier"><A HREF="#NormCreateSession()">NormCreateSession()</A></FONT>.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=106>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>sessionId</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
Application-defined value used as the <I>instance_id</I> field of
|
||||
NORM sender messages for the application's participation within a
|
||||
session. Receivers can detect when a sender has terminated and
|
||||
restarted if the application uses different <FONT FACE="Courier"><U>sessionId</U></FONT>
|
||||
values when initiating sender operation. For example, a robust
|
||||
application could cache previous <FONT FACE="Courier"><U>sessionId</U></FONT>
|
||||
values in non-volatile storage and gracefully recover (without
|
||||
confusing receivers) from a total system shutdown and reboot by
|
||||
using a new <FONT FACE="Courier"><U>sessionId</U></FONT> value
|
||||
upon restart.</P>
|
||||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>bufferSpace</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=456>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This specifies the maximum memory space the NORM protocol engine
|
||||
is allowed to use to buffer any sender calculated FEC segments and
|
||||
|
|
@ -1236,11 +1403,11 @@ function call include:</P>
|
|||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=106>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>segmentSize</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=456>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This parameter sets the maximum <I>payload</I> size (in bytes) of
|
||||
NORM sender messages (<I>not</I> including any NORM message header
|
||||
|
|
@ -1262,11 +1429,11 @@ function call include:</P>
|
|||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=106>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>blockSize</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=456>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This parameter sets the number of source symbol segments (packets)
|
||||
per coding block, for the systematic Reed-Solomon FEC code used in
|
||||
|
|
@ -1286,11 +1453,11 @@ function call include:</P>
|
|||
</TD>
|
||||
</TR>
|
||||
<TR VALIGN=TOP>
|
||||
<TD WIDTH=106>
|
||||
<TD WIDTH=125>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
<FONT FACE="Courier"><U>numParity</U></FONT></P>
|
||||
</TD>
|
||||
<TD WIDTH=456>
|
||||
<TD WIDTH=437>
|
||||
<P CLASS="western" STYLE="font-style: normal; page-break-inside: avoid">
|
||||
This parameter sets the maximum number of parity symbol segments
|
||||
(packets) the sender is willing to <I>calculate</I> per FEC coding
|
||||
|
|
@ -2713,8 +2880,8 @@ yet been received (or is non-existent) for the specified object.</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>off_t
|
||||
NormObjectHasInfo(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
|
||||
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2><A HREF="#NormSize">NormSize</A>
|
||||
NormObjectGetSize(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
|
||||
<H4 CLASS="western">Description</H4>
|
||||
<P CLASS="western" STYLE="font-style: normal">This function can be
|
||||
used to determine the size (in bytes) of the transport object
|
||||
|
|
@ -2724,11 +2891,9 @@ parameter. NORM can support large object sizes for the
|
|||
typically the NORM library is built with any necessary, related
|
||||
macros defined such that operating system large file support is
|
||||
enabled (e.g., "<FONT FACE="Courier">#define _FILE_OFFSET_BITS
|
||||
64</FONT>" or equivalent). Developers should configure their
|
||||
build environment to correspond with the NORM library used to ensure
|
||||
that the "<FONT SIZE=2><FONT FACE="Courier">off_t</FONT></FONT>"
|
||||
type is appropriately defined.
|
||||
</P>
|
||||
64</FONT>" or equivalent). The <FONT FACE="Courier"><A HREF="#NormSize">NormSize</A></FONT>
|
||||
type is defined accordingly, so the application should be built with
|
||||
the same large file support configuration.</P>
|
||||
<P CLASS="western" STYLE="font-style: normal">For objects of type
|
||||
<FONT FACE="Courier"><I>NORM_OBJECT_STREAM</I></FONT>, the size
|
||||
returned here corresponds to the stream buffer size set by the sender
|
||||
|
|
@ -2738,6 +2903,28 @@ application when opening the referenced stream object.</P>
|
|||
content of the specified object, in bytes, is returned. Note that it
|
||||
may be possible that some objects have zero data content, but do have
|
||||
NORM_INFO content available.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormObjectGetBytesPending()">NormObjectGetBytesPending()</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><A HREF="#NormSize">NormSize</A>
|
||||
NormObjectGetBytesPending(<A HREF="#NormObjectHandle">NormObjectHandle</A> objectHandle);</FONT></FONT></P>
|
||||
<H4 CLASS="western">Description</H4>
|
||||
<P CLASS="western" STYLE="font-style: normal">This function can be
|
||||
used to determine the progress of reception of the NORM transport
|
||||
object identified by the <FONT FACE="Courier"><U>objectHandle</U></FONT>
|
||||
parameter. This function indicates the number of bytes that are
|
||||
pending reception (I.e., when the object is completely received,
|
||||
"bytes pending" will equal ZERO). This function is not
|
||||
necessarily applicable to objects of type NORM_OBJECT_STREAM which do
|
||||
not have a finite size. Note it is possible that this function might
|
||||
also be useful to query the "transmit pending" status of
|
||||
sender objects, but it does not account for pending FEC repair
|
||||
transmissions and thus may not produce useful results for this
|
||||
purpose.</P>
|
||||
<H4 CLASS="western">Return Values</H4>
|
||||
<P CLASS="western" STYLE="font-style: normal">A number of object
|
||||
source data bytes pending reception (or transmission) is returned.</P>
|
||||
<H3 CLASS="functionheading-western"><A NAME="NormObjectCancel()">NormObjectCancel()</A></H3>
|
||||
<H4 CLASS="western">Synopsis</H4>
|
||||
<P STYLE="font-style: normal; page-break-after: avoid"><FONT FACE="Courier"><FONT SIZE=2>#include
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -1,5 +1,14 @@
|
|||
NORM Version History
|
||||
|
||||
Version 1.3b3
|
||||
=============
|
||||
- Added NORM_TX_FLUSH_COMPLETE notification so the sender app
|
||||
can make an educated guess as to when his receivers are
|
||||
all happy.
|
||||
- Added NORM API sample code in "examples" directory.
|
||||
- Added NormObjectGetBytesPending() call for receivers to
|
||||
use to monitor reception progress.
|
||||
|
||||
Version 1.3b2
|
||||
=============
|
||||
- Added "graceful" stream shutdown option to
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include "normApi.h"
|
||||
#include "normSession.h"
|
||||
|
||||
|
|
@ -143,8 +142,10 @@ class NormInstance : public NormController
|
|||
NormInstance::Notification::Queue::Queue()
|
||||
: head(NULL), tail(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
NormInstance::Notification::Queue::~Queue()
|
||||
{
|
||||
Destroy();
|
||||
|
|
@ -168,7 +169,7 @@ NormInstance::NormInstance()
|
|||
#else
|
||||
notify_fd[0] = notify_fd[1] = -1;
|
||||
#endif // if/else WIN32/UNIX
|
||||
session_mgr.SetController(this);
|
||||
session_mgr.SetController(static_cast<NormController*>(this));
|
||||
}
|
||||
|
||||
NormInstance::~NormInstance()
|
||||
|
|
@ -314,6 +315,7 @@ void NormInstance::Notify(NormController::Event event,
|
|||
else
|
||||
{
|
||||
// we're ignoring files
|
||||
DMSG(8, "NormInstance::Notify() warning: receive file but no cache directory set, so ignoring file\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
|
@ -849,6 +851,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent)
|
|||
/** NORM Sender Functions */
|
||||
|
||||
bool NormStartSender(NormSessionHandle sessionHandle,
|
||||
NormSessionId sessionId,
|
||||
unsigned long bufferSpace,
|
||||
unsigned short segmentSize,
|
||||
unsigned char numData,
|
||||
|
|
@ -860,7 +863,7 @@ bool NormStartSender(NormSessionHandle sessionHandle,
|
|||
{
|
||||
NormSession* session = (NormSession*)sessionHandle;
|
||||
if (session)
|
||||
result = session->StartServer(bufferSpace, segmentSize, numData, numParity);
|
||||
result = session->StartServer(sessionId, bufferSpace, segmentSize, numData, numParity);
|
||||
else
|
||||
result = false;
|
||||
instance->dispatcher.ResumeThread();
|
||||
|
|
@ -1362,11 +1365,26 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
|
|||
return result;
|
||||
} // end NormObjectGetInfo()
|
||||
|
||||
off_t NormObjectGetSize(NormObjectHandle objectHandle)
|
||||
NormSize NormObjectGetSize(NormObjectHandle objectHandle)
|
||||
{
|
||||
return ((NormObject*)objectHandle)->GetSize().GetOffset();
|
||||
return ((NormSize)((NormObject*)objectHandle)->GetSize().GetOffset());
|
||||
} // end NormObjectGetSize()
|
||||
|
||||
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle)
|
||||
{
|
||||
NormSize bytesPending = 0;
|
||||
if (NORM_OBJECT_INVALID != objectHandle)
|
||||
{
|
||||
NormInstance* instance = NormInstance::GetInstanceFromObject(objectHandle);
|
||||
if (instance && instance->dispatcher.SuspendThread())
|
||||
{
|
||||
bytesPending = ((NormSize)((NormObject*)objectHandle)->GetBytesPending().GetOffset());
|
||||
instance->dispatcher.ResumeThread();
|
||||
}
|
||||
}
|
||||
return bytesPending;
|
||||
} // end NormObjectGetBytesPending()
|
||||
|
||||
void NormObjectCancel(NormObjectHandle objectHandle)
|
||||
{
|
||||
if (NORM_OBJECT_INVALID != objectHandle)
|
||||
|
|
|
|||
|
|
@ -4,15 +4,10 @@
|
|||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h> // for "off_t"
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
#include <stdio.h>
|
||||
//typedef fpos_t off_t;
|
||||
typedef long off_t;
|
||||
#else
|
||||
#include <sys/types.h> // for "off_t" type
|
||||
#endif // if/else _WIN32_WCE
|
||||
////////////////////////////////////////////////////////////
|
||||
// IMPORTANT NOTICE
|
||||
// The NORM API is _very_ much in a developmental phase
|
||||
|
|
@ -35,6 +30,7 @@ extern const NormInstanceHandle NORM_INSTANCE_INVALID;
|
|||
|
||||
typedef const void* NormSessionHandle;
|
||||
extern const NormSessionHandle NORM_SESSION_INVALID;
|
||||
typedef unsigned short NormSessionId;
|
||||
|
||||
typedef const void* NormNodeHandle;
|
||||
extern const NormNodeHandle NORM_NODE_INVALID;
|
||||
|
|
@ -46,6 +42,12 @@ typedef const void* NormObjectHandle;
|
|||
extern const NormObjectHandle NORM_OBJECT_INVALID;
|
||||
typedef unsigned short NormObjectTransportId;
|
||||
|
||||
#ifdef WIN32
|
||||
typedef __int64 NormSize;
|
||||
#else
|
||||
typedef off_t NormSize;
|
||||
#endif // WIN32
|
||||
|
||||
enum NormObjectType
|
||||
{
|
||||
NORM_OBJECT_NONE,
|
||||
|
|
@ -80,6 +82,7 @@ enum NormEventType
|
|||
NORM_EVENT_INVALID = 0,
|
||||
NORM_TX_QUEUE_VACANCY,
|
||||
NORM_TX_QUEUE_EMPTY,
|
||||
NORM_TX_FLUSH_COMPLETED,
|
||||
NORM_TX_OBJECT_SENT,
|
||||
NORM_TX_OBJECT_PURGED,
|
||||
NORM_LOCAL_SERVER_CLOSED,
|
||||
|
|
@ -172,6 +175,7 @@ void NormSetRxLoss(NormSessionHandle sessionHandle, double percent);
|
|||
/** NORM Sender Functions */
|
||||
|
||||
bool NormStartSender(NormSessionHandle sessionHandle,
|
||||
NormSessionId sessionId,
|
||||
unsigned long bufferSpace,
|
||||
unsigned short segmentSize,
|
||||
unsigned char numData,
|
||||
|
|
@ -298,7 +302,9 @@ unsigned short NormObjectGetInfo(NormObjectHandle objectHandle,
|
|||
char* buffer,
|
||||
unsigned short bufferLen);
|
||||
|
||||
off_t NormObjectGetSize(NormObjectHandle objectHandle);
|
||||
NormSize NormObjectGetSize(NormObjectHandle objectHandle);
|
||||
|
||||
NormSize NormObjectGetBytesPending(NormObjectHandle objectHandle);
|
||||
|
||||
void NormObjectCancel(NormObjectHandle objectHandle);
|
||||
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ bool NormApp::OnCommand(const char* cmd, const char* val)
|
|||
len = strlen(buffer);
|
||||
len = (len > 8191) ? 8191 : len;
|
||||
buffer[len++] = '\0';
|
||||
if (!control_pipe.Send(buffer, len))
|
||||
if (!control_pipe.Send(buffer, (unsigned int)len))
|
||||
{
|
||||
DMSG(0, "NormApp::OnCommand() error sending command to remote instance\n");
|
||||
return false;
|
||||
|
|
@ -1104,10 +1104,10 @@ void NormApp::Notify(NormController::Event event,
|
|||
// object Size() has recommended buffering size
|
||||
NormObjectSize size;
|
||||
if (silent_client)
|
||||
size = NormObjectSize((UINT32)rx_buffer_size);
|
||||
size = rx_buffer_size;
|
||||
else
|
||||
size = object->GetSize();
|
||||
|
||||
size = (UINT32)object->GetSize().LSB();
|
||||
ASSERT(0 == size.MSB());
|
||||
if (((NormStreamObject*)object)->Accept(size.LSB()))
|
||||
{
|
||||
rx_stream = (NormStreamObject*)object;
|
||||
|
|
@ -1544,7 +1544,9 @@ bool NormApp::OnStartup(int argc, const char*const* argv)
|
|||
session->SetBackoffFactor(backoff_factor);
|
||||
session->ServerSetGrtt(grtt_estimate);
|
||||
session->ServerSetGroupSize(group_size);
|
||||
if (!session->StartServer(tx_buffer_size, segment_size, ndata, nparity, interface_name))
|
||||
// We also use the baseId as our server's "instance id" for illustrative purposes
|
||||
UINT16 instanceId = baseId;
|
||||
if (!session->StartServer(instanceId, tx_buffer_size, segment_size, ndata, nparity, interface_name))
|
||||
{
|
||||
DMSG(0, "NormApp::OnStartup() start server error!\n");
|
||||
session_mgr.Destroy();
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ int NormFile::Read(char* buffer, int len)
|
|||
#else
|
||||
int result = read(fd, buffer, len);
|
||||
#endif // if/else WIN32
|
||||
if (result > 0) offset += (off_t)result;
|
||||
if (result > 0) offset += (Offset)result;
|
||||
return result;
|
||||
} // end NormFile::Read()
|
||||
|
||||
|
|
@ -360,24 +360,24 @@ int NormFile::Write(const char* buffer, int len)
|
|||
#else
|
||||
int result = write(fd, buffer, len);
|
||||
#endif // if/else WIN32
|
||||
if (result > 0) offset += (off_t)result;
|
||||
if (result > 0) offset += (Offset)result;
|
||||
return result;
|
||||
} // end NormFile::Write()
|
||||
|
||||
bool NormFile::Seek(off_t theOffset)
|
||||
bool NormFile::Seek(Offset theOffset)
|
||||
{
|
||||
ASSERT(IsOpen());
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32_WCE
|
||||
// (TBD) properly support big files on WinCE
|
||||
off_t result = fseek(file_ptr, (long)theOffset, SEEK_SET);
|
||||
Offset result = fseek(file_ptr, (long)theOffset, SEEK_SET);
|
||||
#else
|
||||
off_t result = _lseek(fd, theOffset, SEEK_SET);
|
||||
Offset result = _lseeki64(fd, theOffset, SEEK_SET);
|
||||
#endif // if/else _WIN32_WCE
|
||||
#else
|
||||
off_t result = lseek(fd, theOffset, SEEK_SET);
|
||||
Offset result = lseek(fd, theOffset, SEEK_SET);
|
||||
#endif // if/else WIN32
|
||||
if (result == (off_t)-1)
|
||||
if (result == (Offset)-1)
|
||||
{
|
||||
DMSG(0, "NormFile::Seek() lseek() error: %s", GetErrorString());
|
||||
return false;
|
||||
|
|
@ -389,12 +389,12 @@ bool NormFile::Seek(off_t theOffset)
|
|||
}
|
||||
} // end NormFile::Seek()
|
||||
|
||||
off_t NormFile::GetSize() const
|
||||
NormFile::Offset NormFile::GetSize() const
|
||||
{
|
||||
ASSERT(IsOpen());
|
||||
#ifdef _WIN32_WCE
|
||||
DWORD fileSize = GetFileSize(_fileno(file_ptr), NULL);
|
||||
return ((off_t)fileSize);
|
||||
return ((Offset)fileSize);
|
||||
#else
|
||||
#ifdef WIN32
|
||||
struct _stat info;
|
||||
|
|
@ -787,7 +787,7 @@ NormFile::Type NormFile::GetType(const char* path)
|
|||
#endif // if/else WIN32
|
||||
} // end NormFile::GetType()
|
||||
|
||||
off_t NormFile::GetSize(const char* path)
|
||||
NormFile::Offset NormFile::GetSize(const char* path)
|
||||
{
|
||||
#ifdef _WIN32_WCE
|
||||
WIN32_FIND_DATA findData;
|
||||
|
|
@ -799,7 +799,10 @@ off_t NormFile::GetSize(const char* path)
|
|||
if (INVALID_HANDLE_VALUE != FindFirstFile(path, &findData))
|
||||
#endif // if/else _UNICODE
|
||||
{
|
||||
return ((off_t)findData.nFileSizeLow); // (TBD) support big files
|
||||
Offset fileSize = findData.nFileSizeLow;
|
||||
if (sizeof(Offset) > 4)
|
||||
fileSize |= ((Offset)findData.nFileSizeHigh) << (8*sizeof(DWORD));
|
||||
return fileSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#ifdef _WIN32_WCE
|
||||
#include <stdio.h>
|
||||
//typedef fpos_t off_t;
|
||||
typedef long off_t;
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif // if/else _WIN32_WCE
|
||||
|
|
@ -45,8 +43,12 @@ enum
|
|||
|
||||
class NormFile
|
||||
{
|
||||
// Methods
|
||||
public:
|
||||
#ifdef WIN32
|
||||
typedef __int64 Offset;
|
||||
#else
|
||||
typedef off_t Offset;
|
||||
#endif // if/else WIN32/UNIX
|
||||
enum Type {INVALID, NORMAL, DIRECTORY};
|
||||
NormFile();
|
||||
~NormFile();
|
||||
|
|
@ -66,13 +68,13 @@ class NormFile
|
|||
}
|
||||
int Read(char* buffer, int len);
|
||||
int Write(const char* buffer, int len);
|
||||
bool Seek(off_t theOffset);
|
||||
off_t GetOffset() const {return (offset);}
|
||||
off_t GetSize() const;
|
||||
bool Seek(Offset theOffset);
|
||||
NormFile::Offset GetOffset() const {return (offset);}
|
||||
NormFile::Offset GetSize() const;
|
||||
|
||||
// static helper methods
|
||||
static NormFile::Type GetType(const char *path);
|
||||
static off_t GetSize(const char* path);
|
||||
static NormFile::Offset GetSize(const char* path);
|
||||
static time_t GetUpdateTime(const char* path);
|
||||
static bool IsLocked(const char *path);
|
||||
|
||||
|
|
@ -117,7 +119,11 @@ class NormFile
|
|||
int fd;
|
||||
#endif // if/else _WIN32_WCE
|
||||
int flags;
|
||||
#ifdef WIN32
|
||||
__int64 offset;
|
||||
#else
|
||||
off_t offset;
|
||||
#endif // if/else WIN32/UNIX
|
||||
}; // end class NormFile
|
||||
|
||||
|
||||
|
|
@ -204,7 +210,7 @@ class NormFileList
|
|||
FileItem(const char* thePath);
|
||||
virtual ~FileItem();
|
||||
NormFile::Type GetType() {return NormFile::GetType(path);}
|
||||
off_t Size() const {return size;}
|
||||
NormFile::Offset Size() const {return size;}
|
||||
virtual bool GetNextFile(char* thePath,
|
||||
bool reset,
|
||||
bool updatesOnly,
|
||||
|
|
@ -216,7 +222,7 @@ class NormFileList
|
|||
const char* Path() {return path;}
|
||||
|
||||
char path[PATH_MAX];
|
||||
off_t size;
|
||||
NormFile::Offset size;
|
||||
FileItem* prev;
|
||||
FileItem* next;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -431,111 +431,3 @@ unsigned char NormQuantizeRtt(double rtt)
|
|||
return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt)))));
|
||||
} // end NormQuantizeRtt()
|
||||
|
||||
NormObjectSize NormObjectSize::operator+(const NormObjectSize& size) const
|
||||
{
|
||||
NormObjectSize total;
|
||||
total.msb = msb + size.msb;
|
||||
total.lsb = lsb + size.lsb;
|
||||
if ((total.lsb < lsb) || (total.lsb < size.lsb)) total.msb++;
|
||||
return total;
|
||||
} // end NormObjectSize::operator+(NormObjectSize id)
|
||||
|
||||
NormObjectSize NormObjectSize::operator-(const NormObjectSize& b) const
|
||||
{
|
||||
NormObjectSize result;
|
||||
result.lsb = lsb - b.lsb;
|
||||
result.msb = msb - b.msb;
|
||||
if (lsb < b.lsb) result.msb--;
|
||||
return result;
|
||||
} // end NormObjectSize::operator-(NormObjectSize id)
|
||||
|
||||
NormObjectSize NormObjectSize::operator*(const NormObjectSize& b) const
|
||||
{
|
||||
UINT32 ll = (lsb & 0x0000ffff) * (b.lsb & 0x0000ffff);
|
||||
UINT32 lm = (lsb & 0x0000ffff) * ((b.lsb >> 16) & 0x0000ffff);
|
||||
UINT32 ml = ((lsb >> 16) & 0x0000ffff) * (b.lsb & 0x0000ffff);
|
||||
UINT32 lu = (lsb & 0x0000ffff) * (UINT32)b.msb;
|
||||
UINT32 mm = ((lsb >> 16) & 0x0000ffff) *
|
||||
((b.lsb >> 16) & 0x0000ffff);
|
||||
NormObjectSize result;
|
||||
result.lsb = ll + (lm << 16) + (ml << 16);
|
||||
result.msb = lu + mm + ((lm >> 16) & 0x0000ffff) +
|
||||
((ml >> 16) & 0x0000ffff);
|
||||
return result;
|
||||
} // end NormObjectSize::operator*(NormObjectSize size)
|
||||
|
||||
// Note: This always rounds up if there is _any_ remainder
|
||||
NormObjectSize NormObjectSize::operator/(const NormObjectSize& b) const
|
||||
{
|
||||
// Zero dividend is special case
|
||||
if ((0 == lsb) && (0 == msb)) return NormObjectSize(0, 0);
|
||||
// Zero divisor is special case
|
||||
if ((0 == b.lsb) && (0 == b.msb)) return NormObjectSize(0xffff, 0xffffffff);
|
||||
// Divisor >= dividend is special case
|
||||
if ((b.lsb >= lsb) && (b.msb >= msb)) return NormObjectSize(0,1);
|
||||
// divisor
|
||||
UINT32 divisor[2];
|
||||
divisor[0] = (UINT32)b.msb;
|
||||
divisor[1] = b.lsb;
|
||||
// dividend
|
||||
UINT32 dividend[2];
|
||||
dividend[0] = msb;
|
||||
dividend[1] = (UINT32)lsb;
|
||||
// remainder
|
||||
UINT32 remainder[2];
|
||||
remainder[0] = remainder[1] = 0;
|
||||
unsigned int numBits = 64;
|
||||
UINT32 d[2];
|
||||
while (((divisor[1] > remainder[1]) && (divisor[0] == remainder[0])) ||
|
||||
(divisor[0] > remainder[0]))
|
||||
{
|
||||
remainder[0] <<= 1;
|
||||
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
|
||||
remainder[1] <<= 1;
|
||||
remainder[1] |= (dividend[0] >> 31) & 0x00000001;
|
||||
d[0] = dividend[0];
|
||||
d[1] = dividend[1];
|
||||
dividend[0] <<= 1;
|
||||
dividend[0] |= (dividend[1] >> 31) & 0x00000001;
|
||||
dividend[1] <<= 1;
|
||||
numBits--;
|
||||
}
|
||||
|
||||
// Note: above loop goes one step too far
|
||||
// so we incr numBits, use old dividend (d)
|
||||
numBits++;
|
||||
UINT32 quotient[2];
|
||||
quotient[0] = quotient[1] = 0;
|
||||
bool extra = false;
|
||||
for (unsigned int i = 0; i < numBits; i++)
|
||||
{
|
||||
UINT32 t[2];
|
||||
t[0] = remainder[0] - divisor[0];
|
||||
t[1] = remainder[1] - divisor[1];
|
||||
if (remainder[1] < divisor[1]) t[0]--;
|
||||
UINT32 q = ((t[0] >> 31) & 0x00000001) ^ 0x00000001;
|
||||
d[0] <<= 1;
|
||||
d[0] |= (d[1] >> 31) & 0x00000001;
|
||||
d[1] <<= 1;
|
||||
quotient[0] <<= 1;
|
||||
quotient[1] = (quotient[1] << 1) | q;
|
||||
if (q)
|
||||
{
|
||||
remainder[0] = t[0];
|
||||
remainder[1] = t[1];
|
||||
}
|
||||
if (remainder[0] || remainder[1])
|
||||
extra = true;
|
||||
else
|
||||
extra = false;
|
||||
remainder[0] <<= 1;
|
||||
remainder[0] |= (remainder[1] >> 31) & 0x00000001;
|
||||
remainder[1] <<= 1;
|
||||
remainder[1] |= (d[0] >> 31) & 0x00000001;
|
||||
}
|
||||
NormObjectSize result((UINT16)quotient[0], quotient[1]);
|
||||
// If there was _any_ remainder, round up
|
||||
if (extra) result++;
|
||||
return result;
|
||||
} // end NormObjectSize::operator/(NormObjectSize b)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#ifdef _WIN32_WCE
|
||||
#include <stdio.h>
|
||||
//typedef fpos_t off_t;
|
||||
typedef long off_t;
|
||||
#else
|
||||
#include <sys/types.h> // for off_t
|
||||
#endif // if/else _WIN32_WCE
|
||||
|
|
@ -23,9 +21,6 @@ typedef long off_t;
|
|||
|
||||
const UINT8 NORM_PROTOCOL_VERSION = 1;
|
||||
|
||||
// (TBD) Alot of the "memcpy()" calls could be eliminated by
|
||||
// taking advantage of the alignment of NORM messsages
|
||||
|
||||
const int NORM_ROBUST_FACTOR = 20; // default robust factor
|
||||
|
||||
// Pick a random number from 0..max
|
||||
|
|
@ -101,85 +96,66 @@ inline double NormUnquantizeRate(unsigned short rate)
|
|||
return mantissa * pow(10.0, exponent);
|
||||
}
|
||||
|
||||
// This class is used to describe object "size" and/or "offset"
|
||||
// (TBD) This hokey implementation should just use "off_t" as it's
|
||||
// native storage format and get rid of this custom crap !!!
|
||||
// (We should just get rid of this class !!!!!!!!)
|
||||
class NormObjectSize
|
||||
{
|
||||
public:
|
||||
NormObjectSize() : msb(0), lsb(0) {}
|
||||
NormObjectSize(UINT16 upper, UINT32 lower) : msb(upper), lsb(lower) {}
|
||||
NormObjectSize(UINT32 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(UINT16 size) : msb(0), lsb(size) {}
|
||||
NormObjectSize(const NormObjectSize& size) : msb(size.msb), lsb(size.lsb) {}
|
||||
NormObjectSize(off_t size)
|
||||
#ifdef WIN32
|
||||
typedef __int64 Offset;
|
||||
#else
|
||||
typedef off_t Offset;
|
||||
#endif
|
||||
NormObjectSize() : size(0) {}
|
||||
NormObjectSize(Offset theSize) : size(theSize) {}
|
||||
NormObjectSize(UINT16 msb, UINT32 lsb)
|
||||
{
|
||||
lsb = (unsigned long)(size & 0x00000000ffffffff);
|
||||
size >>= 32;
|
||||
ASSERT(0 == (size & 0xffff0000));
|
||||
msb = (unsigned short)(size & 0x0000ffff);
|
||||
msb = 0;
|
||||
size = (Offset)lsb;
|
||||
size |= (sizeof(Offset) > 4) ? (((Offset)msb) << 32): (Offset)0;
|
||||
}
|
||||
Offset GetOffset() const {return size;}
|
||||
UINT16 MSB() const
|
||||
{return ((sizeof(Offset) > 4) ? (UINT16)((size >> 32) & 0x0000ffff) : 0);}
|
||||
UINT32 LSB() const
|
||||
{return ((UINT32)(size & 0xffffffff));}
|
||||
|
||||
UINT16 MSB() const {return msb;}
|
||||
UINT32 LSB() const {return lsb;}
|
||||
bool operator==(const NormObjectSize& size) const
|
||||
{return ((msb == size.msb) && (lsb == size.lsb));}
|
||||
bool operator>(const NormObjectSize& size) const
|
||||
// Operators
|
||||
bool operator==(const NormObjectSize& b) const
|
||||
{return (b.size == size);}
|
||||
NormObjectSize operator+(const NormObjectSize& b) const
|
||||
{
|
||||
return ((msb == size.msb) ?
|
||||
(lsb > size.lsb) :
|
||||
(msb > size.msb));
|
||||
NormObjectSize result(size);
|
||||
result.size += b.size;
|
||||
return result;
|
||||
}
|
||||
bool operator<(const NormObjectSize& size) const
|
||||
void operator+=(const NormObjectSize& b)
|
||||
{size += b.size;}
|
||||
NormObjectSize operator-(const NormObjectSize& b) const
|
||||
{
|
||||
return ((msb == size.msb) ?
|
||||
(lsb < size.lsb) :
|
||||
(msb < size.msb));
|
||||
NormObjectSize result(size);
|
||||
result.size -= b.size;
|
||||
return result;
|
||||
}
|
||||
bool operator<=(const NormObjectSize& size) const
|
||||
{return ((*this == size) || (*this<size));}
|
||||
bool operator>=(const NormObjectSize& size) const
|
||||
{return ((*this == size) || (*this>size));}
|
||||
bool operator!=(const NormObjectSize& size) const
|
||||
{return ((lsb != size.lsb) || (msb != size.msb));}
|
||||
NormObjectSize operator+(const NormObjectSize& size) const;
|
||||
NormObjectSize operator-(const NormObjectSize& size) const;
|
||||
void operator+=(UINT32 increment)
|
||||
void operator-=(const NormObjectSize& b)
|
||||
{size -= b.size;}
|
||||
void operator+=(Offset increment)
|
||||
{size += increment;}
|
||||
bool operator>(const NormObjectSize& b) const
|
||||
{return (size > b.size);}
|
||||
NormObjectSize operator*(const NormObjectSize& b) const
|
||||
{
|
||||
UINT32 temp32 = lsb + increment;
|
||||
if (temp32 < lsb) msb++;
|
||||
lsb = temp32;
|
||||
NormObjectSize result(size);
|
||||
result.size *= b.size;
|
||||
return result;
|
||||
}
|
||||
NormObjectSize operator+(UINT32 increment) const
|
||||
// Note: this is a "round-upwards" division operator
|
||||
NormObjectSize operator/(const NormObjectSize& b) const
|
||||
{
|
||||
NormObjectSize total;
|
||||
total.msb = msb;
|
||||
total.lsb = lsb + increment;
|
||||
if (total.lsb < lsb) total.msb++;
|
||||
return total;
|
||||
NormObjectSize result(size);
|
||||
result.size /= b.size;
|
||||
result.size = ((result.size * b.size) < size) ? result.size + 1 : result.size;
|
||||
return result;
|
||||
}
|
||||
NormObjectSize& operator++(int)
|
||||
{
|
||||
lsb++;
|
||||
if (0 == lsb) msb++;
|
||||
return (*this);
|
||||
}
|
||||
NormObjectSize operator*(const NormObjectSize& b) const;
|
||||
NormObjectSize operator/(const NormObjectSize& b) const;
|
||||
off_t GetOffset() const
|
||||
{
|
||||
|
||||
off_t offset = msb;
|
||||
offset <<= 32;
|
||||
offset += lsb;
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
UINT16 msb;
|
||||
UINT32 lsb;
|
||||
Offset size;
|
||||
}; // end class NormObjectSize
|
||||
|
||||
#ifndef _NORM_API
|
||||
|
|
@ -426,9 +402,9 @@ class NormObjectMsg : public NormMsg
|
|||
FLAG_STREAM = 0x20,
|
||||
FLAG_MSG_START = 0x40
|
||||
};
|
||||
UINT16 GetSessionId() const
|
||||
UINT16 GetInstanceId() const
|
||||
{
|
||||
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
|
||||
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
|
||||
}
|
||||
UINT8 GetGrtt() const {return ((UINT8*)buffer)[GRTT_OFFSET];}
|
||||
UINT8 GetBackoffFactor() const {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
|
||||
|
|
@ -443,9 +419,9 @@ class NormObjectMsg : public NormMsg
|
|||
}
|
||||
|
||||
// Message building routines
|
||||
void SetSessionId(UINT16 sessionId)
|
||||
void SetInstanceId(UINT16 instanceId)
|
||||
{
|
||||
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
|
||||
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
|
||||
}
|
||||
void SetGrtt(UINT8 grtt) {((UINT8*)buffer)[GRTT_OFFSET] = grtt;}
|
||||
void SetBackoffFactor(UINT8 backoff)
|
||||
|
|
@ -467,8 +443,8 @@ class NormObjectMsg : public NormMsg
|
|||
protected:
|
||||
enum
|
||||
{
|
||||
SESSION_ID_OFFSET = MSG_OFFSET/2,
|
||||
GRTT_OFFSET = (SESSION_ID_OFFSET*2)+2,
|
||||
INSTANCE_ID_OFFSET = MSG_OFFSET/2,
|
||||
GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
|
||||
BACKOFF_OFFSET = GRTT_OFFSET+1,
|
||||
GSIZE_OFFSET = BACKOFF_OFFSET,
|
||||
FLAGS_OFFSET = GSIZE_OFFSET+1,
|
||||
|
|
@ -733,9 +709,9 @@ class NormCmdMsg : public NormMsg
|
|||
};
|
||||
|
||||
// Message building
|
||||
void SetSessionId(UINT16 sessionId)
|
||||
void SetInstanceId(UINT16 instanceId)
|
||||
{
|
||||
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
|
||||
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
|
||||
}
|
||||
void SetGrtt(UINT8 quantizedGrtt)
|
||||
{((UINT8*)buffer)[GRTT_OFFSET] = quantizedGrtt;}
|
||||
|
|
@ -751,7 +727,7 @@ class NormCmdMsg : public NormMsg
|
|||
{((UINT8*)buffer)[FLAVOR_OFFSET] = (UINT8)flavor;}
|
||||
|
||||
// Message processing
|
||||
UINT16 GetSessionId() const {return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));}
|
||||
UINT16 GetInstanceId() const {return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));}
|
||||
UINT8 GetGrtt() const {return ((UINT8*)buffer)[GRTT_OFFSET];}
|
||||
UINT8 GetBackoffFactor() const {return ((((UINT8*)buffer)[GSIZE_OFFSET] >> 4) & 0x0f);}
|
||||
UINT8 GetGroupSize() const {return (((UINT8*)buffer)[GSIZE_OFFSET] & 0x0f);}
|
||||
|
|
@ -761,8 +737,8 @@ class NormCmdMsg : public NormMsg
|
|||
friend class NormMsg;
|
||||
enum
|
||||
{
|
||||
SESSION_ID_OFFSET = MSG_OFFSET/2,
|
||||
GRTT_OFFSET = (SESSION_ID_OFFSET*2)+2,
|
||||
INSTANCE_ID_OFFSET = MSG_OFFSET/2,
|
||||
GRTT_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
|
||||
BACKOFF_OFFSET = GRTT_OFFSET + 1,
|
||||
GSIZE_OFFSET = BACKOFF_OFFSET,
|
||||
FLAVOR_OFFSET = GSIZE_OFFSET + 1
|
||||
|
|
@ -1396,9 +1372,9 @@ class NormNackMsg : public NormMsg
|
|||
{
|
||||
buffer[SERVER_ID_OFFSET] = htonl(serverId);
|
||||
}
|
||||
void SetSessionId(UINT16 sessionId)
|
||||
void SetInstanceId(UINT16 instanceId)
|
||||
{
|
||||
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
|
||||
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
|
||||
}
|
||||
void SetGrttResponse(const struct timeval& grttResponse)
|
||||
{
|
||||
|
|
@ -1424,9 +1400,9 @@ class NormNackMsg : public NormMsg
|
|||
{
|
||||
return (ntohl(buffer[SERVER_ID_OFFSET]));
|
||||
}
|
||||
UINT16 GetSessionId() const
|
||||
UINT16 GetInstanceId() const
|
||||
{
|
||||
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
|
||||
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
|
||||
}
|
||||
void GetGrttResponse(struct timeval& grttResponse) const
|
||||
{
|
||||
|
|
@ -1449,8 +1425,8 @@ class NormNackMsg : public NormMsg
|
|||
enum
|
||||
{
|
||||
SERVER_ID_OFFSET = MSG_OFFSET/4,
|
||||
SESSION_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
|
||||
RESERVED_OFFSET = ((SESSION_ID_OFFSET*2)+2)/2,
|
||||
INSTANCE_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
|
||||
RESERVED_OFFSET = ((INSTANCE_ID_OFFSET*2)+2)/2,
|
||||
GRTT_RESPONSE_SEC_OFFSET = ((RESERVED_OFFSET*2)+2)/4,
|
||||
GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET*4)+4)/4,
|
||||
NACK_HEADER_LEN = (GRTT_RESPONSE_USEC_OFFSET*4)+4
|
||||
|
|
@ -1472,9 +1448,9 @@ class NormAckMsg : public NormMsg
|
|||
{
|
||||
buffer[SERVER_ID_OFFSET] = htonl(serverId);
|
||||
}
|
||||
void SetSessionId(UINT16 sessionId)
|
||||
void SetInstanceId(UINT16 instanceId)
|
||||
{
|
||||
((UINT16*)buffer)[SESSION_ID_OFFSET] = htons(sessionId);
|
||||
((UINT16*)buffer)[INSTANCE_ID_OFFSET] = htons(instanceId);
|
||||
}
|
||||
void SetAckType(NormAck::Type ackType) {((UINT8*)buffer)[ACK_TYPE_OFFSET] = (UINT8)ackType;}
|
||||
void SetAckId(UINT8 ackId) {((UINT8*)buffer)[ACK_ID_OFFSET] = ackId;}
|
||||
|
|
@ -1496,9 +1472,9 @@ class NormAckMsg : public NormMsg
|
|||
{
|
||||
return (ntohl(buffer[SERVER_ID_OFFSET]));
|
||||
}
|
||||
UINT16 GetSessionId() const
|
||||
UINT16 GetInstanceId() const
|
||||
{
|
||||
return (ntohs(((UINT16*)buffer)[SESSION_ID_OFFSET]));
|
||||
return (ntohs(((UINT16*)buffer)[INSTANCE_ID_OFFSET]));
|
||||
}
|
||||
void GetGrttResponse(struct timeval& grttResponse) const
|
||||
{
|
||||
|
|
@ -1514,8 +1490,8 @@ class NormAckMsg : public NormMsg
|
|||
enum
|
||||
{
|
||||
SERVER_ID_OFFSET = MSG_OFFSET/4,
|
||||
SESSION_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
|
||||
ACK_TYPE_OFFSET = (SESSION_ID_OFFSET*2)+2,
|
||||
INSTANCE_ID_OFFSET = ((SERVER_ID_OFFSET*4)+4)/2,
|
||||
ACK_TYPE_OFFSET = (INSTANCE_ID_OFFSET*2)+2,
|
||||
ACK_ID_OFFSET = ACK_TYPE_OFFSET + 1,
|
||||
GRTT_RESPONSE_SEC_OFFSET = (ACK_ID_OFFSET + 1)/4,
|
||||
GRTT_RESPONSE_USEC_OFFSET = ((GRTT_RESPONSE_SEC_OFFSET*4)+4)/4,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ NormCCNode::~NormCCNode()
|
|||
|
||||
|
||||
NormServerNode::NormServerNode(class NormSession& theSession, NormNodeId nodeId)
|
||||
: NormNode(theSession, nodeId), session_id(0), synchronized(false), sync_id(0),
|
||||
: NormNode(theSession, nodeId), instance_id(0), synchronized(false), sync_id(0),
|
||||
max_pending_range(256), is_open(false), segment_size(0), ndata(0), nparity(0),
|
||||
repair_boundary(BLOCK_BOUNDARY), erasure_loc(NULL),
|
||||
retrieval_loc(NULL), retrieval_pool(NULL),
|
||||
|
|
@ -100,9 +100,9 @@ NormServerNode::~NormServerNode()
|
|||
Close();
|
||||
}
|
||||
|
||||
bool NormServerNode::Open(UINT16 sessionId)
|
||||
bool NormServerNode::Open(UINT16 instanceId)
|
||||
{
|
||||
session_id = sessionId;
|
||||
instance_id = instanceId;
|
||||
if (!rx_table.Init(max_pending_range))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() rx_table init error\n");
|
||||
|
|
@ -123,6 +123,7 @@ bool NormServerNode::Open(UINT16 sessionId)
|
|||
}
|
||||
is_open = true;
|
||||
synchronized = false;
|
||||
resync_count = 0; // reset resync_count
|
||||
return true;
|
||||
} // end NormServerNode::Open()
|
||||
|
||||
|
|
@ -178,7 +179,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
|
|||
|
||||
if (!block_pool.Init(numBlocks, blockSize))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() block_pool init error\n");
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() block_pool init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -188,7 +189,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
|
|||
// a NormStreamObject
|
||||
if (!segment_pool.Init(numSegments, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()+1))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() segment_pool init error\n");
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() segment_pool init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -198,7 +199,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
|
|||
// needed for block decoding (new rx buffer mgmt scheme)
|
||||
if (!(retrieval_pool = new char*[numData]))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() new retrieval_pool error: %s\n", GetErrorString());
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() new retrieval_pool error: %s\n", GetErrorString());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -208,7 +209,7 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
|
|||
char* s = new char[segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()];
|
||||
if (NULL == s)
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() new retrieval segment error: %s\n", GetErrorString());
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() new retrieval segment error: %s\n", GetErrorString());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -218,20 +219,20 @@ bool NormServerNode::AllocateBuffers(UINT16 segmentSize,
|
|||
|
||||
if (!(retrieval_loc = new UINT16[numData]))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() retrieval_loc allocation error: %s\n", GetErrorString());
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() retrieval_loc allocation error: %s\n", GetErrorString());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!decoder.Init(numParity, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() decoder init error\n");
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() decoder init error\n");
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
if (!(erasure_loc = new UINT16[numParity]))
|
||||
{
|
||||
DMSG(0, "NormServerNode::Open() erasure_loc allocation error: %s\n", GetErrorString());
|
||||
DMSG(0, "NormServerNode::AllocateBuffers() erasure_loc allocation error: %s\n", GetErrorString());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1006,6 +1007,8 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
|
||||
if (obj)
|
||||
{
|
||||
rx_table.Insert(obj);
|
||||
obj->Retain();
|
||||
NormFtiExtension fti;
|
||||
while (msg.GetNextExtension(fti))
|
||||
{
|
||||
|
|
@ -1021,8 +1024,6 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
session.Notify(NormController::RX_OBJECT_NEW, this, obj);
|
||||
if (obj->Accepted())
|
||||
{
|
||||
rx_table.Insert(obj);
|
||||
obj->Retain();
|
||||
// (TBD) Do I _need_ to call "StreamUpdateStatus()" here?
|
||||
if (obj->IsStream())
|
||||
(static_cast<NormStreamObject*>(obj))->StreamUpdateStatus(blockId);
|
||||
|
|
@ -1031,12 +1032,14 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() object not accepted\n");
|
||||
DeleteObject(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormServerNode::HandleObjectMessage() error opening object\n");
|
||||
DeleteObject(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
|
|
@ -1608,7 +1611,7 @@ bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/)
|
|||
}
|
||||
// Queue NACK for transmission
|
||||
nack->SetServerId(GetId());
|
||||
nack->SetSessionId(session_id);
|
||||
nack->SetInstanceId(instance_id);
|
||||
// GRTT response is deferred until transmit time
|
||||
|
||||
if (unicast_nacks)
|
||||
|
|
@ -1742,7 +1745,7 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
|
|||
NormObject* objMax = rx_table.Find(max_pending_object);
|
||||
if (NULL != objMax)
|
||||
{
|
||||
NormSegmentId segMax = objMax->GetMaxPendingSegmentId();
|
||||
/*NormSegmentId segMax = objMax->GetMaxPendingSegmentId();
|
||||
if (0 != segMax)
|
||||
RepairCheck(NormObject::THRU_SEGMENT,
|
||||
max_pending_object,
|
||||
|
|
@ -1752,7 +1755,10 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/)
|
|||
RepairCheck(NormObject::TO_BLOCK,
|
||||
max_pending_object,
|
||||
objMax->GetMaxPendingBlockId(),
|
||||
0);
|
||||
0);*/
|
||||
// Let's try this instead
|
||||
RepairCheck(NormObject::THRU_OBJECT, // (TBD) thru object???
|
||||
max_pending_object, 0, 0);
|
||||
}
|
||||
else
|
||||
RepairCheck(NormObject::TO_BLOCK, // (TBD) thru object???
|
||||
|
|
@ -1837,7 +1843,7 @@ bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/)
|
|||
}
|
||||
ack->Init();
|
||||
ack->SetServerId(GetId());
|
||||
ack->SetSessionId(session_id);
|
||||
ack->SetInstanceId(instance_id);
|
||||
ack->SetAckType(NormAck::CC);
|
||||
ack->SetAckId(0);
|
||||
|
||||
|
|
@ -1878,7 +1884,7 @@ bool NormServerNode::OnAckTimeout(ProtoTimer& /*theTimer*/)
|
|||
{
|
||||
ack->Init();
|
||||
ack->SetServerId(GetId());
|
||||
ack->SetSessionId(session_id);
|
||||
ack->SetInstanceId(instance_id);
|
||||
ack->SetAckId(0);
|
||||
AttachCCFeedback(*ack);
|
||||
ack->SetObjectId(watermark_object_id);
|
||||
|
|
|
|||
|
|
@ -245,8 +245,8 @@ class NormServerNode : public NormNode
|
|||
void HandleNackMessage(const NormNackMsg& nack);
|
||||
void HandleAckMessage(const NormAckMsg& ack);
|
||||
|
||||
bool Open(UINT16 sessionId);
|
||||
UINT16 GetSessionId() {return session_id;}
|
||||
bool Open(UINT16 instanceId);
|
||||
UINT16 GetInstanceId() {return instance_id;}
|
||||
bool IsOpen() const {return is_open;}
|
||||
void Close();
|
||||
bool AllocateBuffers(UINT16 segmentSize, UINT16 numData, UINT16 numParity);
|
||||
|
|
@ -371,7 +371,7 @@ class NormServerNode : public NormNode
|
|||
void AttachCCFeedback(NormAckMsg& ack);
|
||||
void HandleRepairContent(const UINT32* buffer, UINT16 bufferLen);
|
||||
|
||||
UINT16 session_id;
|
||||
UINT16 instance_id;
|
||||
bool synchronized;
|
||||
NormObjectId sync_id; // only valid if(synchronized)
|
||||
NormObjectId next_id; // only valid if(synchronized)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ void NormObject::Release()
|
|||
if (reference_count)
|
||||
reference_count--;
|
||||
else
|
||||
{
|
||||
DMSG(0, "NormObject::Release() releasing non-retained object?!\n");
|
||||
ASSERT(0);
|
||||
}
|
||||
if (0 == reference_count) delete this;
|
||||
} // end NormObject::Release()
|
||||
|
||||
|
|
@ -109,7 +112,7 @@ bool NormObject::Open(const NormObjectSize& objectSize,
|
|||
}
|
||||
|
||||
// Compute number of segments and coding blocks for the object
|
||||
// (Note NormObjectSize divide operator always rounds _up_)
|
||||
// (Note NormObjectSize divide operator always rounds _upwards_)
|
||||
NormObjectSize numSegments = objectSize / NormObjectSize(segmentSize);
|
||||
NormObjectSize numBlocks = numSegments / NormObjectSize(numData);
|
||||
ASSERT(0 == numBlocks.MSB());
|
||||
|
|
@ -124,7 +127,8 @@ bool NormObject::Open(const NormObjectSize& objectSize,
|
|||
// Init pending_mask (everything pending)
|
||||
if (!pending_mask.Init(numBlocks.LSB(), 0xffffffff))
|
||||
{
|
||||
DMSG(0, "NormObject::Open() init pending_mask error\n");
|
||||
DMSG(0, "NormObject::Open() init pending_mask (%lu) error: %s\n",
|
||||
numBlocks.GetOffset(), GetErrorString());
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
|
@ -206,7 +210,42 @@ void NormObject::Close()
|
|||
pending_mask.Destroy();
|
||||
block_buffer.Destroy();
|
||||
segment_size = 0;
|
||||
} // end NormObject::Close();
|
||||
} // end NormObject::Close()
|
||||
|
||||
NormObjectSize NormObject::GetBytesPending() const
|
||||
{
|
||||
NormObjectSize bytesCompleted;
|
||||
NormBlockId nextId;
|
||||
if (GetFirstPending(nextId))
|
||||
{
|
||||
NormObjectSize largeBlockBytes = NormObjectSize(large_block_size) *
|
||||
NormObjectSize(segment_size);
|
||||
NormObjectSize smallBlockBytes = NormObjectSize(small_block_size) *
|
||||
NormObjectSize(segment_size);
|
||||
NormObjectSize lastBlockBytes = smallBlockBytes - NormObjectSize(segment_size) +
|
||||
NormObjectSize(final_segment_size);
|
||||
NormObjectSize pendingBytes(0);
|
||||
do
|
||||
{
|
||||
NormBlock* block = block_buffer.Find(nextId);
|
||||
if (block)
|
||||
pendingBytes += block->GetBytesPending(GetBlockSize(nextId), segment_size,
|
||||
final_block_id, final_segment_size);
|
||||
else if ((UINT32)nextId < large_block_count)
|
||||
pendingBytes += largeBlockBytes;
|
||||
else if (nextId == final_block_id)
|
||||
pendingBytes += lastBlockBytes;
|
||||
else
|
||||
pendingBytes += smallBlockBytes;
|
||||
nextId++;
|
||||
} while (GetNextPending(nextId));
|
||||
return pendingBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NormObjectSize(0);
|
||||
}
|
||||
} // end NormObject::GetBytesCompleted()
|
||||
|
||||
// Used by server
|
||||
bool NormObject::HandleInfoRequest()
|
||||
|
|
@ -1732,7 +1771,7 @@ NormFileObject::NormFileObject(class NormSession& theSession,
|
|||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId)
|
||||
: NormObject(FILE, theSession, theServer, objectId),
|
||||
large_block_length(0,0), small_block_length(0,0)
|
||||
large_block_length(0), small_block_length(0)
|
||||
{
|
||||
path[0] = '\0';
|
||||
}
|
||||
|
|
@ -1775,7 +1814,7 @@ bool NormFileObject::Open(const char* thePath,
|
|||
// We're sending this file
|
||||
if (file.Open(thePath, O_RDONLY))
|
||||
{
|
||||
off_t size = file.GetSize();
|
||||
NormObjectSize::Offset size = file.GetSize();
|
||||
if (size)
|
||||
{
|
||||
if (!NormObject::Open(NormObjectSize(size),
|
||||
|
|
@ -1861,7 +1900,7 @@ bool NormFileObject::WriteSegment(NormBlockId blockId,
|
|||
segmentOffset = segmentOffset + small_block_length*smallBlockIndex +
|
||||
segmentSize*segmentId;
|
||||
}
|
||||
off_t offset = segmentOffset.GetOffset();
|
||||
NormFile::Offset offset = segmentOffset.GetOffset();
|
||||
if (offset != file.GetOffset())
|
||||
{
|
||||
if (!file.Seek(offset)) return false;
|
||||
|
|
@ -1903,9 +1942,7 @@ UINT16 NormFileObject::ReadSegment(NormBlockId blockId,
|
|||
segmentOffset = segmentOffset + small_block_length*smallBlockIndex +
|
||||
segmentSize*segmentId;
|
||||
}
|
||||
//off_t offsetScaleMSB = 0xffffffff + 1; // yuk! can't we do better
|
||||
//off_t offset = (off_t)segmentOffset.LSB() + ((off_t)segmentOffset.MSB() * offsetScaleMSB);
|
||||
off_t offset = segmentOffset.GetOffset();
|
||||
NormFile::Offset offset = segmentOffset.GetOffset();
|
||||
if (offset != file.GetOffset())
|
||||
{
|
||||
if (!file.Seek(offset))
|
||||
|
|
@ -1952,7 +1989,7 @@ NormDataObject::NormDataObject(class NormSession& theSession,
|
|||
class NormServerNode* theServer,
|
||||
const NormObjectId& objectId)
|
||||
: NormObject(DATA, theSession, theServer, objectId),
|
||||
large_block_length(0,0), small_block_length(0,0),
|
||||
large_block_length(0), small_block_length(0),
|
||||
data_ptr(NULL), data_max(0), data_released(false)
|
||||
{
|
||||
|
||||
|
|
@ -2709,9 +2746,9 @@ bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool findMsgStar
|
|||
{
|
||||
if (stream_closing)
|
||||
{
|
||||
DMSG(0, "NormStreamObject::Read() attempted to read from closed stream\n");
|
||||
DMSG(4, "NormStreamObject::Read() attempted to read from closed stream\n");
|
||||
*buflen = 0;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
Retain();
|
||||
SetNotifyOnUpdate(true); // reset notification when streams are read
|
||||
|
|
@ -3220,7 +3257,7 @@ char* NormSimObject::RetrieveSegment(NormBlockId blockId,
|
|||
|
||||
NormObjectTable::NormObjectTable()
|
||||
: table((NormObject**)NULL), range_max(0), range(0),
|
||||
count(0), size(0,0)
|
||||
count(0), size(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ class NormObject
|
|||
small_block_size);
|
||||
}
|
||||
|
||||
NormObjectSize GetBytesPending() const;
|
||||
|
||||
bool IsPending(bool flush = true) const;
|
||||
bool IsRepairPending() const;
|
||||
bool IsPendingInfo() {return pending_info;}
|
||||
|
|
@ -542,7 +544,7 @@ class NormObjectTable
|
|||
NormObjectId RangeHi() const {return range_hi;}
|
||||
bool IsEmpty() const {return (0 == range);}
|
||||
UINT32 Count() const {return count;}
|
||||
const NormObjectSize& Size() const {return size;}
|
||||
const NormObjectSize& GetSize() const {return size;}
|
||||
|
||||
class Iterator
|
||||
{
|
||||
|
|
|
|||
|
|
@ -474,6 +474,34 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd,
|
|||
return true;
|
||||
} // end NormBlock::AppendRepairAdv()
|
||||
|
||||
NormObjectSize NormBlock::GetBytesPending(UINT16 numData,
|
||||
UINT16 segmentSize,
|
||||
NormBlockId finalBlockId,
|
||||
UINT16 finalSegmentSize) const
|
||||
{
|
||||
NormObjectSize pendingBytes(0);
|
||||
NormSegmentId nextId;
|
||||
if (GetFirstPending(nextId))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (nextId < numData)
|
||||
pendingBytes += NormObjectSize(segmentSize);
|
||||
else
|
||||
break;
|
||||
nextId++;
|
||||
} while (GetNextPending(nextId));
|
||||
}
|
||||
// Correct for final_segment_size, if applicable
|
||||
if ((id == finalBlockId) &&
|
||||
(IsPending(numData - 1)))
|
||||
{
|
||||
pendingBytes -= NormObjectSize(segmentSize);
|
||||
pendingBytes += NormObjectSize(finalSegmentSize);
|
||||
}
|
||||
return pendingBytes;
|
||||
} // end NormBlock::GetBytesPending()
|
||||
|
||||
// Called by client
|
||||
// (TBD) this should return true iff something appended, false otherwise
|
||||
bool NormBlock::AppendRepairRequest(NormNackMsg& nack,
|
||||
|
|
|
|||
|
|
@ -219,6 +219,11 @@ class NormBlock
|
|||
bool IsTransmitPending() const
|
||||
{return (pending_mask.IsSet() || repair_mask.IsSet());}
|
||||
|
||||
NormObjectSize GetBytesPending(UINT16 numData,
|
||||
UINT16 segmentSize,
|
||||
NormBlockId finalBlockId,
|
||||
UINT16 finalSegmentSize) const;
|
||||
|
||||
bool AppendRepairRequest(NormNackMsg& nack,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId)
|
|||
rx_socket(ProtoSocket::UDP), local_node_id(localNodeId),
|
||||
ttl(DEFAULT_TTL), loopback(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), session_id(0),
|
||||
backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), instance_id(0),
|
||||
ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0),
|
||||
next_tx_object_id(0), tx_cache_count_min(8), tx_cache_count_max(256),
|
||||
tx_cache_size_max((UINT32)20*1024*1024),
|
||||
|
|
@ -269,7 +269,8 @@ void NormSession::SetTxRateBounds(double rateMin, double rateMax)
|
|||
} // end NormSession::SetTxRateBounds()
|
||||
|
||||
|
||||
bool NormSession::StartServer(UINT32 bufferSpace,
|
||||
bool NormSession::StartServer(UINT16 instanceId,
|
||||
UINT32 bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
@ -337,6 +338,7 @@ bool NormSession::StartServer(UINT32 bufferSpace,
|
|||
}
|
||||
}
|
||||
|
||||
instance_id = instanceId;
|
||||
segment_size = segmentSize;
|
||||
sent_rate = 0.0;
|
||||
prev_update_time.tv_sec = prev_update_time.tv_usec = 0;
|
||||
|
|
@ -622,6 +624,10 @@ void NormSession::Serve()
|
|||
{
|
||||
DMSG(6, "NormSession::Serve() node>%lu server flush complete ...\n",
|
||||
LocalNodeId());
|
||||
|
||||
Notify(NormController::TX_FLUSH_COMPLETED,
|
||||
(NormServerNode*)NULL,
|
||||
(NormObject*)NULL);
|
||||
flush_count++;
|
||||
}
|
||||
}
|
||||
|
|
@ -993,7 +999,7 @@ bool NormSession::QueueTxObject(NormObject* obj)
|
|||
unsigned long count = tx_table.Count();
|
||||
while ((count >= tx_cache_count_min) &&
|
||||
((count >= tx_cache_count_max) ||
|
||||
((tx_table.Size() + obj->GetSize()) > tx_cache_size_max)))
|
||||
((tx_table.GetSize() + obj->GetSize()) > tx_cache_size_max)))
|
||||
{
|
||||
// Remove oldest non-pending
|
||||
NormObject* oldest = tx_table.Find(tx_table.RangeLo());
|
||||
|
|
@ -1173,9 +1179,6 @@ void NormTrace(const struct timeval& currentTime,
|
|||
"CMD(ACK_REQ)",
|
||||
"CMD(APP)"
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const char* REQ_NAME[] =
|
||||
{
|
||||
"INVALID",
|
||||
|
|
@ -1202,26 +1205,26 @@ void NormTrace(const struct timeval& currentTime,
|
|||
#else
|
||||
struct tm* ct = gmtime((time_t*)¤tTime.tv_sec);
|
||||
#endif // if/else _WIN32_WCE
|
||||
DMSG(0, "trace>%02d:%02d:%02d.%06lu node>%lu %s>%s seq>%hu ",
|
||||
DMSG(0, "trace>%02d:%02d:%02d.%06lu node>%lu %s>%s ",
|
||||
ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec,
|
||||
(UINT32)localId, status, addr.GetHostString(), seq);
|
||||
(UINT32)localId, status, addr.GetHostString());
|
||||
bool clrFlag = false;
|
||||
switch (msgType)
|
||||
{
|
||||
case NormMsg::INFO:
|
||||
{
|
||||
const NormInfoMsg& info = (const NormInfoMsg&)msg;
|
||||
DMSG(0, "INFO obj>%hu ", (UINT16)info.GetObjectId());
|
||||
DMSG(0, "inst>%hu seq>%hu INFO obj>%hu ",
|
||||
info.GetInstanceId(), seq, (UINT16)info.GetObjectId());
|
||||
break;
|
||||
}
|
||||
case NormMsg::DATA:
|
||||
{
|
||||
const NormDataMsg& data = (const NormDataMsg&)msg;
|
||||
if (data.IsData())
|
||||
DMSG(0, "DATA ");
|
||||
else
|
||||
DMSG(0, "PRTY ");
|
||||
DMSG(0, "obj>%hu blk>%lu seg>%hu ",
|
||||
DMSG(0, "inst>%hu seq>%hu %s obj>%hu blk>%lu seg>%hu ",
|
||||
data.GetInstanceId(),
|
||||
seq,
|
||||
data.IsData() ? "DATA" : "PRTY",
|
||||
(UINT16)data.GetObjectId(),
|
||||
(UINT32)data.GetFecBlockId(),
|
||||
(UINT16)data.GetFecSymbolId());
|
||||
|
|
@ -1242,8 +1245,9 @@ void NormTrace(const struct timeval& currentTime,
|
|||
}
|
||||
case NormMsg::CMD:
|
||||
{
|
||||
NormCmdMsg::Flavor flavor = ((const NormCmdMsg&)msg).GetFlavor();
|
||||
DMSG(0, "%s ", CMD_NAME[flavor]);
|
||||
const NormCmdMsg& cmd = static_cast<const NormCmdMsg&>(msg);
|
||||
NormCmdMsg::Flavor flavor = cmd.GetFlavor();
|
||||
DMSG(0, "inst>%hu seq>%hu %s ", cmd.GetInstanceId(), seq, CMD_NAME[flavor]);
|
||||
switch (flavor)
|
||||
{
|
||||
case NormCmdMsg::ACK_REQ:
|
||||
|
|
@ -1255,7 +1259,8 @@ void NormTrace(const struct timeval& currentTime,
|
|||
}
|
||||
case NormCmdMsg::SQUELCH:
|
||||
{
|
||||
const NormCmdSquelchMsg& squelch = (const NormCmdSquelchMsg&)msg;
|
||||
const NormCmdSquelchMsg& squelch =
|
||||
static_cast<const NormCmdSquelchMsg&>(msg);
|
||||
DMSG(0, " obj>%hu blk>%lu seg>%hu ",
|
||||
(UINT16)squelch.GetObjectId(),
|
||||
(UINT32)squelch.GetFecBlockId(),
|
||||
|
|
@ -1264,7 +1269,8 @@ void NormTrace(const struct timeval& currentTime,
|
|||
}
|
||||
case NormCmdMsg::FLUSH:
|
||||
{
|
||||
const NormCmdFlushMsg& flush = (const NormCmdFlushMsg&)msg;
|
||||
const NormCmdFlushMsg& flush =
|
||||
static_cast<const NormCmdFlushMsg&>(msg);
|
||||
DMSG(0, " obj>%hu blk>%lu seg>%hu ",
|
||||
(UINT16)flush.GetObjectId(),
|
||||
(UINT32)flush.GetFecBlockId(),
|
||||
|
|
@ -1273,7 +1279,8 @@ void NormTrace(const struct timeval& currentTime,
|
|||
}
|
||||
case NormCmdMsg::CC:
|
||||
{
|
||||
const NormCmdCCMsg& cc = (const NormCmdCCMsg&)msg;
|
||||
const NormCmdCCMsg& cc =
|
||||
static_cast<const NormCmdCCMsg&>(msg);
|
||||
DMSG(0, " seq>%u ", cc.GetCCSequence());
|
||||
NormHeaderExtension ext;
|
||||
while (cc.GetNextExtension(ext))
|
||||
|
|
@ -1382,12 +1389,12 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
|||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||
if (theServer)
|
||||
{
|
||||
if (msg.GetSessionId() != theServer->GetSessionId())
|
||||
if (msg.GetInstanceId() != theServer->GetInstanceId())
|
||||
{
|
||||
DMSG(2, "NormSession::ClientHandleObjectMessage() node>%lu server>%lu sessionId change - resyncing.\n",
|
||||
DMSG(2, "NormSession::ClientHandleObjectMessage() node>%lu server>%lu instanceId change - resyncing.\n",
|
||||
LocalNodeId(), theServer->GetId());
|
||||
theServer->Close();
|
||||
if (!theServer->Open(msg.GetSessionId()))
|
||||
if (!theServer->Open(msg.GetInstanceId()))
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleObjectMessage() node>%lu error re-opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
|
|
@ -1400,7 +1407,7 @@ void NormSession::ClientHandleObjectMessage(const struct timeval& currentTime,
|
|||
if ((theServer = new NormServerNode(*this, msg.GetSourceId())))
|
||||
{
|
||||
Notify(NormController::REMOTE_SERVER_NEW, theServer, NULL);
|
||||
if (theServer->Open(msg.GetSessionId()))
|
||||
if (theServer->Open(msg.GetInstanceId()))
|
||||
{
|
||||
server_tree.AttachNode(theServer);
|
||||
theServer->Retain();
|
||||
|
|
@ -1438,12 +1445,12 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
|||
NormServerNode* theServer = (NormServerNode*)server_tree.FindNodeById(sourceId);
|
||||
if (theServer)
|
||||
{
|
||||
if (cmd.GetSessionId() != theServer->GetSessionId())
|
||||
if (cmd.GetInstanceId() != theServer->GetInstanceId())
|
||||
{
|
||||
DMSG(2, "NormSession::ClientHandleCommand() node>%lu server>%lu sessionId change - resyncing.\n",
|
||||
DMSG(2, "NormSession::ClientHandleCommand() node>%lu server>%lu instanceId change - resyncing.\n",
|
||||
LocalNodeId(), theServer->GetId());
|
||||
theServer->Close();
|
||||
if (!theServer->Open(cmd.GetSessionId()))
|
||||
if (!theServer->Open(cmd.GetInstanceId()))
|
||||
{
|
||||
DMSG(0, "NormSession::ClientHandleCommand() node>%lu error re-opening NormServerNode\n");
|
||||
// (TBD) notify application of error
|
||||
|
|
@ -1457,7 +1464,8 @@ void NormSession::ClientHandleCommand(const struct timeval& currentTime,
|
|||
// LocalNodeId());
|
||||
if ((theServer = new NormServerNode(*this, cmd.GetSourceId())))
|
||||
{
|
||||
if (theServer->Open(cmd.GetSessionId()))
|
||||
Notify(NormController::REMOTE_SERVER_NEW, theServer, NULL);
|
||||
if (theServer->Open(cmd.GetInstanceId()))
|
||||
{
|
||||
server_tree.AttachNode(theServer);
|
||||
theServer->Retain();
|
||||
|
|
@ -2645,16 +2653,16 @@ bool NormSession::SendMessage(NormMsg& msg)
|
|||
bool isProbe = false;
|
||||
|
||||
// Fill in any last minute timestamps
|
||||
// (TBD) fill in SessionId fields on all messages as needed
|
||||
// (TBD) fill in InstanceId fields on all messages as needed
|
||||
switch (msg.GetType())
|
||||
{
|
||||
case NormMsg::INFO:
|
||||
case NormMsg::DATA:
|
||||
((NormObjectMsg&)msg).SetSessionId(session_id);
|
||||
((NormObjectMsg&)msg).SetInstanceId(instance_id);
|
||||
msg.SetSequence(tx_sequence++); // (TBD) set for session dst msgs
|
||||
break;
|
||||
case NormMsg::CMD:
|
||||
((NormCmdMsg&)msg).SetSessionId(session_id);
|
||||
((NormCmdMsg&)msg).SetInstanceId(instance_id);
|
||||
switch (((NormCmdMsg&)msg).GetFlavor())
|
||||
{
|
||||
case NormCmdMsg::CC:
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class NormController
|
|||
EVENT_INVALID = 0,
|
||||
TX_QUEUE_VACANCY,
|
||||
TX_QUEUE_EMPTY,
|
||||
TX_FLUSH_COMPLETED,
|
||||
TX_OBJECT_SENT,
|
||||
TX_OBJECT_PURGED,
|
||||
LOCAL_SERVER_CLOSED,
|
||||
|
|
@ -158,10 +159,11 @@ class NormSession
|
|||
void ServerSetBaseObjectId(NormObjectId baseId)
|
||||
{
|
||||
next_tx_object_id = IsServer() ? next_tx_object_id : baseId;
|
||||
session_id = IsServer() ? session_id : (UINT16)baseId;
|
||||
//instance_id = IsServer() ? instance_id : (UINT16)baseId;
|
||||
}
|
||||
bool IsServer() {return is_server;}
|
||||
bool StartServer(UINT32 bufferSpace,
|
||||
bool StartServer(UINT16 instanceId,
|
||||
UINT32 bufferSpace,
|
||||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity,
|
||||
|
|
@ -363,7 +365,7 @@ class NormSession
|
|||
|
||||
// Server parameters and state
|
||||
bool is_server;
|
||||
UINT16 session_id;
|
||||
UINT16 instance_id;
|
||||
UINT16 segment_size;
|
||||
UINT16 ndata;
|
||||
UINT16 nparity;
|
||||
|
|
|
|||
|
|
@ -15,12 +15,7 @@
|
|||
#endif // UNIX
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
printf("normTest starting ...\n");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
printf("normTest starting (sizeof(NormOffset) = %d)...\n", sizeof(NormOffset));
|
||||
|
||||
NormInstanceHandle instance = NormCreateInstance();
|
||||
|
||||
|
|
@ -40,17 +35,18 @@ int main(int argc, char* argv[])
|
|||
// NOTE: These are debugging routines available (not for normal app use)
|
||||
SetDebugLevel(2);
|
||||
// Uncomment to turn on debug NORM message tracing
|
||||
NormSetMessageTrace(session, true);
|
||||
//NormSetMessageTrace(session, true);
|
||||
// Uncomment to turn on some random packet loss
|
||||
//NormSetTxLoss(session, 1.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
|
||||
//srand(currentTime.tv_sec); // seed random number generator
|
||||
// (and a different sender sessionId)
|
||||
srand(currentTime.tv_sec); // seed random number generator
|
||||
|
||||
NormSetGrttEstimate(session, 0.001); // 1 msec initial grtt
|
||||
|
||||
NormSetTransmitRate(session, 60.0e+06); // in bits/second
|
||||
NormSetTransmitRate(session, 60.0e+03); // in bits/second
|
||||
|
||||
NormSetDefaultRepairBoundary(session, NORM_BOUNDARY_BLOCK);
|
||||
|
||||
|
|
@ -64,7 +60,7 @@ int main(int argc, char* argv[])
|
|||
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)
|
||||
|
|
@ -73,8 +69,12 @@ int main(int argc, char* argv[])
|
|||
// Uncomment to enable TCP-friendly congestion control
|
||||
//NormSetCongestionControl(session, true);
|
||||
|
||||
// We use a random "sessionId"
|
||||
NormSessionId sessionId = (NormSessionId)rand();
|
||||
|
||||
|
||||
// Uncomment the following line to start sender
|
||||
NormStartSender(session, 4096*1024, 1400, 64, 0);
|
||||
NormStartSender(session, sessionId, 4096*1024, 1400, 64, 0);
|
||||
|
||||
// Uncomment to set large tx socket buffer size
|
||||
// (might be needed for high rate sessions)
|
||||
|
|
@ -87,7 +87,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, 4096*1024);
|
||||
|
||||
// NORM_FLUSH_PASSIVE automatically flushes full writes to
|
||||
// the stream.
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@
|
|||
|
||||
#ifndef _NORM_VERSION
|
||||
#define _NORM_VERSION
|
||||
#define VERSION "1.3b2"
|
||||
#define VERSION "1.3b3"
|
||||
#endif // _NORM_VERSION
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
NORM API Examples
|
||||
=================
|
||||
|
||||
This directory contains some purposely simplified examples of NORM
|
||||
API usage. See comments in the source code files on how to build
|
||||
these on Unix platforms. Eventually, "Makefiles" (and hopefully
|
||||
"configure" scripts) will be provided as well as Visual C++
|
||||
project files for Win32 builds.
|
||||
|
||||
The following example programs are included:
|
||||
|
||||
|
||||
normFileSend.cpp - simple file transmission program. Sends one
|
||||
file and exits.
|
||||
|
||||
normFileRecv.cpp - simple file reception program. Receives one
|
||||
file and exits.
|
||||
|
||||
(These two programs use a hard-coded multicast address and port,
|
||||
but take a file name and directory name, respectively, as a
|
||||
command-line argument to determine the file sent and the
|
||||
directory to which receive files are stored.)
|
||||
|
||||
|
||||
Other examples will be added later including examples using the
|
||||
"NormGetDescriptor()" function to allow NORM API events to be
|
||||
multiplexed with other possible application events (e.g. other I/O
|
||||
or Windows messages, etc).
|
||||
|
||||
------------- Brian Adamson <mailto:adamson@itd.nrl.navy.mil> 9
|
||||
June 2005
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
/******************************************************************************
|
||||
Simple NORM file receiver example app using the NORM API
|
||||
|
||||
USAGE:
|
||||
|
||||
normRecvFile <rxCacheDirectory>
|
||||
|
||||
BUILD (Unix):
|
||||
|
||||
g++ -o normRecvFile normRecvFile.cpp -I../common/ -I../protolib/common \
|
||||
-DPROTO_DEBUG ../unix/libnorm.a ../protolib/unix/libProtokit.a -lpthread
|
||||
|
||||
(for MacOS/BSD, add "-lresolv")
|
||||
(for Solaris, add "-ldl -lnsl -lsocket -lresolv")
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
// Notes:
|
||||
// 1) The program exits once a single file has been received ...
|
||||
// 2) The received file is written to the <rxCacheDirectory>
|
||||
// 3) The program also will exit on <CTRL-C> from user
|
||||
// 4) "normFileRecv" should be started before "normFileSend"
|
||||
|
||||
#include "normApi.h" // for NORM API
|
||||
|
||||
#include "protoDefs.h" // for ProtoSystemTime
|
||||
#include "protoDebug.h" // for SetDebugLevel(), etc
|
||||
|
||||
#include <stdio.h> // for printf(), etc
|
||||
#include <stdlib.h> // for srand()
|
||||
#include <string.h> // for strrchr()
|
||||
|
||||
#ifdef WIN32
|
||||
const char DIR_DELIMITER = '\\';
|
||||
#else
|
||||
const char DIR_DELIMITER = '/';
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// 0) The rxCachePath should be argv[1] ...
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "normFileRecv error: invalid argument(s)\n");
|
||||
fprintf(stderr, "Usage: normRecvFile <rxCachePath>\n");
|
||||
return -1;
|
||||
}
|
||||
const char* rxCachePath = argv[1];
|
||||
|
||||
// 1) Create a NORM API "NormInstance"
|
||||
NormInstanceHandle instance = NormCreateInstance();
|
||||
|
||||
// 2) Create a NormSession using default "automatic" local node id
|
||||
NormSessionHandle session = NormCreateSession(instance,
|
||||
"224.1.2.3",
|
||||
6003,
|
||||
NORM_NODE_ANY);
|
||||
|
||||
// NOTE: These are debugging routines available
|
||||
// (not necessary for normal app use)
|
||||
// (Need to include "protolib/common/protoDebug.h" for this
|
||||
//SetDebugLevel(2);
|
||||
// Uncomment to turn on debug NORM message tracing
|
||||
//NormSetMessageTrace(session, true);
|
||||
// Uncomment to turn on some random packet loss for testing
|
||||
//NormSetRxLoss(session, 10.0); // 10% packet loss
|
||||
struct timeval currentTime;
|
||||
ProtoSystemTime(currentTime);
|
||||
// Uncomment to get different packet loss patterns from run to run
|
||||
srand(currentTime.tv_sec); // seed random number generator
|
||||
|
||||
// 3) Set receiver file cache path (where received files are mstored)
|
||||
if (!NormSetCacheDirectory(instance, rxCachePath))
|
||||
{
|
||||
fprintf(stderr, "normFileReceive: error setting cache directory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 4) Start the receiver with 1 Mbyte buffer per sender
|
||||
NormStartReceiver(session, 1024*1024);
|
||||
|
||||
// 5) Enter NORM event loop
|
||||
bool keepGoing = true;
|
||||
NormEvent theEvent;
|
||||
while (keepGoing && NormGetNextEvent(instance, &theEvent))
|
||||
{
|
||||
switch (theEvent.type)
|
||||
{
|
||||
case NORM_RX_OBJECT_NEW:
|
||||
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_NEW event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_INFO:
|
||||
// Assume info contains '/' delimited <path/fileName> string
|
||||
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_INFO event ...\n");
|
||||
if (NORM_OBJECT_FILE == NormObjectGetType(theEvent.object))
|
||||
{
|
||||
char fileName[PATH_MAX];
|
||||
strcpy(fileName, rxCachePath);
|
||||
int pathLen = strlen(fileName);
|
||||
if (DIR_DELIMITER != fileName[pathLen-1])
|
||||
{
|
||||
fileName[pathLen++] = DIR_DELIMITER;
|
||||
fileName[pathLen] = '\0';
|
||||
}
|
||||
unsigned short nameLen = PATH_MAX - pathLen;
|
||||
nameLen = NormObjectGetInfo(theEvent.object, fileName+pathLen, nameLen);
|
||||
fileName[nameLen + pathLen] = '\0';
|
||||
char* ptr = fileName + 5;
|
||||
while ('\0' != *ptr)
|
||||
{
|
||||
if ('/' == *ptr) *ptr = DIR_DELIMITER;
|
||||
ptr++;
|
||||
}
|
||||
if (!NormFileRename(theEvent.object, fileName))
|
||||
fprintf(stderr, "normFileRecv: NormSetFileName(%s) error\n", fileName);
|
||||
}
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_UPDATED:
|
||||
{
|
||||
//fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_UPDATE event ...\n");
|
||||
// Uncomment this stuff to monitor file receive progress
|
||||
// (At high packet rates, you may want to be careful here and
|
||||
// only calculate/post updates occasionally rather than for
|
||||
// each and every RX_OBJECT_UPDATE event)
|
||||
NormSize objectSize = NormObjectGetSize(theEvent.object);
|
||||
NormSize completed = objectSize - NormObjectGetBytesPending(theEvent.object);
|
||||
double percentComplete = 100.0 * ((double)completed/(double)objectSize);
|
||||
fprintf(stderr, "normFileRecv: completion status %lu/%lu (%3.0lf%%)\n",
|
||||
completed, objectSize, percentComplete);
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_RX_OBJECT_COMPLETED:
|
||||
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_COMPLETED event ...\n");
|
||||
keepGoing = false;
|
||||
break;
|
||||
|
||||
case NORM_RX_OBJECT_ABORTED:
|
||||
fprintf(stderr, "normFileRecv: NORM_RX_OBJECT_ABORTED event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_REMOTE_SERVER_NEW:
|
||||
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_NEW event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_REMOTE_SERVER_ACTIVE:
|
||||
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_ACTIVE event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_REMOTE_SERVER_INACTIVE:
|
||||
fprintf(stderr, "normFileRecv: NORM_REMOTE_SERVER_INACTIVE event ...\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "normFileRecv: Got event type: %d\n", theEvent.type);
|
||||
} // end switch(theEvent.type)
|
||||
}
|
||||
NormStopReceiver(session);
|
||||
NormDestroySession(session);
|
||||
NormDestroyInstance(instance);
|
||||
|
||||
fprintf(stderr, "normFileRecv: Done.\n");
|
||||
return 0;
|
||||
} // end main()
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/******************************************************************************
|
||||
Simple NORM file sender example app using the NORM API
|
||||
|
||||
USAGE:
|
||||
|
||||
normSendFile <fileName>
|
||||
|
||||
BUILD (Unix):
|
||||
|
||||
g++ -o normFileSend normFileSend.cpp -I../common/ -I../protolib/common \
|
||||
../unix/libnorm.a ../protolib/unix/libProtokit.a -lpthread
|
||||
|
||||
(for MacOS/BSD, add "-lresolv")
|
||||
(for Solaris, add "-ldl -lnsl -lsocket -lresolv")
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
// Notes:
|
||||
// 1) A single file is sent.
|
||||
// 2) The program exits upon NORM_TX_FLUSH_COMPLETED notification (or user <CTRL-C>)
|
||||
// 3) NORM receiver should be started first (before sender starts)
|
||||
|
||||
|
||||
#include "normApi.h" // for NORM API
|
||||
|
||||
#include "protoDefs.h" // for ProtoSystemTime
|
||||
#include "protoDebug.h" // for SetDebugLevel(), etc
|
||||
|
||||
#include <stdio.h> // for printf(), etc
|
||||
#include <stdlib.h> // for srand()
|
||||
#include <string.h> // for strrchr()
|
||||
|
||||
#ifdef WIN32
|
||||
const char DIR_DELIMITER = '\\';
|
||||
#else
|
||||
const char DIR_DELIMITER = '/';
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// 0) The filePath should be argv[1] ...
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "normFileSend error: invalid argument(s)\n");
|
||||
fprintf(stderr, "Usage: normFileSend <file>\n");
|
||||
return -1;
|
||||
}
|
||||
const char* filePath = argv[1];
|
||||
// Here we determine the "name" portion of the filePath
|
||||
// (The file "name" is later used for NORM_INFO content)
|
||||
const char* fileName = strrchr(filePath, DIR_DELIMITER);
|
||||
if (fileName)
|
||||
fileName++;
|
||||
else
|
||||
fileName = filePath;
|
||||
|
||||
|
||||
// 1) Create a NORM API "NormInstance"
|
||||
NormInstanceHandle instance = NormCreateInstance();
|
||||
|
||||
// 2) Create a NormSession using default "automatic" local node id
|
||||
NormSessionHandle session = NormCreateSession(instance,
|
||||
"224.1.2.3",
|
||||
6003,
|
||||
NORM_NODE_ANY);
|
||||
|
||||
// NOTE: These are some debugging routines available
|
||||
// (not necessary for normal app use)
|
||||
// (Need to include "protolib/common/protoDebug.h" for this
|
||||
//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
|
||||
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
|
||||
|
||||
// 3) Set transmission rate
|
||||
NormSetTransmitRate(session, 256.0e+03); // in bits/second
|
||||
|
||||
// Uncomment to use a _specific_ transmit port number
|
||||
// (Can be the same as session port (rx port), but this
|
||||
// is _not_ recommended when unicast feedback may be
|
||||
// possible! - must be called _before_ NormStartSender())
|
||||
//NormSetTxPort(session, 6001);
|
||||
|
||||
// Uncomment to enable TCP-friendly congestion control
|
||||
//NormSetCongestionControl(session, true);
|
||||
|
||||
// 4) Start the sender using a random "sessionId"
|
||||
NormSessionId sessionId = (NormSessionId)rand();
|
||||
NormStartSender(session, sessionId, 1024*1024, 1400, 64, 16);
|
||||
|
||||
// Uncomment to set large tx socket buffer size
|
||||
// (might be needed for high rate sessions)
|
||||
//NormSetTxSocketBuffer(session, 512000);
|
||||
|
||||
|
||||
// 5) Enqueue the file for transmission
|
||||
// (We use the file _name_ for NORM_INFO)
|
||||
//
|
||||
NormObjectHandle txFile =
|
||||
NormFileEnqueue(session, filePath,
|
||||
fileName, strlen(fileName));
|
||||
|
||||
// 6) Enter NORM event loop
|
||||
bool keepGoing = true;
|
||||
NormEvent theEvent;
|
||||
while (keepGoing && NormGetNextEvent(instance, &theEvent))
|
||||
{
|
||||
switch (theEvent.type)
|
||||
{
|
||||
case NORM_TX_QUEUE_VACANCY:
|
||||
fprintf(stderr, "normFileSend: NORM_TX_QUEUE_VACANCY event...\n");
|
||||
break;
|
||||
case NORM_TX_QUEUE_EMPTY:
|
||||
fprintf(stderr, "normFileSend: NORM_TX_QUEUE_EMPTY event...\n");
|
||||
break;
|
||||
|
||||
case NORM_TX_OBJECT_PURGED:
|
||||
fprintf(stderr, "normFileSend: NORM_TX_OBJECT_PURGED event ...\n");
|
||||
break;
|
||||
|
||||
case NORM_TX_FLUSH_COMPLETED:
|
||||
fprintf(stderr, "normFileSend: NORM_TX_FLUSH_COMPLETED event ...\n");
|
||||
keepGoing = false; // our file has been sent (we think)
|
||||
break;
|
||||
|
||||
default:
|
||||
TRACE("normFileSend: Got event type: %d\n", theEvent.type);
|
||||
} // end switch(theEvent.type)
|
||||
} // end while (NormGetNextEvent())
|
||||
|
||||
NormStopSender(session);
|
||||
NormDestroySession(session);
|
||||
NormDestroyInstance(instance);
|
||||
|
||||
fprintf(stderr, "normFileSend: Done.\n");
|
||||
return 0;
|
||||
} // end main()
|
||||
BIN
win32/Norm.suo
BIN
win32/Norm.suo
Binary file not shown.
BIN
wince/Norm.vco
BIN
wince/Norm.vco
Binary file not shown.
Loading…
Reference in New Issue