diff --git a/NormDeveloperGuide.html b/NormDeveloperGuide.html new file mode 100644 index 0000000..9fb2954 --- /dev/null +++ b/NormDeveloperGuide.html @@ -0,0 +1,2885 @@ + + + + + NORM Developer’s Guide + + + + + + + + + + + + + + + + +
+

+
+

+ NORM
Developer’s +
Guide

+
+

Background

+

This document describes +an application programming interface (API) for the Nack-Oriented +Reliable Multicast (NORM) protocol implementation developed by the +United States Naval Research Laboratory (NRL). The NORM protocol +provides general purpose reliable data transport for applications +wishing to use Internet Protocol (IP) Multicast services for group +data delivery. NORM can also support unicast (point-to-point) data +communication and may be used for such when deemed appropriate.

+

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 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 +control scheme is specified to allow the NORM protocol fairly share +available network bandwidth with other transport protocols such as +Transmission Control Protocol (TCP). It is capable of operating with +both reciprocal multicast routing among senders and receivers and +with asymmetric connectivity (possibly a unicast return path) from +the senders to receivers. The protocol offers a number of features +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.

+

Table +of Contents

+
+

Overview

+

API + Initialization

+

Session + Creation and Control

+

NORM + Data Transport

+

NORM + Data Transmission

+

NORM + Data Reception

+

API + Event Notification

+

API + Reference

+

API + Variable Types and Constants

+

NormInstanceHandle

+

NormSessionHandle

+

NormNodeHandle

+

NormNodeId

+

NormObjectHandle

+

NormObjectType

+

NormObjectTransportId

+

NormEventType

+

NormEvent

+

API + Initialization

+

NormCreateInstance()

+

NormDestroyInstance()

+

NormSetCacheDirectory()

+

NormGetNextEvent()

+

NormGetDescriptor()

+

Session + Creation and Control

+

NormCreateSession()

+

NormDestroySession()

+

NormGetLocalNodeId()

+

NormSetMulticastInterface()

+

NormSetTTL()

+

NormSetTOS()

+

NormSetLoopback()

+

NORM + Sender Functions

+

NormStartSender()

+

NormStopSender()

+

NormSetTransmitRate()

+

NormSetCongestionControl()

+

NormSetTransmitRateBounds()

+

NormSetAutoParity()

+

NormSetGrttEstimate()

+

NormAddAckingNode()

+

NormRemoveAckingNode()

+

NormFileEnqueue()

+

NormDataEnqueue()

+

NormStreamOpen()

+

NormStreamClose()

+

NormStreamWrite()

+

NormStreamFlush()

+

NormStreamSetAutoFlush()

+

NormStreamSetPushEnable()

+

NormStreamMarkEom()

+

NormSetWatermark()

+

NORM + Receiver Functions

+

NormStartReceiver()

+

NormStopReceiver()

+

NormSetSilentReceiver()

+

NormSetDefaultUnicastNack()

+

NormNodeSetUnicastNack()

+

NormSetDefaultNackingMode()

+

NormNodeSetNackingMode()

+

NormObjectSetNackingMode()

+

NormSetDefaultRepairBoundary()

+

NormNodeSetRepairBoundary()

+

NormStreamRead()

+

NormStreamSeekMsgStart()

+

NormStreamGetReadOffset()

+

NORM + Object Functions

+

NormObjectGetType()

+

NormObjectHasInfo()

+

NormObjectGetInfoLength()

+

NormObjectGetInfo()

+

NormObjectGetSize()

+

NormObjectCancel()

+

NormObjectRetain()

+

NormObjectRelease()

+

NormFileGetName()

+

NormFileRename()

+

NormDataAccessData()

+

NormDataDetachData()

+

NormObjectGetSender()

+

NORM + Node Functions

+

NormNodeGetId()

+

NormNodeRetain()

+

NormNodeRelease()

+
+

Overview

+

The NORM API has been +designed to provide simple, straightforward access to and control of +NORM protocol state and functions. Functions are provided to create +and initialize instances of the NORM API and associated transport +sessions (NormSessions). Subsequently, NORM data +transmission (NormSender) operation can be activated and the +application can queue various types of data (NormObjects) for +reliable transport. Additionally or alternatively, NORM reception +(NormReceiver) operation can also be enabled on a per-session +basis and the protocol implementation alerts the application of +receive events.

+

By default, the NORM +API will create an operating system thread in which the NORM protocol +engine runs. This allows user application code and the underlying +NORM code to execute somewhat independently of one another. The NORM +protocol thread notifies the application of various protocol events +through a thread-safe event dispatching mechanism and API calls are +provided to allow the application to control NORM operation. (Note: + API mechanisms for lower-level, non-threaded control and execution +of the NORM protocol engine will also be provided in the future.)

+

The NORM API operation +can be roughly summarized with the following categories of functions:

+
    +
  1. API Initialization

    +
  2. Session Creation + and Control

    +
  3. Data Transport

    +
  4. Event Notification

    +
+

Note the order of these +categories roughly reflects the order of function calls required to +use NORM in an application. The first step is to create and +initialize, as needed, at least one instance of the NORM API. Then +one or more NORM transport sessions (where a “session” +corresponds to data exchanges on a given multicast group and host +port number) may be created and controlled. Applications may +participate as senders and/or receivers within a NORM session. NORM +senders transmit data to the session destination address (usually an +IP multicast group) while receivers are notified of incoming data. +The NORM API provides and event notification scheme to notify the +application of significant sender and receiver events. There are +also a number support functions provided for the application to +control and monitor its participation within a NORM transport +session.

+

API Initialization

+

The NORM API requires +that an application explicitly create at least one instance of the +NORM protocol engine which is subsequently used as a conduit for +further NORM API calls. By default, the NORM protocol engine runs in +its own operating system thread and interacts with the application in +a thread-safe manner through the API calls and event dispatching +mechanism. In general, only the thread creating the NORM API +instance should invoke API calls referencing that instance or any +sessions or state created within that instance (NOTE: This +limitation may change in the future. The current implementation is +theoretically safe for concurrent access, but this has not been fully +tested). Multiple API instances may be created as needed for +applications with specific requirements for accessing and controlling +participation in multiple NORM sessions from operating system +multiple threads.

+

Session Creation and Control

+

Once an API instance +has been successfully created, the application may then create NORM +transport session instances as needed. The application can +participate in each session as a sender and/or receiver of data. If +an application is participating as a sender, it may enqueue data +transport objects for transmission. The control of transmission is +largely left to the sender and API calls are provided to control +transmission rate, FEC parameters, etc. Applications participating +as receivers will be notified via the NORM API's event dispatching +mechanism of pending and completed reliable reception of data along +with other significant events. Additionally, API controls for some +optional NORM protocol mechanisms, such as positive acknowledgment +collection, are also provided.

+

Note when multiple +senders are involved, receivers allocate system resources (buffer +space) for each active sender. With a very large number of +concurrently active senders, this may translate to significant memory +allocation on receiver nodes. Currently, the API allows the +application to control how much buffer space is allocated for each +active sender (NOTE: In the future, API functions may be provided +limit the number of active senders monitored and/or provide the +application with finer control over receive buffer allocation, +perhaps on a per sender basis). +

+

NORM Data Transport

+

The NORM protocol +supports transport of three basic types of data content. These +include the types NORM_OBJECT_FILE +and NORM_OBJECT_DATA which +represent predetermined, fixed-size application data content. The +only differentiation with respect to these two types is the implicit +“hint” to the receiver to use non-volatile (i.e. file +system) storage or memory. This “hint” lets the receiver +allocate appropriate storage space with no other information on the +incoming data. The NORM implementation reads/writes data for the +NORM_OBJECT_FILE type directly +from/to file storage, while application memory space is accessed for +the NORM_OBJECT_DATA type. The +third data content type, NORM_OBJECT_STREAM, +represents unbounded, possibly persistent, streams of data content. +Using this transport paradigm, traditional, byte-oriented streaming +transport service (e.g. similar to that provided by a TCP socket) can +be provided. Additionally, NORM has provisions for +application-defined message-oriented transport where receivers can +recover message boundaries without any “handshake” with +the sender. Stream content is buffered by the NORM implementation +for transmission/retransmission and as it is received.

+

NORM Data Transmission

+

The behavior of data +transport operation is largely placed in the control of the NORM +sender(s). NORM senders controls their data transmission rate, +forward error correction (FEC) encoding settings, and parameters +controlling feedback from the receiver group. Multiple senders may +operate in a session, each with independent transmission parameters. +NORM receivers learn needed parameter values from fields in NORM +message headers.

+

NORM transport +“objects” (file, data, or stream) are queued for +transmission by NORM senders. NORM senders may also cancel +transmission of objects at any time. The NORM sender controls the +transmission rate either manually (fixed transmission rate) or +automatically when NORM congestion control operation is enabled. The +NORM congestion control mechanism is designed to be "friendly" +to other data flows on the network, fairly sharing available +bandwidth.

+

By default, the NORM +sender transmits application-enqueued data content, providing repair +transmissions (usually in the form of FEC messages) only when +requested by NACKs from the receivers. However, the application may +also configure NORM to proactively send some amount of FEC content +along with the original data content to create a "robust" +transmission that, in some cases, may be reliably received without +any NACKing activity. This can allow for some degree of reliable +protocol operation even without receiver feedback available. NORM +senders may also requeue (within the limits of "transmit cache" +settings) objects for repeat transmission, and receivers may combine +together multiple transmissions to reliably receive content. +Additionally, hybrid proactive/reactive FEC repair operation is +possible with the receiver NACK process as a "backup" for +when network packet loss exceeds the repair capability of the +proactive FEC settings.

+

The NRL NORM +implementation also supports optional collection of positive +acknowledgment from a subset of the receiver group at +application-determined positions during data transmission. The NORM +API allows the application to specify the receiver subset ("acking +node list") and set "watermark" points for which +positive acknowledgement is collected. This process can provide the +application with explicit flow control for an application-determined +critical set of receivers in the group.

+

NORM Data Reception

+

NORM receiver +applications learn of active senders and their corresponding pending +and completed data transfers, etc via the API event dispatching +mechanism. By default, NORM receivers use NACK messages to request +repair of transmitted content from the originating sender as needed +to achieve reliable transfer. Some API functions are available to +provide some additional control over the NACKing behavior, such as +initially NACKing for NORM_INFO content only or even to the extent of +disabling receiver feedback (silent receiver operation) entirely.

+

API Event Notification

+

An asynchronous event +dispatching mechanism is provided to notify the application of +significant NORM protocol events ...

+

API Reference

+

This section provides a +reference to the NORM API variable types, constants and functions.

+

API Variable Types and Constants

+

The NORM API defines +and enumerates a number of supporting variable types and values which +are used in different function calls. The variable types are +described here.

+

NormInstanceHandle

+

The NormInstanceHandle +type is returned when a NORM API instance is created (see +NormCreateInstance()). This handle can +be subsequently used for API calls which require reference to a +specific NORM API instance. By default, each NORM API instance +instantiated creates an operating system thread for protocol +operation. Note that multiple NORM transport sessions may be created +for a single API instance. In general, it is expected that +applications will create a single NORM API instance, but some +multi-threaded application designs may prefer multiple corresponding +NORM API instances. The value NORM_INSTANCE_INVALID +corresponds to an invalid API instance.

+

NormSessionHandle

+

The NormSessionHandle +type is used to reference NORM transport sessions which have been +created using the NormCreateSession() API +call. Multiple NormSessionHandles may be +associated with a given NormInstanceHandle. + The special value NORM_SESSION_INVALID is +used to refer to invalid session references.

+

NormNodeHandle

+

The NormNodeHandle +type is used to reference state kept by the NORM +implementation with respect to other participants within a +NormSession. Most typically, the NormNodeHandle +is used by receiver applications to dereference information +about remote senders of data as needed. The special value +NORM_NODE_INVALID corresponds to an +invalid reference.

+

NormNodeId

+

The NormNodeId +type corresponds to a 32-bit numeric value which should uniquely +identify a participant (node) in a given NormSession. The +NormNodeGetId() function can be used to +retrieve this value given a valid NormNodeHandle. + The special value NORM_NODE_NONE +corresponds to an invalid (or null) node while the value +NORM_NODE_ANY serves as a wildcard value +for some functions.

+

NormObjectHandle

+

The NormObjectHandle +type is used to reference state kept for data transport objects being +actively transmitted or received. The state kept for NORM transport +objects is temporary, but the NORM API provides a function to +persistently retain state associated with a sender or receiver +NormObjectHandle (see NormObjectRetain()) +if needed. For sender objects, unless explicitly retained, the +NormObjectHandle can be considered valid +until the referenced object is explicitly canceled (see +NormObjectCancel()) or purged from the +sender transmission queue (see the event NORM_TX_OBJECT_PURGED). + For receiver objects, these handles should be treated as valid only +until a subsequent call to NormGetNextEvent() +unless, again, specifically retained. The special value +NORM_OBJECT_INVALID corresponds to +an invalid transport object reference.

+

NormObjectType

+

The NormObjectType +type is an enumeration of possible NORM data transport object types. +As previously mentioned, valid types include:

+
    +
  1. NORM_OBJECT_FILE

    +
  2. NORM_OBJECT_DATA, + and

    +
  3. NORM_OBJECT_STREAM

    +
+

Given a +NormObjectHandle, the application may +determine an object's type using the NormObjectGetType() +function call. A special NormObjectType +value, NORM_OBJECT_NONE, indicates +an invalid object type. +

+

NormObjectTransportId

+

The +NormObjectTransportId type is a 16-bit +numerical value assigned to NormObjects by senders during +active transport. These values are temporarily unique with respect +to a given sender within a NormSession and may be "recycled" +for use for future transport objects. NORM sender nodes assign these +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 +NormObjectGetTransportId() is provided to +retrieve these values if needed. (Note this function may be +deprecated – it may not be needed at all if the +NormObjectRequeue() function (TBD) is implemented using handles only, +but _some_ applications requiring persistence even after a system +reboot may need the ability to recall previous transport ids?)

+

NormEventType

+

The NormEventType +is an enumeration of NORM API events. "Events" are used by +the NORM API to signal the application of significant NORM protocol +operation events (e.g., receipt of a new receive object, etc). A +description of possible NormEventType +values and their interpretation is given below. The function call +NormGetNextEvent() is used to retrieve +events from the NORM protocol engine.

+

NormEvent

+

The NormEvent +type is a structure used to describe significant NORM protocol +events. This structure is defined as follows:

+

typedef +struct
{
    NormEventType     type;
    NormSessionHandle session;
    NormNodeHandle    node;
    NormObjectHandle  object;
} +NormEvent;

+

The type +field indicates the NormEventType and +determines how the other fields should be interpreted. Note that not +all NormEventType fields are relevant to +all events. The session, node, +and object fields indicate the applicable +NormSessionHandle, NormNodeHandle, +and NormObjectHandle, respectively, to +which the event applies. NORM protocol events are made available to +the application via the NormGetNextEvent() +function call. +

+

API Initialization

+

The first step in using +the NORM API is to create an "instance" of the NORM +protocol engine. Note that multiple instances may be created by the +application if necessary, but generally only a single instance is +required since multiple NormSessions may be managed under a +single NORM API instance.

+

NormCreateInstance()

+

Synopsis

+

#include +<normApi.h>

+

NormInstanceHandle +NormCreateInstance();

+

Description

+

This function creates +an instance of a NORM protocol engine and is the necessary first step +before any other API functions may be used. With the instantiation +of the NORM protocol engine, an operating system thread is created +for protocol execution. The returned NormInstanceHandle +value may be used in subsequent API calls as needed, such +NormCreateSesssion(), etc. +

+

Return Values

+

A value of +NORM_INSTANCE_INVALID is returned upon +failure. The function will only fail if system resources are +unavailable to allocate the instance and/or create the corresponding +thread.

+

NormDestroyInstance()

+

Synopsis

+

#include +<normApi.h>

+

void +NormDestroyInstance(NormInstanceHandle instance);

+

Description

+

The +NormDestroyInstance() function +immediately shuts down and destroys the NORM protocol engine instance +referred to by the instance +parameter. The application should make no subsequent references to +the indicated NormInstanceHandle or any +other API handles or objects associated with it. However, the +application is still responsible for releasing any object handles it +has retained (see NormObjectRetain() and +NormObjectRelease()). +

+

Return Values

+

The function has no +return value.

+

NormSetCacheDirectory()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetCacheDirectory(NormInstanceHandle instance,
                           const +char*        cachePath);

+

Description

+

This function sets the +directory path used by receivers to cache newly-received +NORM_OBJECT_FILE objects. This +function must be called before any file objects may be received and +thus should be called before any calls to NormStartReceiver() +are made. However, note that the cache directory may be changed even +during active NORM reception. In this case, the new specified +directory path will be used for subsequently-received files. Any +files received before a directory path change will remain in the +previous cache location. Note that the NormFileRename() +function may be used to rename, and thus potentially move, received +files after reception has begun. +

+

The instance +parameter specifies the NORM protocol engine instance (all +NormSessions associated with that instance +share the same cache path) and the cachePath +is a string specifying a valid (and writable) directory path. The +function returns true on success +and false on failure. The failure +conditions are that the indicated directory does not exist or the +process does not have permissions to write.

+

NormGetNextEvent()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormGetNextEvent(NormInstanceHandle instance,
                      NormEvent*         theEvent);

+

Description

+

This function retrieves +the next available NORM protocol event from the protocol engine. The +instance parameter +specifies the applicable NORM protocol engine, and the theEvent +parameter must be a valid pointer to a NormEvent +structure capable of receiving the NORM event information. For +expected reliable protocol operation, the application should make +every attempt to retrieve and process NORM notification events in a +timely manner.

+

Note that this is +currently the only blocking call in the NORM API. But non-blocking +operation may be achieved by using the NormGetDescriptor() +function to obtain a descriptor (or HANDLE for WIN32) suitable for +asynchronous input/output (I/O) notification using such system calls +as select() (UNIX) or +WaitForMultipleObjects() (WIN32). +The descriptor is signaled when a notification event is pending and a +call to NormGetNextEvent() will not +block.

+

NORM Notification Event Types

+

The following table +enumerates the possible NormEvent values +and describes how these notifications should be interpreted as they +are retrieved by the application via the NormGetNextEvent() +function call.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+ Sender Notification Event Types:

+
+

+ NORM_TX_QUEUE_VACANCY

+
+

+ This event indicates that there is room for additional transmit + objects to be enqueued, or, if the handle of NORM_OBJECT_STREAM + is given in the event "object" field, the application + may successfully write to the indicated stream.

+
+

+ NORM_TX_QUEUE_EMPTY

+
+

+ This event indicates the NORM protocol engine has no new data + pending transmission and the application may enqueue additional + objects for transmission.

+
+

+ NORM_TX_OBJECT_SENT

+
+

+ This event indicates that the transport object referenced by the + event's "object" field has completed at least one pass + of total transmission. Note that this does not guarantee that + reliable transmission has yet completed; only that the entire + object content has been transmitted. Depending upon network + behavior, several rounds of NACKing and repair transmissions may + be required to complete reliable transfer.

+
+

+ NORM_TX_OBJECT_PURGED

+
+

+ This event indicates that the NORM protocol engine will no longer + refer to the transport object identified by the event's "object' + field. Typically, this will occur when the application has + enqueued more objects than space available within the set sender + transmit cache bounds. Posting of this notification means the + application is free to free any resources (memory, files, etc) + associated with the indicated "object". After this + event, the given "object" handle (NormObjectHandle) + is no longer valid unless it is specifically retained by the + application.

+
+

+ NORM_LOCAL_SERVER_CLOSED

+
+

+ This event is posted when the NORM protocol engine completes the + "graceful shutdown" of its participation as a sender in + the indicated "session" (see NormStopSender()).

+
+

+ Receiver Notification Event Types:

+
+

+ NORM_REMOTE_SERVER_NEW

+
+

+ This notification is posted when a receiver first receives + messages from a specific remote NORM server. This marks the + beginning of the interval during which the application may + reference the provided "node" handle (NormNodeHandle).

+
+

+ NORM_REMOTE_SERVER_ACTIVE

+
+

+ This event is posted when a previously inactive (or new) remote + server is detected operating as an active sender within the + session.

+
+

+ NORM_REMOTE_SERVER_INACTIVE

+
+

+ This event is posted after a significant period of inactivity (no + sender messages received) of a specific NORM sender within the + session. The NORM protocol engine frees buffering resources + allocated for this sender when it becomes inactive.

+
+

+ NORM_REMOTE_SERVER_PURGED

+
+

+ This event is posted when the NORM protocol engine frees resources + for, and thus invalidates the indicated "node" handle.

+
+

+ NORM_RX_OBJECT_NEW

+
+

+ This event is posted when reception of a new transport object + begins and marks the beginning of the interval during which the + specified "object" (NormObjectHandle) + is valid.

+
+

+ NORM_RX_OBJECT_INFO

+
+

+ This notification is posted when the NORM_INFO content for the + indicated "object" is received.

+
+

+ NORM_RX_OBJECT_UPDATED

+
+

+ This event indicates that the identified receive "object" + has newly received data content.

+
+

+ NORM_RX_OBJECT_COMPLETED

+
+

+ This event is posted when a receive object is completely received, + including available NORM_INFO content. Unless the application + specifically retains the "object" handle, the indicated + NormObjectHandle becomes invalid and + must no longer be referenced.

+
+

+ NORM_RX_OBJECT_ABORTED

+
+

+ This notification is posted when a pending receive object's + transmission is aborted by the remote sender. Unless the + application specifically retains the "object" handle, + the indicated NormObjectHandle becomes + invalid and must no longer be referenced.

+
+

+ Miscellaneous Notification Event Types

+
+

+ NORM_EVENT_INVALID

+
+

+ This NormEventType indicates an invalid or "null" + notification which should be ignored.

+
+


+

+

Return Values

+

This function generally +blocks the thread of application execution until a NormEvent +is available and returns true when +a NormEvent is available. However, there +are some exceptional cases when the function may immediately return +even when no event is pending. In these cases, the return value is +false. +

+

WIN32 Note: A future version of this API will +provide an option to have a user-defined Window message posted when a +NORM API event is pending. (Also some event filtering calls may be +provided (e.g. avoid the potentially numerous RX_OBJECT_UPDATED +events if undesired)).

+

NormGetDescriptor()

+

Synopsis

+

#include +<normApi.h>

+

NormDescriptor +NormGetDescriptor(NormInstanceHandle instance);

+

Description

+

This function is used +to retrieve a NormDescriptor (integer +file descriptor (UNIX) or HANDLE (WIN32)) suitable for asynchronous +I/O notification to avoid blocking calls to NormGetNextEvent(). + A NormDescriptor is available for each +protocol engine instance. The +descriptor (or WIN32 HANDLE) is suitable for use as an input (or +"read") descriptor which is signaled when a NORM protocol +event is ready for retrieval via NormGetNextEvent(). + Hence, a call to NormGetNextEvent() will +not block when the descriptor has been signaled. The select() +system call (UNIX) (or WaitForMultipleObjects() +(WIN32)) can be used to detect when the returned NormDescriptor +is signaled. For the select() call +usage, the NORM descriptor should be treated as a "read" +descriptor.

+

Return Values

+

A descriptor is +returned which is valid until a call to NormDestroyInstance() is +made. Upon error, a value of NORM_DESCRIPTOR_INVALID +is returned.

+

Session Creation and Control

+

NormCreateSession()

+

Synopsis

+

#include +<normApi.h>

+

NormSessionHandle +NormCreateSession(NormInstanceHandle instance,
                                    const +char*        address,
                                    unsigned +short     port,
                                    NormNodeId         localId);

+

Description

+

This function creates a +NORM reliable multicast session (NormSession) using the +address parameters provided. While session state is allocated and +initialized, active session participation does not begin until a call +is made to NormStartSender() and/or +NormStartReceiver() to join the specified +multicast group (if applicable) and start protocol operation. The +following parameters are required in this function call:

+ + + + + + + + + + + + + + + + + + + +
+

+ instance

+
+

+ This must be a valid NormInstanceHandle + previously obtained with a call to NormCreateInstance().

+
+

+ address

+
+

+ This points to a string containing an IP address (e.g. dotted + decimal IPv4 address (or IPv6 address) or name resolvable to a + valid IP address. The specified address + (along with the port number) + determines the destination of NORM messages sent. For multicast + sessions, NORM senders and receivers must use a common multicast + address and port number. For unicast sessions, the sender and + receiver must use a common port number, but specify the other + node's IP address as the session address (Although note that + receiver-only unicast nodes who are providing unicast feedback to + senders will not generate any messages to the session IP address + and the address parameter value + is thus inconsequential for this special case).

+
+

+ port

+
+

+ This must be a valid, unused port number corresponding to the + desired NORM session address. See the address + parameter description for more details.

+
+

+ localId

+
+

+ The localId parameter specifies the + NormNodeId that should be used to + identify the application's presence in the NormSession. + All participant's in a NormSession should use unique + localId values. The application may + specify a value of NORM_NODE_ANY or + NORM_NODE_ANY for the localId + parameter. In this case, the NORM implementation will attempt to + pick an identifier based on the host computer's "default" + IP address (based on the computer's default host name). Note + there is a chance that this approach may not provide unique node + identifiers in some situations and the NORM protocol does not + currently provide a mechanism to detect or resolve NormNodeId + collisions. Thus, the application should explicitly specify the + localId unless there is a high degree + of confidence that the default IP address will provide a unique + identifier.

+
+

Return Values

+

The returned +NormSessionHandle value is valid until a +call to NormDestroySession() is made. A +value of NORM_SESSION_INVALID is +returned upon error.

+

NormDestroySession()

+

Synopsis

+

#include +<normApi.h>

+

void +NormDestroySession(NormSessionHandle session);

+

Description

+

This function +immediately terminates the application's participation in the +NormSession identified by the session +parameter and frees any resources used by that session. An exception +to this is that the application is responsible for releasing any +explicitly retained NormObjectHandles +(See NormObjectRetain() and +NormObjectRelease()).

+

Return Values

+

This function has no +returned values.

+

NormGetLocalNodeId()

+

Synopsis

+

#include +<normApi.h>

+

NormNodeId +NormGetLocalNodeId(NormSessionHandle session);

+

Description

+

This function retrieves +the NormNodeId value used for the +application's participation in the NormSession identified by +the session parameter. The value +may have been explicitly set during the NormCreateSession() +call or derived using the host computer's "default" IP +network address.

+

Return Values

+

The returned value +indicates the NormNode identifier used by the NORM protocol +engine for the local application's participation in the specified +NormSession.

+

NormSetMulticastInterface()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetMulticastInterface(NormSessionHandle +session,
                               const +char*       interfaceName);

+

Description

+

This function specifies +which host network interface is used for IP Multicast transmissions +and group membership. This should be called before any call +to NormStartSender() or +NormStartReceiver() is made so that the +IP multicast group is joined on the proper host interface. However, +if a call to NormSetMulticastInterface() +is made after either of these function calls, the call will +not affect the group membership interface, but only dictate that a +possibly different network interface is used for transmitted NORM +messages. Thus, the code:

+

NormSetMulticastInterface(session, +"interface1");
NormStartReceiver(session, +...);
NormSetMulticastInterface(session, "interface2");

+

will result in NORM +group membership (i.e. multicast reception) being managed on +"interface1" while NORM multicast transmissions are made +via "interface2".

+

Return Values

+

A return value of true +indicates success while a return value of false +indicates that the specified interface was valid. This function will +always return true if made before +calls to NormStartSender() or +NormStartReceiver(). However, those +calls may fail if an invalid interface is specified.

+

NormSetTTL()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetTTL(NormSessionHandle session,
                unsigned +char     ttl);

+

Description

+

This function specifies +the time-to-live (ttl) for IP +Multicast datagrams generated by NORM for the specified session. + The IP TTL field limits the number of router "hops" that a +generated multicast packet may traverse before being dropped. For +example, if TTL is equal to one, the transmissions will be limited to +the local area network (LAN) of the host computers network interface. + Larger TTL values should be specified to span large networks. Also +note that some multicast router configurations use artificial "TTL +threshold" values to constrain some multicast traffic to an +administrative boundary. In these cases. the NORM TTL setting must +also exceed the router "TTL threshold" in order for the +NORM traffic to be allowed to exit the administrative area.

+

Return Values

+

A return value of true +indicates success while a return value of false +indicates that the specified ttl +could not be set. This function will always return true +if made before calls to NormStartSender() +or NormStartReceiver(). However, those +calls may fail if the desired ttl +value cannot be set..

+

NormSetTOS()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetTOS(NormSessionHandle session,
                unsigned +char     tos);

+

Description

+

This function specifies +the type-of-service (tos) field +value used in IP Multicast datagrams generated by NORM for the +specified session. The IP TOS +field value can be used as an indicator that a "flow" of +packets may merit special Quality-of-Service (QoS) treatment by +network devices. Users should refer to applicable QoS information +for their network to determine the expected interpretation and +treatment (if any) of packets with explicit TOS marking.

+

Return Values

+

A return value of true +indicates success while a return value of false +indicates that the specified tos +could not be set. This function will always return true +if made before calls to NormStartSender() +or NormStartReceiver(). However, those +calls may fail if the desired tos +value cannot be set..

+

NormSetLoopback()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetLoopback(NormSessionHandle session,
                     bool              loopbackEnable);

+

Description

+

This function enables +or disables loopback operation for the indicated NORM session. + If loopbackEnable is set to true, +loopback operation is enabled which allows the application to receive +its own message traffic. Thus, an application which is both actively +receiving and sending may receive its own transmissions. Note it is +expected that this option would be principally be used for test +purposes and that applications would generally not need to transfer +data to themselves. If loopbackEnable +is false, the application is +prevented from receiving its own NORM message transmissions. By +default, loopback operation is disabled when a NormSession is +created.

+

Return Values

+

This function has no +return values.

+

NORM Sender +Functions

+

NormStartSender()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormStartSender(NormSessionHandle session
                     unsigned +long     bufferSpace
                     unsigned +short    segmentSize,
                     unsigned +char     blockSize,
                     unsigned +char     numParity);

+

Description

+

The application's +participation as a sender within a specified NormSession +begins when this function is called. This includes protocol activity +such as congestion control and/or group round-trip timing (GRTT) +feedback collection and application API activity such as posting of +sender-related NormEvents. The parameters required for this +function call include:

+ + + + + + + + + + + + + + + + + + + + + + + +
+

+ session

+
+

+ This must be a valid NormSessionHandle + previously obtained with a call to NormCreateSession().

+
+

+ bufferSpace

+
+

+ This specifies the maximum memory space the NORM protocol engine + is allowed to use to buffer any sender calculated FEC segments and + repair state for the session. The optimum bufferSpace + value is function of the network topology bandwidth*delay + product and packet loss characteristics. If the bufferSpace + limit is too small, the protocol may operate less efficiently as + the sender is required to possibly recalculate FEC parity segments + and/or provide less efficient repair transmission strategies + (resort to explicit repair) when state is dropped due to + constrained buffering resources. However, note the protocol will + still provide reliable transfer. A large bufferSpace + allocation is safer at the expense of possibly committing more + memory resources.

+
+

+ segmentSize

+
+

+ This parameter sets the maximum payload size (in bytes) of + NORM sender messages (not including any NORM message header + fields). A sender's segmentSize value + is also used by receivers to limit the payload content of some + feedback messages (e.g. NORM_NACK message content, etc.) generated + in response to that sender. Note different senders within a + NormSession may use different segmentSize + values. Generally, the appropriate segment size to use is + dependent upon the types of networks forming the multicast + topology, but applications may choose different values for other + purposes. Note that application designers MUST account for the + size of NORM message headers when selecting a segmentSize. + For example, the NORM_DATA message header for a + NORM_OBJECT_STREAM with full + header extensions is 48 bytes in length. In this case, the UDP + payload size of these messages generated by NORM would be up to + (48 + segmentSize) bytes.

+
+

+ blockSize

+
+

+ This parameter sets the number of source symbol segments (packets) + per coding block, for the systematic Reed-Solomon FEC code used in + the current NORM implementation. For traditional systematic block + code "(n,k)" nomenclature, the blockSize + value corresponds to (n-k). NORM logically segments + transport object data content into coding blocks and the blockSize + parameter determines the number of source symbol segments + (packets) comprising a single coding block where each source + symbol segment is up to segmentSize + bytes in length.. A given block's parity symbol segments are + calculated using the corresponding set of source symbol segments. + The maximum blockSize allowed + by the 8-bit Reed-Solomon codes in NORM is 255, with the further + limitation that (blockSize + + numParity) ≤ 255.

+
+

+ numParity

+
+

+ This parameter sets the maximum number of parity symbol segments + (packets) the sender is willing to calculate per FEC coding + block. The parity symbol segments for a block are calculated from + the corresponding blockSize + source symbol segments. In the "(n,k)" + nomenclature mention above, the numParity + value corresponds to "k". A property of the + Reed-Solomon FEC codes used in the current NORM implementation is + that one parity segment can fill any one erasure (missing segment + (packet)) for a coding block. For a given blockSize, + the maximum numParity value is + (255 – blockSize). + However, note that computational complexity increases + significantly with increasing numParity + values and applications may wish to be conservative with respect + to numParity selection, given + anticipated network packet loss conditions and group size + scalability concerns. Additional FEC code options may be provided + for this NORM implementation in the future with different + parameters, capabilities, trade-offs, and computational + requirements.

+
+

These parameters are +currently immutable with respect to a sender's participation within a +NormSession. Sender operation must be stopped (see +NormStopSender()) and restarted with +another call to NormStartSender() if +these parameters require alteration. The API may be extended in the +future to support additional flexibility here, if required. For +example, the NORM protocol "sessionId" field may +possibly be leveraged to permit a node to establish multiple virtual +presences as a sender within a NormSession in the future. +This would allow the sender to provide multiple concurrent streams of +transport, with possibly different FEC and other parameters if +appropriate within the context of a single NormSession. +Again, this extended functionality is not yet supported in this +implementation.

+

Return Values

+

A value of true +is returned upon success and false +upon failure. The reasons failure may occur include limited system +resources or that the network sockets required for communication +failed to open or properly configure. (TBD – Provide a +NormGetError(NormSessionHandle session) +function to retrieve a more specific error indication for this and +other functions.)

+

NormStopSender()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStopSender(NormSessionHandle session, +
                    bool              graceful += false);

+

Description

+

This function +terminates the application's participation in a NormSession as +a sender. By default, the sender will immediately exit the session +without notifying the receiver set of its intention. However a +"graceful shutdown" option is provided to terminate sender +operation gracefully, notifying the receiver set its pending exit +with appropriate protocol messaging. A NormEvent, +NORM_LOCAL_SERVER_CLOSED, is +dispatched when the graceful shutdown process has completed.

+

(NOTE: The +"graceful" +parameter is currently not available, and the current behavior of +this API call corresponds to the default behavior of graceful += false). + The functionality described here will soon be supported in the API.

+

Return Values

+

This function has no +return values.

+

NormSetTransmitRate()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetTransmitRate(NormSessionHandle session, +
                         double            rate);

+

Description

+

This function sets the +transmission rate limit (in bits per second (bps)) used for +NormSender transmissions. For fixed-rate transmission of +NORM_OBJECT_FILE or +NORM_OBJECT_DATA, this limit +determines the data rate at which NORM protocol messages and data +content. For NORM_OBJECT_STREAM +transmissions, this is the maximum rate allowed for transmission. +Note that the application will need to consider the overhead of NORM +protocol headers when determining an appropriate transmission rate +for its purposes. When NORM congestion control is enabled (see +NormSetCongestionControl()), the rate set +here will be set, but congestion control operation may quickly +readjust the rate unless disabled. +

+

Return Values

+

This function has no +return values.

+

NormSetCongestionControl()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetTransmitRate(NormSessionHandle session, +
                         bool              enable);

+

Description

+

This function enables +(or disables) the NORM sender congestion control operation for the +session designated by the session +parameter. For best operation, this function should be called before +the call to NormStartSender() is made, +but congestion control operation can be dynamically enabled/disabled +during the course of sender operation. If the value of enable +is true, congestion control +operation is enabled while it is disabled for enable +equal to false. When congestion +control operation is enabled, the NORM sender automatically adjusts +its transmission rate based on feedback from receivers. If bounds on +transmission rate have been set (see NormSetTransmitRateBounds()) +the rate adjustment will remain within any set bounds. The rate set +by NormSetTransmitRate() has no effect +when congestion control operation is enabled. NORM's congestion +algorithm provides rate adjustment to fairly compete for available +network bandwidth with other TCP, NORM, or similarly governed traffic +flows.

+

Return Values

+

This function has no +return values.

+

NormSetTransmitRateBounds()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetTransmitRateBounds(NormSessionHandle session, +
                               double            rateMin,
                               double            rateMax);

+

Description

+

This function sets the +range of sender transmission rates within which the NORM congestion +control algorithm is allowed to operate. By default, the NORM +congestion control algorithm operates with no lower or upper bound on +its rate adjustment. This function allows this to be limited where +rateMin corresponds to the minimum +transmission rate (bps) and rateMax +corresponds to the maximum transmission rate. One or both of these +parameters may be set to values less than zero to remove one or both +bounds. For example "NormSetTransmitRate(session, +-1.0, +64000.0)" +will set an upper limit of 64 kbps for the sender transmission rate +with no lower bound. These rate bounds apply only when congestion +control operation is enabled (see +NormSetCongestionControl()). If the current congestion +control rate falls outside of the specified bounds, the sender +transmission rate will

+

Return Values

+

This function returns +true upon success. If both +rateMin and rateMax +are greater than or equal to zero, but (rateMax +< rateMin), the rate bounds +will remain unset or unchanged and the function will return false.

+

NormSetAutoParity()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetAutoParity(NormSessionHandle sessionHandle, +
                       unsigned +char     autoParity);

+

Description

+

This function sets the +quantity of proactive "auto parity" NORM_DATA messages sent +at the end of each FEC coding block. By default (i.e., autoParity += 0), FEC content is sent only in response to repair requests +(NACKs) from receivers. But, by setting a non-zero value for +autoParity, the sender can +automatically accompany each coding block of transport object source +data segments (NORM_DATA messages) with the set number of FEC +segments. The number of source symbol messages (segments) per FEC +coding block is determined by the blockSize +parameter used when NormStartSender() was +called for the given sessionHandle.

+

The use of +proactively-sent "auto parity" may eliminate the need for +any receiver NACKing to achieve reliable transfer in networks with +low packet loss. However, note that the quantity of "auto +parity" set adds overhead to transport object transmission. In +networks with a predictable level of packet loss and potentially +large round-trip times, the use of "auto parity" may allow +lower latency in the reliable delivery process. Also, its use may +contribute to a smaller amount of receiver feedback as only receivers +with exceptional packet loss may need to NACK for additional repair +content.

+

The value of autoParity +set must be less than or equal to the numParity +parameter set when NormStartSender() was +called for the given sessionHandle.

+

Return Values

+

This function has no +return values.

+

NormSetGrttEstimate()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetGrttEstimate(NormSessionHandle session, +
                         double            grtt);

+

Description

+

This function sets the +sender's estimate of group round-trip timing (GRTT). This function +is expected to most typically used to initialize ther sender's GRTT +estimate prior to the call to NormStartSender() +when the application has a priori confidence that the default +initial GRTT value of 0.5 second is inappropriate. The sender GRTT +estimate will be updated during normal sender protocol operation +after sender startup or if this call is made while sender operation +is active. For experimental purposes (or very special application +needs), this API provides a mechanism to control or disable the +sender GRTT update process (see NormSetGrttProbing()). + The grtt value will be limited to the maximum GRTT as set (see +NormSetGrttMax()) or the default maximum +of 10 seconds. +

+

The sender GRTT is +advertised to the receiver group and is used to scale various NORM +protocol timers. The default NORM GRTT estimation process +dynamically measures round-trip timing to determine an appropriate +operating value. An overly-large GRTT estimate can introduce +additional latency into the reliability process (resulting in a +larger virtual delay*bandwidth product for the protocol and +potentially requiring more buffer space to maintain reliability). An +overly-small GRTT estimate may introduce the potential for feedback +implosion, limiting the scalability of group size.

+

Return Values

+

This function has no +return values.

+

NormAddAckingNode()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormAddAckingNode(NormSessionHandle session,
                       NormNodeId        nodeId);

+

Description

+

When this function is +called, the specified nodeId is +added to the list of NormNodes used when NORM sender operation +performs positive acknowledgement (ACK) collection for the specified +session. The optional NORM +positive acknowledgement collection occurs when a specified +transmission point (see NormSetWatermark()) +is reached or for specialized protocol actions such as +positively-acknowledged application-defined commands (TBD).

+

Return Values

+

The function returns +true upon success and false +upon failure. The only failure condition is that insufficient memory +resources were available. If a specific nodeId +is added more than once, this has no effect.

+

NormRemoveAckingNode()

+

Synopsis

+

#include +<normApi.h>

+

void +NormRemoveAckingNode(NormSessionHandle session,
                          NormNodeId        nodeId);

+

Description

+

This function deletes +the specified nodeId from the list +of NormNodes used when NORM sender operation performs positive +acknowledgement (ACK) collection for the specified session. + +

+

Return Values

+

The function has no +return values.

+

NormFileEnqueue()

+

Synopsis

+

#include +<normApi.h>

+

NormObjectHandle +NormFileEnqueue(NormSessionHandle session,
                                 const +char*       filename,
                                 const +char*       infoPtr = +NULL,
                                 unsigned +int      infoLen = 0);

+

Description

+

This function enqueues +a file for transmission within the specified NORM session. + Note that NormStartSender() must have +been previously called before files or any transport objects may be +enqueued and transmitted. The fileName +parameter specifies the path to the file to be transmitted. The NORM +protocol engine read and writes directly from/to file system storage +for file transport, potentially providing for a very large virtual +"repair window" as needed for some applications. While +relative paths with respect to the current working directory may be +used, it is recommended that full paths be used when possible. The +optional infoPtr and infoLen +parameters are used to associate NORM_INFO content with the sent +transport object. The maximum allowed infoLen +corresponds to the segmentSize +used in the prior call to NormStartSender(). + The use and interpretation of the NORM_INFO content is left to the +application's discretion. Example usage of NORM_INFO content for +NORM_OBJECT_FILE might include +file name, creation date, MIME-type or other information which will +enable NORM receivers to properly handle the file when reception is +complete.

+

The application is +allowed to enqueue multiple transmit objects within in the "transmit +cache" limits (see NormSetTxCacheLimits()) +and enqueued objects are transmitted (and repaired as needed) within +the limits determined by automated congestion control (see +NormSetCongestionControl()) or fixed rate +(see NormSetTxRate()) parameters.

+

Return Values

+

A NormObjectHandle +is returned which the application may use in other NORM API calls as +needed. This handle can be considered valid until the application +explicitly cancels the object's transmission (see NormObjectCancel()) +or a NORM_TX_OBJECT_PURGED event +is received for the given object. Note the application may use the +NormObjectRetain() method if it wishes to +refer to the object after the NORM_TX_OBJECT_PURGED +notification. In this case, the application, when finished with the +object, must use NormObjectRelease() to +free any resources used or else a memory leak condition will result. +A value of NORM_OBJECT_INVALID is +return upon error. Possible failure conditions include the specified +session is not operating as a +NormSender, insufficient memory resources were available, or +the "transmit cache" limits have been reached and all +previously enqueued NORM transmit objects are pending transmission. +Also the call will fail if the infoLen +parameter exceeds the local NormSender segmentSize +limit.

+

NormDataEnqueue()

+

Synopsis

+

#include +<normApi.h>

+

NormObjectHandle +NormDataEnqueue(NormSessionHandle session,
                                 const +char*       dataPtr,
                                 unsigned +int      dataLen,
                                 const +char*       infoPtr = +NULL,
                                 unsigned +int      infoLen = 0);

+

Description

+

This function enqueues +a segment of application memory space for transmission within the +specified NORM session. Note that +NormStartSender() must have been +previously called before files or any transport objects may be +enqueued and transmitted. The dataPtr +parameter must be a valid pointer to the area of application memory +to be transmitted and the dataLen +parameter indicates the quantity of data to transmit. The NORM +protocol engine read and writes directly from/to application memory +space so it is important that the application does not modify (or +deallocate) the memory space during the time the NORM protocel engine +may access this area. The optional infoPtr +and infoLen parameters are used to +associate NORM_INFO content with the sent transport object. The +maximum allowed infoLen +corresponds to the segmentSize +used in the prior call to NormStartSender(). + The use and interpretation of the NORM_INFO content is left to the +application's discretion. Example usage of NORM_INFO content for +NORM_OBJECT_DATA might include +application-defined data typing or other information which will +enable NORM receiver applications to properly interpret the received +data when reception is complete. Of course, it is possible that the +application may embed such typing information in the object data +content itself. This is left to the application's discretion.

+

The application is +allowed to enqueue multiple transmit objects within in the "transmit +cache" limits (see NormSetTxCacheLimits()) +and enqueued objects are transmitted (and repaired as needed) within +the limits determined by automated congestion control (see +NormSetCongestionControl()) or fixed rate +(see NormSetTxRate()) parameters.

+

Return Values

+

A NormObjectHandle +is returned which the application may use in other NORM API calls as +needed. This handle can be considered valid until the application +explicitly cancels the object's transmission (see NormObjectCancel()) +or a NORM_TX_OBJECT_PURGED event +is received for the given object. Note the application may use the +NormObjectRetain() method if it wishes to +refer to the object after the NORM_TX_OBJECT_PURGED +notification. In this case, the application, when finished with the +object, must use NormObjectRelease() +to free any resources used or else a memory leak condition will +result. A value of NORM_OBJECT_INVALID +is return upon error. Possible failure conditions include the +specified session is not operating +as a NormSender, insufficient memory resources were available, +or the "transmit cache" limits have been reached and all +previously enqueued NORM transmit objects are pending transmission. +Also the call will fail if the infoLen +parameter exceeds the local NormSender segmentSize +limit.

+

NormStreamOpen()

+

Synopsis

+

#include +<normApi.h>

+

NormObjectHandle +NormStreamOpen(NormSessionHandle session,
                                unsigned +int      bufferSize,
                                const +char*       infoPtr = +NULL,
                                unsigned +int      infoLen = 0);

+

Description

+

This function opens a +NORM_OBJECT_STREAM sender object +and enqueues it for transmission within the indicated session. + NormStream objects provide reliable, in-order delivery of data +content written to the stream by the sender application. Note that +no data is sent until subsequent calls to NormStreamWrite() +are made unless NORM_INFO content is specified for the stream with +the infoPtr and infoLen +parameters. Example usage of NORM_INFO content for NORM_OBJECT_STREAM +might include application-defined data typing or other information +which will enable NORM receiver applications to properly interpret +the received stream as it is being received. The NORM protocol +engine buffers data written to the stream for original transmission +and repair transmissions as needed to achieve reliable transfer. The +bufferSize parameter controls the +size of the stream's "repair window" which limits how far +back the sender will "rewind" to satisfy receiver repair +requests. +

+

NORM, as a +NACK-oriented protocol, currently lacks a mechanism for receivers to +explicitly feedback flow control status to the sender unless +the sender leverages NORM's optional positive acknowledgement (ACK) +features. Thus, the bufferSize +selection plays an important role in NORM's reliability. Generally, +a larger bufferSize value is safer +with respect to reliability, but some applications may wish to limit +how far the sender rewinds to repair receivers with poor connectivity +with respect to the group at large. Such applications may set a +smaller bufferSize to avoid the +potential for large latency in data delivery. This may result in +breaks in the reliable delivery of stream data to some receivers, but +this form of quasi-reliability while limiting latency may be useful +for some types of applications (e.g. reliable real-time messaging, +video or sensor data transport). Note that NORM receivers can +"resync" to the sender after such breaks if the application +leverages the message boundary recovery features of NORM (see +NormStreamMarkEom()).

+

Note that the current +implementation of NORM is designed to support only one active stream +per session, and that any NORM_OBJECT_DATA +or NORM_OBJECT_FILE objects +enqueued for transmission will not begin transmission until an active +stream is closed. Applications requiring multiple streams or +concurrent file/data transfer should instantiate multiple +NormSessions as needed.

+

Note there is no +corresponding "open" call for receiver streams. Receiver +NORM_OBJECT_STREAMs are +automatically opened by the NORM protocol engine and the receiver +applications is notified of new streams via the NORM_RX_OBJECT_NEW +notification (see NormGetNextEvent()).

+

Return Values

+

A NormObjectHandle +is returned which the application may use in other NORM API calls as +needed. This handle can be considered valid until the application +explicitly cancels the object's transmission (see NormObjectCancel()) +or a NORM_TX_OBJECT_PURGED event +is received for the given object. Note the application may use the +NormObjectRetain() method if it wishes to +refer to the object after the NORM_TX_OBJECT_PURGED +notification. In this case, the application, when finished with the +object, must use NormObjectRelease() +to free any resources used or else a memory leak condition will +result. A value of NORM_OBJECT_INVALID +is return upon error. Possible failure conditions include the +specified session is not operating +as a NormSender, insufficient memory resources were available, +or the "transmit cache" limits have been reached and all +previously enqueued NORM transmit objects are pending transmission. +Also the call will fail if the infoLen +parameter exceeds the local NormSender segmentSize +limit.

+

NormStreamClose()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormStreamClose(NormObjectHandle streamHandle);

+

Description

+

This function halts +transfer of the stream specified by the streamHandle +parameter and releases any resources used unless the associated +object has been explicitly retained by a call to NormObjectRetain(). + This function is equivalent to the NormObjectCancel() +routine and may be used for sender or receiver streams. This +alternative function is simply provided to compliment the +NormStreamOpen() call.

+

Return Values

+

This function has no +return values.

+

NormStreamWrite()

+

Synopsis

+

#include +<normApi.h>

+

unsigned +int +NormStreamWrite(NormObjectHandle streamHandle
                             const +char*      buffer,
                             unsigned +int     numBytes);

+

Description

+

This function enqueues +data for transmission within the NORM stream specified by the +streamHandle parameter. The +buffer parameter must be a pointer +to the data to be enqueued and the numBytes +parameter indicates the length of the data content. Note this call +does not block and will return immediately. The return value +indicates the number of bytes copied from the provided buffer to the +internal stream transmission buffers. Calls to this function will be +successful unless the stream's transmit buffer space is fully +occupied with data pending original or repair transmission if the +stream's "push mode" is set to false +(default, see NormStreamSetPushMode() for +details). If the stream's "push mode" is set to true, a +call to NormStreamWrite() will always +result in copying of application data to the stream at the cost of +previously enqueued data pending transmission (original or repair) +being dropped by the NORM protocol engine. While NORM NACK-based +reliability does not provide explicit flow control, there is some +degree of implicit flow control in limiting writing new data to the +stream against pending repairs. +

+

Return Values

+

This function returns +the number of bytes of data successfully enqueued for NORM stream +transmission.

+

NormStreamFlush()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStreamFlush(NormObjectHandle +streamHandle,
                     bool             eom += false,
                     NormFlushMode    flushMode += NORM_FLUSH_PASSIVE);

+

Description

+

This function causes an +immediate "flush" of the transmit stream specified by the +streamHandle parameter. Normally, +unless NormSetAutoFlush() has been +invoked, the NORM protocol engine buffers data written to a stream +until it has accumulated a sufficient quantity to generate a +NORM_DATA message with a full payload (as designated by the +segmentSize parameter of the +NormStartSender() call). This results in +most efficient operation with respect to protocol overhead. However, +for some NORM streams, the application may not wish wait for such +accumulation when critical data has been written to a stream. The +default stream "flush" operation invoked via +NormStreamFlush() for flushMode +equal to NORM_FLUSH_PASSIVE causes +NORM to immediately transmit all enqueued data for the stream +(subject to session transmit rate limits), even if this results in +NORM_DATA messages with "small" payloads. If the optional +flushMode parameter is set to +NORM_FLUSH_ACTIV, the application +can achieve reliable delivery of stream content up to the current +write position in an even more proactive fashion. In this case, the +sender additionally, actively transmits NORM_CMD(FLUSH) +messages after any enqueued stream content has been sent. This +immediately prompt receivers for repair requests which reduces +latency of reliable delivery, but at a cost of some additional +messaging. Note any such "active" flush activity will be +terminated upon the next subsequent write to the stream. If +flushMode is set to +NORM_FLUSH_NONE, this call has no +effect other than the optional end-of-message marking described here.

+

The optional eom +parameter, when set to true, +allows the sender application to mark an end-of-message indication +(see NormStreamMarkEom()) for the stream +and initiate flushing in a single function call. The end-of-message +indication causes NORM to mark the first NORM_DATA message generated +following a subsequent write to the stream with the +NORM_FLAGS_MSG_START flag. This mechanism provide a means for +message boundary recovery when receivers join or re-sync to a sender +mid-stream.

+

Note that frequent +flushing, particularly for NORM_FLUSH_ACTIVE +operation, may result in more NORM protocol activity than usual, so +care must be taken in application design and deployment when +scalability to large group sizes is expected.

+

Return Values

+

This function has no +return values.

+

NormStreamSetAutoFlush()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStreamSetAutoFlush(NormObjectHandle +streamHandle
                            NormFlushMode    flushMode);

+

Description

+

This function sets +"automated flushing" for the NORM transmit stream +indicated by the streamHandle +parameter. By default, a NORM transmit stream is "flushed" +only when explicitly requested by the application (see +NormStreamFlush()). +However, to simplify programming, the NORM API allows that automated +flushing be enabled such that the "flush" operation occurs +every time the full requested buffer +provided to a NormStreamWrite() +call is successfully enqueued. This may be appropriate for messaging +applications where the provided buffers corresponds to an application +messages requiring immediate, full transmission. This may make the +NORM protocol perhaps more "chatty" than its typical "bulk +transfer" form of operation, but can provide a useful capability +for some applications. +

+

Possible values for the +flushMode parameter include +NORM_FLUSH_NONE, +NORM_FLUSH_PASSIVE, and +NORM_FLUSH_ACTIVE. The default +setting for a NORM stream is NORM_FLUSH_NONE +where no flushing occurs unless explicitly requested via +NormStreamFlush(). +By setting the automated flushMode +to NORM_FLUSH_PASSIVE, the only +action taken is to immediately transmit any data that has been +written to the stream, even if "runt" NORM_DATA messages +(with payloads less than the NormSender segmentSize +parameter) are generated as a result. If NORM_FLUSH_ACTIVE +is specified, the automated flushing operation is further augmented +with the additional transmission of NORM_CMD(FLUSH) messages to +proactively excite the receiver group for repair requests.

+

Return Values

+

This function has no +return values.

+

NormStreamSetPushEnable()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStreamSetPushEnable(NormObjectHandle +streamHandle
                             bool             pushEnable);

+

Description

+

This function controls +how the NORM API behaves when the application attempts to enqueue new +stream data for transmission when the associated stream's transmit +buffer is fully occupied with data pending original or repair +transmission. By default, a call to NormStreamWrite() +will return a zero value under this condition, indicating it was +unable to enqueue the new data. However, if pushEnable +is set to true for a given +streamHandle, the NORM protocol +engine will discard the oldest buffered stream data (even if it is +pending repair transmission or has never been transmitted) as needed +to enqueue the new data. Thus a call to NormStreamWrite() +will never fail to copy data. This behavior may be desirable for +applications where it is more important to quickly delivery new data +than to reliably deliver older data written to a stream. The default +behavior for a newly opened stream corresponds to pushEnable +equals false. This limits the +rate to which an application can write new data to the stream to the +current transmission rate and status of the reliable repair process.

+

Return Values

+

This function has no +return values.

+

NormStreamMarkEom()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStreamMarkEom(NormObjectHandle streamHandle);

+

Description

+

This function allows +the application to indicate to the NORM protocol engine that the last +data successfully written to the stream indicated by streamHandle +corresponded to the end of an application-defined message boundary. +If the stream is either explicitly flushed at this point (see +NormStreamFlush()) or the last write had +exactly filled a NormSender segmentSize +NORM_DATA message payload, the beginning of the next write will +correspond to the beginning of a new NORM_DATA message. The +end-of-message indication given here will cause the NORM protocol +engine to flag this new message with NORM_FLAG_MSG_START which allows +receivers to recover message boundary synchronization even when +beginning reception mid-stream. Note that the marking is most +effective when explicit flushing is used which forces alignment of +application message boundaries with NORM_DATA messages. It is +anticipated that future versions of the NORM protocol specification +(and/or the NRL implementation) will provide additional, more +flexible stream control mechanisms (e.g. mid-segment message boundary +alignment) that allow for more robust message boundary recovery.

+

It is recommended that +the NormStreamMarkEom() should be used +with automated flushing modes (see NormStreamSetAutoFlush()) +while the optional eom parameter +of NormStreamFlush() is instead used when +explicit flushing is practiced. End-of-message marking may be +used when no flushing is done, but note then there is no guarantee of +message boundary to NORM_DATA message alignment unless the +application message sizes correspond to multiples of the configured +NormSender segmentSize. +Again, note future versions of NORM and this implementation may +provide more flexibility here.

+

Return Values

+

This function has no +return values.

+

NormSetWatermark()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormSetWatermark(NormSessionHandle session,
                      NormObjectHandle  object);

+

Description

+

This function specifies +a "watermark" transmission point at which NORM sender +protocol operation should perform positive acknowledgment collection +for a given session. For +NORM_OBJECT_FILE and +NORM_OBJECT_DATA transmissions, +the positive acknowledgement collection will begin when the specified +object has been completely +transmitted. The object parameter must be a valid handle to a +previously-created sender object (see NormEnqueueFile(), +NormEnqueueData(), or +NormStreamOpen()). +For NORM_OBJECT_STREAM +transmission, the positive acknowledgment collection begins +immediately, using the current position (last data written) of the +sender stream as a reference. +

+

As the acknowledgment +collection proceeds, NORM_ACK_FAILED +events will be posted for individual receiver NormNodes which +fail to acknowledge the request. The NormEvent::node +field contains a NormNodeHandle for the +failed node and NormNodeGetId() can be +used to retrieve the failing node's NormNodeId. + When the sender acknowledgment collection process has completed, the +NORM_ACK_COMPLETE event is posted +and the application may assume that the remaining nodes (those for +which there was no NORM_ACK_FAILED +event) successfully acknowledged the request.

+

If a subsequent call is +made to NormSetWatermark() before the +prior acknowledgement request has completed, the pending +acknowledgment request is canceled and new one may begin.

+

Note that the sender +may still enqueue NormObjects for transmission (or write to +the existing stream) and the positive acknowledgement collection will +be multiplexed with the ongoing data transmission. However, the +sender application may wish to defer sending more data until a +NORM_ACK_COMPLETE event is +received for the session. This +provides a form of explicit sender->receiver(s) flow control (with +respect to the current list of "acking" receivers) which +does not exist in NORM's default NACK-only operation.

+

Return Values

+

The function returns +true upon successful establishment +of the watermark point. The function may return false +upon failure (why would it fail? – TBD).

+

NORM Receiver Functions

+

NormStartReceiver()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormStartReceiver(NormSessionHandle session, +
                       unsigned +long     bufferSpace);

+

Description

+

This function initiates +the application's participation as a receiver within the NormSession +identified by the session +parameter. The receiver will respond with appropriate protocol +messages (unless NormSetSilentReceiver(true) +is invoked) and begin providing the application with +receiver-related NormEvent notification. The bufferSpace +parameter is used to set a limit on the amount of bufferSpace +allocated by the receiver per active NormSender within the +session. The appropriate bufferSpace +to use is a function of expected network delay*bandwidth +product and packet loss characteristics. A discussion of trade-offs +associated with NORM transmit and receiver buffer space selection is +provided later in this document. An insufficient bufferSpace +allocation will result in potentially inefficient protocol operation, +even though reliable operation may be maintained. In some cases of a +large delay*bandwidth product and/or severe packet loss, a +small bufferSpace allocation +(coupled with the lack of explicit flow control in NORM) may result +in the receiver "re-syncing" to the sender, resulting in +"outages" in the reliable transmissions from a sender (this +is similar to the conditions resulting in a TCP connection timeout +failure). +

+

Return Values

+

A value of true +is returned upon success and false +upon failure. The reasons failure may occur include limited system +resources or that the network sockets required for session +communication failed to open or properly configure.

+

NormStopReceiver()

+

Synopsis

+

#include +<normApi.h>

+

void +NormStopReceiver(NormSessionHandle session, +
                      unsigned +int      gracePeriod = 0);

+

Description

+

This function ends the +application's participation as a receiver in the NormSession +specified by the session +parameter. By default, all receiver-related protocol activity is +immediately halted and all receiver-related resources are freed +(except for those which have been specifically retained (see +NormObjectRetain()). However, and +optional gracePeriod parameter is +provided to allow the receiver an opportunity to inform the group of +its intention. This is applicable when the local receiving NormNode +has been designated as an active congestion control representative +(i.e. current limiting receiver (CLR) or potential limiting receiver +(PLR)). In this case, a non-zero gracePeriod +value provides an opportunity for the receiver to respond to the +applicable sender(s) so the sender will not expect further congestion +control feedback from this receiver. The gracePeriod +integer value is used as a multiplier with the largest sender GRTT to +determine the actual time period for which the receiver will linger +in the group to provide such feedback (i.e. "grace time" = +(gracePeriod * GRTT)). + During this time, the receiver will not generate any requests for +repair or other protocol actions aside from response to applicable +congestion control probes. When the receiver is removed from the +current list of receivers in the sender congestion control probe +messages (or the gracePeriod +expires, whichever comes first), the NORM protocol engine will post a +NORM_LOCAL_RECEIVER_CLOSED event +for the applicable session, and +related resources are then freed.

+

Return Values

+

This function has no +return values.

+

NormSetSilentReceiver()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetSilentReceiver(NormSessionHandle session, +
                           bool              silent);

+

Description

+

This function provides +the option to configure a NORM receiver application as a "silent +receiver". This mode of receiver operation dictates that the +host does not generate any protocol messages while operating as a +receiver within the specified session. + Setting the silent parameter to +true enables silent receiver +operation while setting it to false +results in normal protocol operation where feedback is provided as +needed for reliability and protocol operation. Silent receivers are +dependent upon proactive FEC transmission (see NormSetAutoParity()) +or using repair information requested by other non-silent receivers +within the group to achieve reliable transfers.

+

Return Values

+

This function has no +return values.

+

NormSetDefaultUnicastNack()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetDefaultUnicastNack(NormSessionHandle session, +
                               bool              state);

+

Description

+

This function controls +the default behavior determining the destination of receiver feedback +messages generated while participating in the session. If state +is true, "unicast NACKing" is enabled for new remote +senders while it is disabled for state +equal to false. The NACKing behavior for current remote senders is +not affected. When "unicast NACKing" is disabled +(default), NACK messages are sent to the session address (usually a +multicast address) and port, but "unicast NACKing", when +enabled, causes receiver feedback messages to be sent to the unicast +address (and port) based on the source address of sender messages +received. For unicast NORM sessions, it is recommended that "unicast +NACKing" be enabled. Note that receiver feedback messages +subject to the state of "unicast NACKing" include +NACK-messages as well as some ACK messages such as congestion control +feedback. Explicitly solicited ACK messages, such as those used to +satisfy sender watermark acknowledgement requests (see +NormSetWatermark()) are always unicast to +the applicable sender. (TBD – provide API option so that all +messages are multicast.) The default session-wide behavior for +unicast NACKing can be overridden via the NormNodeSetUnicastNack() +function for individual remote senders.

+

Return Values

+

This function has no +return values.

+

NormNodeSetUnicastNack()

+

Synopsis

+

#include +<normApi.h>

+

void +NormNodeSetUnicastNack(NormNodeHandle senderNode, +
                            bool           state);

+

Description

+

This function controls +the the destination address of receiver feedback messages generated +in response to a specific remote NORM sender.. If state +is true, "unicast NACKing" is enabled while it is disabled +for state equal to false. See the +description of NormSetDefaultUnicastNack() +for details on 'unicast NACKing" behavior.

+

Return Values

+

This function has no +return values.

+

NormSetDefaultNackingMode()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetDefaultNackingMode(NormSessionHandle session, +
                               NormNackingMode   nackingMode);

+

Description

+

This function sets the +default "nacking mode" used when receiving objects. This +allows the receiver application some control of its degree of +participation in the repair process. By limiting receivers to only +request repair of objects in which they are really interested in +receiving, some overall savings in unnecessary network loading might +be realized. Available nacking modes include:

+ + + + + + + + + + + + + + + +
+

NORM_NACK_NONE

+
+

+ Do not transmit any repair requests for the newly received object.

+
+

NORM_NACK_INFO_ONLY

+
+

+ Transmit repair requests for NORM_INFO content only as needed.

+
+

NORM_NACK_NORMAL

+
+

+ Transmit repair requests for entire object as needed.

+
+

This function specifies +the default behavior with respect to any new sender or object. + This default behavior may be overridden for specific sender nodes or +specific object using NormNodeSetNackingMode() +or NormObjectSetNackingMode(), +respectively. The receiver application's use of NORM_NACK_NONE +essentially disables a guarantee of reliable reception, although the +receiver may still take advantage of sender repair transmissions in +response to other receivers' requests. When the sender provides, +NORM_INFO content for transmitted objects, the NORM_NACK_INFO_ONLY +mode may allows the receiver to reliably receive object context +information from which it may choose to "upgrade" its +nacking mode for the specific object via the +NormObjectSetNackingMode() call. +Similarly, the receiver may changes its default nacking mode with +respect to specific senders via the NormNodeSetNackingMode() +call. The default "default nacking mode" when this call is +not made is NORM_NACK_NORMAL.

+

Return Values

+

This function has no +return values.

+

NormNodeSetNackingMode()

+

Synopsis

+

#include +<normApi.h>

+

void +NormNodeSetNackingMode(NormNodeHandle  nodeHandle, +
                            NormNackingMode +nackingMode);

+

Description

+

This function sets the +default "nacking mode" used for receiving new objects from +a specific sender as identified by the nodeHandle +parameter. This overrides the default nacking mode set for the +receive session. See +NormSetDefaultNackingMode() for a description of possible +nackingMode parameter values and +other related information.

+

Return Values

+

This function has no +return values.

+

NormObjectSetNackingMode()

+

Synopsis

+

#include +<normApi.h>

+

void +NormObjectSetNackingMode(NormObjectHandle objectHandle, +
                              NormNackingMode  nackingMode);

+

Description

+

This function sets the +"nacking mode" used for receiving a specific transport +object as identified by the objectHandle +parameter. This overrides the default nacking mode set for the +applicable sender node. See +NormSetDefaultNackingMode() for a description of possible +nackingMode parameter values and +other related information.

+

Return Values

+

This function has no +return values.

+

NormSetDefaultRepairBoundary()

+

Synopsis

+

#include +<normApi.h>

+

void +NormSetDefaultRepairBoundary(NormSessionHandle  sessionHandle, +
                                  NormRepairBoundary +repairBoundary);

+

Description

+

This function allows +the receiver application to customize, for a given sessionHandle, +at what points the receiver initiates the NORM NACK repair process +during protocol operation. Normally, the NORM receiver initiates +NACking for repairs at the FEC code block and transport object +boundaries. For smaller block sizes, the NACK repair process is +often/quickly initiated and the repair of an object will occur, as +needed, during the transmission of the object. This default +operation corresponds to repairBoundary +equal to NORM_BOUNDARY_BLOCK. +Using this function, the application may alternatively, setting +repairBoundary equal to NORM_BOUNDARY_OBJECT, +cause the protocol to defer NACK process initiation until the current +transport object has been completely transmitted. This mode of +operation may be useful when it is desirable to allow receivers with +high quality network connectivity (perhaps requiring only a little +(or even no) "auto parity" (see NormSetAutoParity()) +to achieve reliable transfer) receive object transmission before any +extensive repair process that may be required to satisfy other +receivers with poor network connectivity. The repair boundary can +also be set for individual remote senders using the +NormNodeSetRepairBoundary() function.

+

Return Values

+

This function has no +return values.

+

NormNodeSetRepairBoundary()

+

Synopsis

+

#include +<normApi.h>

+

void +NormNodeSetRepairBoundary(NormNodeHandle     nodeHandle, +
                               NormRepairBoundary +repairBoundary);

+

Description

+

This function allows +the receiver application to customize, for the specific remote sender +referenced by the nodeHandle +parameter, at what points the receiver initiates the NORM NACK repair +process during protocol operation. See the description of +NormSetDefaultRepairBoundary() for +further details on the impact of setting the NORM receiver repair +boundary and possible values for the repairBoundary +parameter.

+

Return Values

+

This function has no +return values.

+

NormStreamRead()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormStreamRead(NormObjectHandle +streamHandle,
                    char*            buffer
                    unsigned +int*    numBytes);

+

Description

+

This function can be +used by the receiver application to read any available data from an +incoming NORM stream. NORM receiver applications "learn" +of available NORM streams via NORM_RX_OBJECT_NEW +notification events. The streamHandle +parameter here must correspond to a valid NormObjectHandle +value provided during such a prior +NORM_RX_OBJECT_NEW notification. The buffer +parameter must be a pointer to an array where the received data can +be stored of a length as referenced by the numBytes +pointer. On successful completion, the numBytes +storage will be modified to indicate the actual number of bytes +copied into the provided buffer. +If the numBytes storage is +modified to a zero value, this indicates that no stream data was +currently available for reading.

+

Note that +NormStreamRead() is never a blocking call +and only returns failure (false) +when a break in the integrity of the received stream occurs. The +NORM_RX_OBJECT_UPDATE provides an +indication to when there is stream data available for reading. When +such notification occurs, the application should repeatedly +read from the stream until the numBytes +storage is set to zero, even if a false +value is returned. Additional NORM_RX_OBJECT_UPDATE +notifications might not be posted until the application can has read +all available data.

+

Return Values

+

This function normally +returns a value of true. However, if a break in the integrity of the +reliable received stream occurs, a value of false is returned to +indicate the break. The application may continue to read from the +stream as the NORM protocol will automatically "resync" to +streams, even if network conditions are sufficiently poor that breaks +in reliability occur. If such a "break" and "resync" +occurs, the application may be able to leverage other NORM API calls +such as NormStreamSeekMsgStart() or +NormStreamGetOffset() if needed to +recover its alignment with received stream content. This depends +upon the nature of the application and its stream content.

+

NormStreamSeekMsgStart()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormStreamSeekMsgStart(NormObjectHandle streamHandle);

+

Description

+

This function advances +the read offset of the receive stream referenced by the streamHandle +parameter to align with the next available message boundary. Message +boundaries are defined by the sender application using the +NormStreamMarkEom() call. Note that any +received data prior to the next message boundary is discarded by the +NORM protocol engine and is not available to the application (i.e., +there is currently no "rewind" function for a NORM stream). + Also note this call cannot be used to skip messages. Once a valid +message boundary is found, the application must read from the +stream using NormStreamRead() to further +advance the read offset. The current offset (in bytes) for the +stream can be retrieved via NormStreamGetReadOffset().

+

Return Values

+

This function returns a +value of true when +start-of-message is found. The next call to NormStreamRead() +will retrieve data aligned with the message start. If no new message +boundary is found in the buffered receive data for the stream, the +function returns a value of false. + In this case, the application should defer repeating a call to this +function until a subsequent NORM_RX_OBJECT_UPDATE +notification is posted.

+

NormStreamGetReadOffset()

+

Synopsis

+

#include +<normApi.h>

+

unsigned +long NormStreamGetReadOffset(NormObjectHandle streamHandle);

+

Description

+

This function retrieves +the current read offset value for the receive stream indicated by the +streamHandle parameter. Note that +for very long-lived streams, this value may wrap. Thus, in general, +applications should not be highly dependent upon the stream offset, +but this feature may be valuable for certain applications which +associate some application context with stream position.

+

Return Values

+

This function returns +the current read offset in bytes. The return value is undefined for +sender streams. There is no error result. +

+

NORM Object Functions

+

The functions described +in this section may be used for sender or receiver purposes to manage +transmission and reception of NORM transport objects. In most cases, +the receiver will be the typical user of these functions to retrieve +additional information on newly-received objects. All of these +functions require a valid NormObjectHandle +argument which specifies the applicable object. Note that +NormObjectHandle values obtained from a +NormEvent notification may be considered +valid only until a subsequent call to NormGetNextEvent(), +unless explicitly retained by the application (see +NormObjectRetain()). NormObjectHandle +values obtained as a result of NormFileEnqueue(), +NormDataEnqueue(), or NormOpenStream() +calls can be considered valid only until a corresponding +NORM_TX_OBJECT_PURGED notification +is posted or the object is dequeued using NormCancelObject(), +unless, again, otherwise explicitly retained (see +NormObjectRetain()).

+

NormObjectGetType()

+

Synopsis

+

#include +<normApi.h>

+

NormObjectType +NormObjectGetType(NormObjectHandle objectHandle);

+

Description

+

This function can be +used to determine the object type (NORM_OBJECT_DATA, +NORM_OBJECT_FILE, or +NORM_OBJECT_STREAM) for the NORM +transport object identified by the objectHandle +parameter. The objectHandle must +refer to a current, valid transport object.

+

Return Values

+

This function returns +the NORM object type. Valid NORM object types include +NORM_OBJECT_DATA, +NORM_OBJECT_FILE, or +NORM_OBJECT_STREAM. A type value +of NORM_OBJECT_NONE will be +returned for an objectHandle value of NORM_OBJECT_INVALID.

+

NormObjectHasInfo()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormObjectHasInfo(NormObjectHandle objectHandle);

+

Description

+

This function can be +used to determine if the sender has associated any NORM_INFO content +with the transport object specified by the objectHandle +parameter. This can even be used before the NORM_INFO content +is delivered to the receiver and a NORM_RX_OBJECT_INFO +notification is posted.

+

Return Values

+

A value of true +is returned if NORM_INFO is (or will be) available for the specified +transport object. A value of false +is returned otherwise.

+

NormObjectGetInfoLength()

+

Synopsis

+

#include +<normApi.h>

+

unsigned +short NormObjectGetInfoLength(NormObjectHandle objectHandle);

+

Description

+

This function can be +used to determine the length of currently available NORM_INFO content +(if any) associated with the transport object referenced by the +objectHandle parameter.

+

Return Values

+

The length of the +NORM_INFO content, in bytes, of currently available for the specified +transport object is returned. A value of 0 +is returned if no NORM_INFO content is currently available or +associated with the object.

+

NormObjectGetInfo()

+

Synopsis

+

#include +<normApi.h>

+

unsigned +short NormObjectGetInfo(NormObjectHandle +objectHandle,
                                 char*            buffer,
                                 unsigned +short   bufferLen);

+

Description

+

This function copies +any NORM_INFO content associated (by the sender application) with the +transport object specified by objectHandle +into the provided memory space referenced by the buffer +parameter. The bufferLen +parameter indicates the length of the buffer +space in bytes. If the provided bufferLen +is less than the actual NORM_INFO length, a partial copy will occur. +The actual length of NORM_INFO content available for the specified +object is returned. However, note that until a NORM_RX_OBJECT_INFO +notification is posted to the receive application, no NORM_INFO +content is available and a zero result will be returned, even if +NORM_INFO content may be subsequently available. The +NormObjectHasInfo() call can be used to +determine if any NORM_INFO content will ever be available for a +specified transport object (i.e., determine if the sender has +associated any NORM_INFO with the object in question).

+

Return Values

+

The actual length of +currently available NORM_INFO content for the specified +transport object is returned. This function can be used to determine +the length of NORM_INFO content for the object even if a NULL +buffer value and zero bufferLen +is provided. A zero value is returned if NORM_INFO content has not +yet been received (or is non-existent) for the specified object.

+

NormObjectGetSize()

+

Synopsis

+

#include +<normApi.h>

+

off_t +NormObjectHasInfo(NormObjectHandle objectHandle);

+

Description

+

This function can be +used to determine the size (in bytes) of the transport object +specified by the objectHandle +parameter. NORM can support large object sizes for the +NORM_OBJECT_FILE type, so +typically the NORM library is built with any necessary, related +macros defined such that operating system large file support is +enabled (e.g., "#define _FILE_OFFSET_BITS +64" or equivalent). Developers should configure their +build environment to correspond with the NORM library used to ensure +that the "off_t" +type is appropriately defined. +

+

For objects of type +NORM_OBJECT_STREAM, the size +returned here corresponds to the stream buffer size set by the sender +application when opening the referenced stream object.

+

Return Values

+

A size of the data +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.

+

NormObjectCancel()

+

Synopsis

+

#include +<normApi.h>

+

void +NormObjectCancel(NormObjectHandle objectHandle);

+

Description

+

This function +immediately cancels the transmission of a local sender transport +object or the reception of a specified object from a remote sender as +specified by the objectHandle +parameter. The objectHandle must +refer to a currently valid NORM transport object. Any resources used +by the transport object in question are immediately freed unless the +object has been otherwise retained by the application via the +NormObjectRetain() call. Unless the +application has retained the object in such fashion, the object in +question should be considered invalid and the application must not +again reference the objectHandle +after this call is made. +

+

If the canceled object +is a sender object not completely received by participating +receivers, the receivers will be informed of the object's +cancellation via the NORM protocol NORM_CMD(SQUELCH) message in +response to any NACKs requesting repair or retransmission of the +applicable object. In the case of receive objects, the NORM receiver +will not make further requests for repair of the indicated object, +but furthermore, will acknowledge the object as completed with +respect to any associated positive acknowledgement requests (see +NormSetWatermark()).

+

Return Values

+

This function has no +return value.

+

NormObjectRetain()

+

Synopsis

+

#include +<normApi.h>

+

void +NormObjectRetain(NormObjectHandle objectHandle);

+

Description

+

This function "retains" +the objectHandle and any state +associated with it for further use by the application even when the +NORM protocol engine may no longer require access to the associated +transport object. Normally, the application is guaranteed that a +given NormObjectHandle is valid only +while it is being actively transported by NORM (i.e., for sender +objects, from the time an object is created by the application until +it is canceled by the application or purged (see the +NORM_TX_OBJECT_PURGED +notification) by the protocol engine, or, for receiver objects, from +the time of the object's NORM_RX_OBJECT_NEW +notification until its reception is canceled by the application or a +NORM_RX_OBJECT_COMPLETED or +NORM_RX_OBJECT_ABORTED +notification is posted). Note that an application may refer to a +given object after any related notification until the application +makes a subsequent call to NormGetNextEvent(). + +

+

When the application +makes a call to NormObjectRetain() for a +given objectHandle, the +application may use that objectHandle +value in any NORM API calls until the application makes a call to +NormObjectRelease() for the given object. + Note that the application MUST make a corresponding call to +NormObjectRelease() for each call it has +made to NormObjectRetain() in order to +free any system resources (i.e., memory) used by that object. Also +note that retaining a receive object also automatically retains any +state associated with the NormNodeHandle +corresponding to the remote sender of that receive object so +that the application may use NORM node API calls for the value +returned by NormObjectGetSender() as +needed.

+

Return Values

+

This function has no +return value.

+

NormObjectRelease()

+

Synopsis

+

#include +<normApi.h>

+

void +NormObjectRelease(NormObjectHandle objectHandle);

+

Description

+

This function +complements the NormObjectRetain() call +by immediately freeing any resources associated with the given +objectHandle, assuming the +underlying NORM protocol engine no longer requires access to the +corresponding transport object. Note the NORM protocol engine +retains/releases state for associated objects for its own needs and +thus it is very unsafe for an application to call NormObjectRelease() +for an objectHandle for which it +has not previously explicitly retained via NormObjectRetain(). + +

+

Return Values

+

This function has no +return value.

+

NormFileGetName()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormFileGetName(NormObjectHandle +fileHandle)
                     char*            nameBuffer,
                     unsigned +int     bufferLen);

+

Description

+

This function copies +the name, as a NULL-terminated string, of the file object specified +by the fileHandle parameter into +the nameBuffer of length bufferLen +bytes provided by the application. The fileHandle +parameter must refer to a valid NormObjectHandle +for an object of type NORM_OBJECT_FILE. If the actual name is longer +than the provided bufferLen, a +partial copy will occur. Note that the file name consists of the +entire path name of the specified file object and the application +should give consideration to operating system file path lengths when +providing the nameBuffer.

+

Return Values

+

This function returns +true upon success and false upon failure. Possible failure +conditions include the fileHandle +does not refer to an object of type NORM_OBJECT_FILE.

+

NormFileRename()

+

Synopsis

+

#include +<normApi.h>

+

bool +NormFileRename(NormObjectHandle fileHandle)
                    const +char*      fileName);

+

Description

+

This function renames +the file used to store content for the NORM_OBJECT_FILE +transport object specified by the fileHandle +parameter. This allows receiver applications to rename (or move) +received files as needed. NORM uses temporary file names for +received files until the application explicitly renames the file. +For example, sender applications may choose to use the NORM_INFO +content associated with a file object to provide name and/or typing +information to receivers. The fileName +parameter must be a NULL-terminated string which should specify the +full desired path name to be used. NORM will attempt to create +sub-directories as needed to satisfy the request. Note that existing +files of the same name may be overwritten.

+

Return Values

+

This function returns +true upon success and false upon failure. Possible failure +conditions include the case where the fileHandle +does not refer to an object of type NORM_OBJECT_FILE +and where NORM was unable to successfully create any needed +directories and/or the file itself.

+

NormDataAccessData()

+

Synopsis

+

#include +<normApi.h>

+

const +char* NormDataAccessData(NormObjectHandle objectHandle)

+

Description

+

This function allows +the application to access the data storage area associated with a +transport object of type NORM_OBJECT_DATA. + For example, the application may use this function to copy the +received data content for its own use. Alternatively, the +application may establish "ownership" for the allocated +memory space using the NormDataDetachData() +function if it is desired to avoid the copy.

+

If the object specified +by the objectHandle parameter has +no data content (or is not of type NORM_OBJECT_DATA), +a NULL value may be returned. The application MUST NOT attempt to +modify the memory space used by NORM_OBJECT_DATA +objects during the time an associated objectHandle +is valid. The length of data storage area can be determined with a +call to NormObjectGetSize() for the same +objectHandle value.

+

Return Values

+

This function returns a +pointer to the data storage area for the specified transport object. +A NULL value may be returned if the object has no associated data +content or is not of type NORM_OBJECT_DATA.

+

NormDataDetachData()

+

Synopsis

+

#include +<normApi.h>

+

char* +NormDataDetachData(NormObjectHandle objectHandle)

+

Description

+

This function allows +the application to disassociate data storage allocated by the NORM +protocol engine for a receive object from the NORM_OBJECT_DATA +transport object specified by the objectHandle +parameter. It is important that this function is called after +the NORM protocol engine has indicated it is finished with the data +object (i.e., after a NORM_TX_OBJECT_PURGED, +NORM_RX_OBJECT_COMPLETED, or +NORM_RX_OBJECT_ABORTED +notification event). But the application must call +NormDataDetachData() before a call +is made to NormObjectCancel() or +NormObjectRelease() for the object if it +plans to access the data content afterwards. Otherwise, the NORM +protocol engine will free the applicable memory space when the +associated NORM_OBJECT_DATA +transport object is deleted and the application will be unable to +access the received data unless it has previously copied the content.

+

Once the application +has used this call to "detach" the data content, it is the +application's responsibility to subsequently free the data storage +space as needed.

+

Return Values

+

This function returns a +pointer to the data storage area for the specified transport object. +A NULL value may be returned if the object has no associated data +content or is not of type NORM_OBJECT_DATA.

+

NormObjectGetSender()

+

Synopsis

+

#include +<normApi.h>

+

NormNodeHandle +NormObjectGetSender(NormObjectHandle objectHandle)

+

Description

+

This function retrieves +the NormNodeHandle corresponding to the +remote sender of the transport object associated with the given +objectHandle parameter. Note that +the returned NormNodeHandle value is only +valid for the same period that the objectHandle +is valid. The returned NormNodeHandle +may optionally be retained for further use by the application using +the NormNodeRetain() function call. The +returned value can be used in the NORM Node Functions described later +in this document.

+

Return Values

+

This function returns +the NormNodeHandle corresponding to the +remote sender of the transport object associated with the given +objectHandle parameter. A value +of NORM_NODE_INVALID is returned if the specified objectHandle +references a locally originated, sender object.

+

NORM Node Functions

+

The functions described +in this section may be used for NORM sender or receiver (most +typically receiver) purposes to retrieve additional information about +a NormNode, given a valid NormNodeHandle. + Note that, unless specifically retained (see NormNodeRetain()), +a NormNodeHandle provided in a NormEvent +notification should be considered valid only until a subsequent call +to NormGetNextEvent() is made. +NormNodeHandles retrieved using +NormObjectGetSender() can be considered +valid for the same period of time as the corresponding +NormObjectHandle is valid.

+

NormNodeGetId()

+

Synopsis

+

#include +<normApi.h>

+

NormNodeId +NormNodeGetId(NormNodeHandle nodeHandle)

+

Description

+

This function retrieves +the NormNodeId identifier for the remote +participant referenced by the given nodeHandle +value. The NormNodeId is a 32-bit value used within the NORM +protocol to uniquely identify participants within a NORM session. +The participants identifiers are assigned by the application or +derived (by the NORM API code) from the host computers default IP +address.

+

Return Values

+

This function returns +the NormNodeId value associated with the +specified nodeHandle. In the case +nodeHandle is equal to +NORM_NODE_INVALID, the return +value will be NORM_NODE_NONE.

+

NormNodeRetain()

+

Synopsis

+

#include +<normApi.h>

+

void +NormNodeRetain(NormNodeHandle nodeHandle)

+

Description

+

In the same manner as +the NormObjectRetain() function, this +function allows the application to retain state associated with a +given nodeHandle value even when +the underlying NORM protocol engine might normally free the +associated state and thus invalidate the NormNodeHandle. + If the application uses this function, it must make a corresponding +call to NormNodeRelease() when finished +with the node information to avoid a memory leak condition. +NormNodeHandle values (unless retained) +are valid from the time of a NORM_REMOTE_SERVER_NEW +notification until a complimentary NORM_REMOTE_SERVER_PURGED +notification. During that interval, the application will receive +NORM_REMOTE_SERVER_ACTIVE and +NORM_REMOTE_SERVER_INACTIVE +notifications according to the server's message transmission activity +within the session.

+

It is important to note +that, if the NORM protocol engine posts a NORM_REMOTE_SERVER_PURGED +notification for a given NormNodeHandle, +the NORM protocol engine could possibly, subsequently establish a +new, different NormNodeHandle value for +the same remote server (i.e., one of equivalent NormNodeId) +if it again becomes active in the session. A new NormNodeHandle +may likely be established even if the application has retained the +previous NormNodeHandle value. +Therefore, to the application, it might appear that two different +servers with the same NormNodeId are +participating if these notifications are not carefully monitored. +This behavior is contingent upon how the application has configured +the NORM protocol engine to manage resources when there is potential +for a large number of remote servers within a session (related APIs +are TBD). For example, the application may wish to control which +specific remote servers for which it keeps state (or limit the memory +resources used for remote servers state, etc) and the NORM API may be +extended in the future to control this behavior.

+

Return Values

+

This function has no +return value.

+

NormNodeRelease()

+

Synopsis

+

#include +<normApi.h>

+

void +NormNodeRelease(NormNodeHandle nodeHandle)

+

Description

+

In complement to the +NormNodeRetain() function, this API call +releases the specified nodeHandle +so that the NORM protocol engine may free associated resources as +needed. Once this call is made, the application should no longer +reference the specified NormNodeHandle, +unless it is still valid.

+

Return Values

+

This function has no +return value.

+ + diff --git a/NormDeveloperGuide.pdf b/NormDeveloperGuide.pdf new file mode 100644 index 0000000..52240ee Binary files /dev/null and b/NormDeveloperGuide.pdf differ diff --git a/VERSION.TXT b/VERSION.TXT index 6e62914..ed35c8e 100644 --- a/VERSION.TXT +++ b/VERSION.TXT @@ -1,9 +1,14 @@ NORM Version History +Version 1.2b5 +============= + - Initial release with theoretically-working API + (including "Norm Developer's Guide!") + Version 1.2b4 ============= - Finally remembered to update this file! - - Added "help" command to "norm" demo app (Thanks Marinho Barcellos) + - Added "help" command to "norm" demo app (Thanks Marinho Barcellos!) - New rxbuffer mgmnt scheme to better use limited buffer space. - Removed explicit rate limit on receiver feedback messages - API more complete and established better API naming conventions @@ -12,6 +17,7 @@ Version 1.2b4 - NORM RFC 3940 was released and this version is in compliance. - Added optional positive acknowledgements for sender-defined "watermarks". + - Fixed multicast leave problem when interfaceName was used for join Version 1.1b9 ============= diff --git a/common/normApi.cpp b/common/normApi.cpp index d1311ec..5df047f 100644 --- a/common/normApi.cpp +++ b/common/normApi.cpp @@ -10,6 +10,11 @@ const NormNodeId NORM_NODE_NONE = ((NormNodeId)0x00000000); const NormNodeId NORM_NODE_ANY = ((NormNodeId)0xffffffff); const NormObjectHandle NORM_OBJECT_INVALID = ((NormObjectHandle)0); +/** The "NormInstance" class is a C++ helper class that keeps + * state for an instance of the NORM API. It acts as a + * "go between" the API's procedural function calls and + * the underlying NORM C++ implementation + */ class NormInstance : public NormController { public: @@ -48,6 +53,11 @@ class NormInstance : public NormController NormSession* session = (NormSession*)sessionHandle; return static_cast(session->GetSessionMgr().GetController()); } + static NormInstance* GetInstanceFromNode(NormNodeHandle nodeHandle) + { + NormSession& session = ((NormNode*)nodeHandle)->GetSession(); + return static_cast(session.GetSessionMgr().GetController()); + } static NormInstance* GetInstanceFromObject(NormObjectHandle objectHandle) { NormSession& session = ((NormObject*)objectHandle)->GetSession();; @@ -209,7 +219,7 @@ void NormInstance::Notify(NormController::Event event, { case RX_OBJECT_NEW: { - // recv object "Accept()" policy implemented here + // new recv object "Accept()" policy implemented here switch (object->GetType()) { case NormObject::STREAM: @@ -265,8 +275,27 @@ void NormInstance::Notify(NormController::Event event, } break; } + case NormObject::DATA: + { + NormDataObject* dataObj = static_cast(object); + unsigned int dataLen = (unsigned int)(object->GetSize().GetOffset()); + char* dataPtr = new char[dataLen]; + if (NULL == dataPtr) + { + DMSG(0, "NormInstance::Notify(RX_OBJECT_NEW) new dataPtr error: %s\n", + GetErrorString()); + return; + } + // Note that the "true" parameter means the + // NORM protocol engine will free the allocated + // data on object deletion, so the app should + // use NormDataDetachData() to keep the received + // data (or copy it before the data object is deleted) + dataObj->Accept(dataPtr, dataLen, true); + break; + } default: - // (TBD) support other object types + // This shouldn't occur return; } // end switch(object->GetType()) break; @@ -329,7 +358,7 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent) // First, do any garbage collection for "previous_notification" if (NULL != previous_notification) { - // (TBD) "Release" purged/completed/aborted objects + // "Release" any purged/completed/aborted objects switch(previous_notification->event.type) { case NORM_RX_OBJECT_COMPLETED: @@ -366,7 +395,7 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent) { case NORM_EVENT_INVALID: continue; - case NORM_RX_OBJECT_UPDATE: + case NORM_RX_OBJECT_UPDATED: // reset update event notification ((NormObject*)n->event.object)->SetNotifyOnUpdate(true); break; @@ -480,6 +509,7 @@ void NormInstance::Shutdown() default: break; } + notify_pool.Append(previous_notification); previous_notification = NULL; } @@ -494,9 +524,6 @@ void NormInstance::Shutdown() NormObject* obj = (NormObject*)n->event.object; switch (obj->GetType()) { - case NormObject::DATA: - delete (char*)static_cast(obj)->GetData(); - break; case NormObject::FILE: // (TBD) unlink temp file? break; @@ -525,6 +552,8 @@ void NormInstance::Shutdown() // NORM API FUNCTION IMPLEMENTATIONS // +/** NORM API Initialization */ + NormInstanceHandle NormCreateInstance() { NormInstance* normInstance = new NormInstance; @@ -543,6 +572,36 @@ void NormDestroyInstance(NormInstanceHandle instanceHandle) delete ((NormInstance*)instanceHandle); } // end NormDestroyInstance() +bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, + const char* cachePath) +{ + NormInstance* instance = (NormInstance*)instanceHandle; + if (instance) + return instance->SetCacheDirectory(cachePath); + else + return false; +} // end NormSetCacheDirectory() + +bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent) +{ + bool result = false; + NormInstance* instance = (NormInstance*)instanceHandle; + if (instance) + { + if (instance->NotifyQueueIsEmpty()) //(TBD) perform this check??? + instance->WaitForEvent(); + if (instance->dispatcher.SuspendThread()) + { + result = instance->GetNextEvent(theEvent); + instance->dispatcher.ResumeThread(); + } + } + return result; +} // end NormGetNextEvent() + + +/** NORM Session Creation and Control Functions */ + NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle, const char* sessionAddr, unsigned short sessionPort, @@ -577,27 +636,6 @@ void NormDestroySession(NormSessionHandle sessionHandle) } } // end NormDestroySession() -void NormSetTransmitRate(NormSessionHandle sessionHandle, - double bitsPerSecond) -{ - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) session->SetTxRate(bitsPerSecond); - instance->dispatcher.ResumeThread(); - } -} // end NormSetTransmitRate() - -void NormSetGrttEstimate(NormSessionHandle sessionHandle, - double grttEstimate) -{ - // (TBD) suspend instance if timer reschedule is - // added to ServerSetGrtt() method. - NormSession* session = (NormSession*)sessionHandle; - if (session) session->ServerSetGrtt(grttEstimate); -} // end NormSetGrttEstimate() - NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle) { NormSession* session = (NormSession*)sessionHandle; @@ -607,6 +645,62 @@ NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle) return NORM_NODE_NONE; } // end NormGetLocalNodeId() +bool NormSetMulticastInterface(NormSessionHandle sessionHandle, + const char* interfaceName) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance) + { + if (instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + result = session->SetMulticastInterface(interfaceName); + instance->dispatcher.ResumeThread(); + } + } + return result; +} // end NormSetMulticastInterface() + +bool NormSetTTL(NormSessionHandle sessionHandle, + unsigned char ttl) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance) + { + if (instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + result = session->SetTTL(ttl); + instance->dispatcher.ResumeThread(); + } + } + return result; +} // end NormSetTTL() + +bool NormSetTOS(NormSessionHandle sessionHandle, + unsigned char tos) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance) + { + if (instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + result = session->SetTTL(tos); + instance->dispatcher.ResumeThread(); + } + } + return result; +} // end NormSetTOS() + +/** Special test/debug support functions */ + bool NormSetLoopback(NormSessionHandle sessionHandle, bool state) { NormSession* session = (NormSession*)sessionHandle; @@ -616,6 +710,27 @@ bool NormSetLoopback(NormSessionHandle sessionHandle, bool state) return false; } // end NormSetLoopback() +void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state) +{ + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetTrace(state); +} // end NormSetMessageTrace() + +void NormSetTxLoss(NormSessionHandle sessionHandle, double percent) +{ + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetTxLoss(percent); +} // end NormSetTxLoss() + +void NormSetRxLoss(NormSessionHandle sessionHandle, double percent) +{ + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetRxLoss(percent); +} // end NormSetRxLoss() + + +/** NORM Sender Functions */ + bool NormStartSender(NormSessionHandle sessionHandle, unsigned long bufferSpace, unsigned short segmentSize, @@ -647,6 +762,251 @@ void NormStopSender(NormSessionHandle sessionHandle) } } // end NormStopSender() +void NormSetTransmitRate(NormSessionHandle sessionHandle, + double bitsPerSecond) +{ + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetTxRate(bitsPerSecond); + instance->dispatcher.ResumeThread(); + } +} // end NormSetTransmitRate() + +void NormSetCongestionControl(NormSessionHandle sessionHandle, bool enable) +{ + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetCongestionControl(enable); + instance->dispatcher.ResumeThread(); + } +} // end NormSetCongestionControl() + +void NormSetTransmitRateBounds(NormSessionHandle sessionHandle, + double rateMin, + double rateMax) +{ + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) session->SetTxRateBounds(rateMin, rateMax); + instance->dispatcher.ResumeThread(); + } +} // end NormSetTransmitRateBounds() + +void NormSetAutoParity(NormSessionHandle sessionHandle, unsigned char autoParity) +{ + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) session->ServerSetAutoParity(autoParity); + instance->dispatcher.ResumeThread(); + } +} // end NormSetAutoParity() + +void NormSetGrttEstimate(NormSessionHandle sessionHandle, + double grttEstimate) +{ + // (TBD) suspend instance if timer reschedule is + // added to ServerSetGrtt() method. + NormSession* session = (NormSession*)sessionHandle; + if (session) session->ServerSetGrtt(grttEstimate); +} // end NormSetGrttEstimate() + +bool NormAddAckingNode(NormSessionHandle sessionHandle, + NormNodeId nodeId) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + result = session->ServerAddAckingNode(nodeId); + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormAddAckingNode() + +void NormRemoveAckingNode(NormSessionHandle sessionHandle, + NormNodeId nodeId) +{ + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) session->ServerRemoveAckingNode(nodeId); + instance->dispatcher.ResumeThread(); + } +} // end NormRemoveAckingNode() + +NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, + const char* fileName, + const char* infoPtr, + unsigned int infoLen) +{ + NormObjectHandle objectHandle = NORM_OBJECT_INVALID; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + { + NormObject* obj = session->QueueTxFile(fileName, infoPtr, infoLen); + if (obj) objectHandle = (NormObjectHandle)obj; + } + instance->dispatcher.ResumeThread(); + } + return objectHandle; +} // end NormFileEnqueue() + +NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle, + const char* dataPtr, + unsigned long dataLen, + const char* infoPtr = NULL, + unsigned int infoLen = 0) +{ + NormObjectHandle objectHandle = NORM_OBJECT_INVALID; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + { + NormObject* obj = session->QueueTxData(dataPtr, dataLen, infoPtr, infoLen); + if (obj) objectHandle = (NormObjectHandle)obj; + } + instance->dispatcher.ResumeThread(); + } + return objectHandle; +} // end NormDataEnqueue() + +NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, + unsigned long bufferSize) +{ + NormObjectHandle objectHandle = NORM_OBJECT_INVALID; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + if (session) + { + NormObject* obj = + static_cast(session->QueueTxStream(bufferSize)); + if (obj) objectHandle = (NormObjectHandle)obj; + } + instance->dispatcher.ResumeThread(); + } + return objectHandle; +} // end NormStreamOpen() + +void NormStreamClose(NormObjectHandle streamHandle) +{ + NormObjectCancel(streamHandle); +} // end NormStreamClose() + +unsigned int NormStreamWrite(NormObjectHandle streamHandle, + const char* buffer, + unsigned int numBytes) +{ + unsigned int result = 0; + NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) + result = stream->Write(buffer, numBytes, false); + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormStreamWrite() + +void NormStreamFlush(NormObjectHandle streamHandle, + bool eom, + NormFlushMode flushMode) +{ + NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) stream->Flush(eom); + instance->dispatcher.ResumeThread(); + } +} // end NormStreamFlush() + +void NormStreamSetAutoFlush(NormObjectHandle streamHandle, + NormFlushMode flushMode) +{ + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) + stream->SetFlushMode((NormStreamObject::FlushMode)flushMode); +} // end NormStreamSetAutoFlush() + +void NormStreamSetPushEnable(NormObjectHandle streamHandle, bool state) +{ + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) stream->SetPushMode(state); +} // end NormStreamSetPushEnable() + + +void NormStreamMarkEom(NormObjectHandle streamHandle) +{ + NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) stream->Write(NULL, 0, true); + instance->dispatcher.ResumeThread(); + } +} // end NormStreamMarkEom() + +bool NormSetWatermark(NormSessionHandle sessionHandle, + NormObjectHandle objectHandle) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormSession* session = (NormSession*)sessionHandle; + NormObject* obj = (NormObject*)objectHandle; + if (session && obj) + { + // (segmentId doesn't matter for non-stream) + if (obj->IsStream()) + { + NormStreamObject* stream = static_cast(obj); + session->ServerSetWatermark(stream->GetId(), + stream->FlushBlockId(), + stream->FlushSegmentId()); + } + else + { + NormBlockId blockId = obj->GetFinalBlockId(); + NormSegmentId segmentId = obj->GetBlockSize(blockId) - 1; + session->ServerSetWatermark(obj->GetId(), + blockId, + segmentId); + } + result = true; + } + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormSetWatermark() + + +/** NORM Receiver Functions */ + bool NormStartReceiver(NormSessionHandle sessionHandle, unsigned long bufferSpace) { @@ -676,24 +1036,47 @@ void NormStopReceiver(NormSessionHandle sessionHandle) } } // end NormStopReceiver() -void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state) +void NormSetSilentReceiver(NormSessionHandle sessionHandle, + bool silent) { NormSession* session = (NormSession*)sessionHandle; - if (session) session->SetTrace(state); -} // end NormSetMessageTrace() + if (session) session->ClientSetSilent(silent); +} // end NormSetSilentReceiver() -void NormSetTxLoss(NormSessionHandle sessionHandle, double percent) +void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle, + bool unicastNacks) { NormSession* session = (NormSession*)sessionHandle; - if (session) session->SetTxLoss(percent); -} // end NormSetTxLoss() + if (session) session->ClientSetUnicastNacks(unicastNacks); +} // end NormSetDefaultUnicastNack() -void NormSetRxLoss(NormSessionHandle sessionHandle, double percent) +void NormNodeSetUnicastNack(NormNodeHandle nodeHandle, + bool unicastNacks) +{ + NormServerNode* node = (NormServerNode*)nodeHandle; + if (node) node->SetUnicastNacks(unicastNacks); +} // end NormNodeSetUnicastNack() + +void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, + NormNackingMode nackingMode) { NormSession* session = (NormSession*)sessionHandle; - if (session) session->SetRxLoss(percent); -} // end NormSetRxLoss() + if (session) session->ClientSetDefaultNackingMode((NormObject::NackingMode)nackingMode); +} // end NormSetDefaultNackingMode() +void NormNodeSetNackingMode(NormNodeHandle nodeHandle, + NormNackingMode nackingMode) +{ + NormServerNode* node = (NormServerNode*)nodeHandle; + if (node) node->SetDefaultNackingMode((NormObject::NackingMode)nackingMode); +} // end NormNodeSetNackingMode() + +void NormObjectSetNackingMode(NormObjectHandle objectHandle, + NormNackingMode nackingMode) +{ + NormObject* object = (NormObject*)objectHandle; + if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode); +} // end NormObjectSetNackingMode() void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, NormRepairBoundary repairBoundary) @@ -703,17 +1086,6 @@ void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, session->ClientSetDefaultRepairBoundary((NormServerNode::RepairBoundary)repairBoundary); } // end NormSetDefaultRepairBoundary() - -NormRepairBoundary NormNodeGetRepairBoundary(NormNodeHandle nodeHandle) -{ - NormServerNode* node = static_cast((NormNode*)nodeHandle); - if (node) - return ((NormRepairBoundary)(node->GetRepairBoundary())); - else - return NORM_BOUNDARY_BLOCK; // return default value -} // end NormNodeGetRepairBoundary() - - void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, NormRepairBoundary repairBoundary) { @@ -722,16 +1094,48 @@ void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, node->SetRepairBoundary((NormServerNode::RepairBoundary)repairBoundary); } // end NormNodeSetRepairBoundary() - -NormNodeId NormNodeGetId(NormNodeHandle nodeHandle) +bool NormStreamRead(NormObjectHandle streamHandle, + char* buffer, + unsigned int* numBytes) { - NormNode* node = (NormNode*)nodeHandle; - if (node) - return node->GetId(); - else - return NORM_NODE_NONE; -} // end NormNodeGetId() + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + if (stream) + result = stream->Read(buffer, numBytes); + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormStreamRead() +bool NormStreamSeekMsgStart(NormObjectHandle streamHandle) +{ + bool result = false; + NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormStreamObject* stream = + static_cast((NormObject*)streamHandle); + unsigned int numBytes = 0; + if (stream) + result = stream->Read(NULL, &numBytes, true); + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormStreamSeekMsgStart() + + +unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle) +{ + NormStreamObject* stream = static_cast((NormObject*)streamHandle); + return stream->GetCurrentReadOffset(); +} // end NormStreamGetReadOffset() + + +/** NORM Object Functions */ NormObjectType NormObjectGetType(NormObjectHandle objectHandle) { @@ -741,44 +1145,41 @@ NormObjectType NormObjectGetType(NormObjectHandle objectHandle) return NORM_OBJECT_NONE; } // end NormObjectGetType() -NormObjectTransportId NormObjectGetTransportId(NormObjectHandle objectHandle) +bool NormObjectHasInfo(NormObjectHandle objectHandle) { - // Like many other API calls, these should be changed - // to provide an error code result - if (NORM_OBJECT_INVALID != objectHandle) - return ((NormObjectTransportId)(((NormObject*)objectHandle)->GetId())); - else - return 0; -} // end NormObjectGetTransportId() + return ((NormObject*)objectHandle)->HasInfo(); +} // end NormObjectHasInfo() -bool NormObjectGetInfo(NormObjectHandle objectHandle, - char* infoBuffer, - unsigned short* infoLen) +unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle) { - if ((NORM_OBJECT_INVALID != objectHandle) && infoLen) + return ((NormObject*)objectHandle)->GetInfoLength(); +} // end NormObjectGetInfoLength() + +unsigned short NormObjectGetInfo(NormObjectHandle objectHandle, + char* buffer, + unsigned short bufferLen) +{ + unsigned short result = 0; + if (NORM_OBJECT_INVALID != objectHandle) { - bool result = true; NormObject* object = (NormObject*)objectHandle; if (object->HaveInfo()) { - unsigned short bufferLen = *infoLen; - *infoLen = object->GetInfoLength(); - if (bufferLen >= *infoLen) - bufferLen = *infoLen; - else - result = false; // incomplete copy - if (infoBuffer) - memcpy(infoBuffer, object->GetInfo(), bufferLen); + result = object->GetInfoLength(); + if (result < bufferLen) + bufferLen = result; + if (buffer) + memcpy(buffer, object->GetInfo(), bufferLen); } - else - { - *infoLen = 0; - } - return result; } - return false; + return result; } // end NormObjectGetInfo() +off_t NormObjectGetSize(NormObjectHandle objectHandle) +{ + return ((NormObject*)objectHandle)->GetSize().GetOffset(); +} // end NormObjectGetSize() + void NormObjectCancel(NormObjectHandle objectHandle) { if (NORM_OBJECT_INVALID != objectHandle) @@ -827,274 +1228,6 @@ void NormObjectRelease(NormObjectHandle objectHandle) } } // end NormObjectRelease() -NormNackingMode NormObjectGetNackingMode(NormObjectHandle objectHandle) -{ - NormObject* object = (NormObject*)objectHandle; - if (object) - return ((NormNackingMode)object->GetNackingMode()); - else - return NORM_NACK_NONE; -} // end NormObjectGetNackingMode() - -void NormSetObjectNackingMode(NormObjectHandle objectHandle, - NormNackingMode nackingMode) -{ - NormObject* object = (NormObject*)objectHandle; - if (object) object->SetNackingMode((NormObject::NackingMode)nackingMode); -} // end NormSetObjectNackingMode() - -void NormObjectSetNackingMode(NormNodeHandle nodeHandle, - NormNackingMode nackingMode) -{ - NormServerNode* node = (NormServerNode*)nodeHandle; - if (node) node->SetDefaultNackingMode((NormObject::NackingMode)nackingMode); -} // end NormObjectSetNackingMode() - -void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, - NormNackingMode nackingMode) -{ - NormSession* session = (NormSession*)sessionHandle; - if (session) session->ClientSetDefaultNackingMode((NormObject::NackingMode)nackingMode); -} // end NormSetDefaultNackingMode() - -bool NormSetWatermark(NormSessionHandle sessionHandle, - NormObjectHandle objectHandle) -{ - bool result = false; - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - NormObject* obj = (NormObject*)objectHandle; - if (session && obj) - { - // (TBD) set stream watermark differently - // (segmentId doesn't matter for non-stream) - if (obj->IsStream()) - { - NormStreamObject* stream = static_cast(obj); - session->ServerSetWatermark(stream->GetId(), - stream->FlushBlockId(), - stream->FlushSegmentId()); - } - else - { - NormBlockId blockId = obj->GetFinalBlockId(); - NormSegmentId segmentId = obj->GetBlockSize(blockId) - 1; - session->ServerSetWatermark(obj->GetId(), - blockId, - segmentId); - } - result = true; - } - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormSetWatermark() - -bool NormAddAckingNode(NormSessionHandle sessionHandle, - NormNodeId nodeId) -{ - bool result = false; - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) - result = session->ServerAddAckingNode(nodeId); - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormAddAckingNode() - -void NormRemoveAckingNode(NormSessionHandle sessionHandle, - NormNodeId nodeId) -{ - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) session->ServerRemoveAckingNode(nodeId); - instance->dispatcher.ResumeThread(); - } -} // end NormAddAckingNode() - -NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, - unsigned long bufferSize) -{ - NormObjectHandle objectHandle = NORM_OBJECT_INVALID; - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) - { - NormObject* obj = - static_cast(session->QueueTxStream(bufferSize)); - if (obj) objectHandle = (NormObjectHandle)obj; - } - instance->dispatcher.ResumeThread(); - } - return objectHandle; -} // end NormStreamOpen() - -void NormStreamClose(NormObjectHandle streamHandle) -{ - NormObjectCancel(streamHandle); -} // end NormStreamClose() - - -// (TBD) Some stream i/o performance improvement can be realized -// if the option to make "NormWriteStream()" and -// "NormReadStream()" _blocking_ calls is implemented. -// Right now, the stream read/write are non-blocking -// so applications should use "NormGetNextEvent()" to -// know when to read or write ... This results in the -// underlying NORM thread to be suspended/resumed _twice_ -// per read or write ... It would be more efficient to -// "suspend" the NORM thread while the application -// processes all pending events and _then_ "resume" the -// NORM thread ... an approach to this would be enable -// the app to install an event handler callback and dispatch -// events with a "NormDispatchEvents()" call ... -// - -void NormStreamSetFlushMode(NormObjectHandle streamHandle, - NormFlushMode flushMode) -{ - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) - stream->SetFlushMode((NormStreamObject::FlushMode)flushMode); -} // end NormStreamSetFlushMode() - -void NormStreamSetPushMode(NormObjectHandle streamHandle, bool state) -{ - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) stream->SetPushMode(state); -} // end NormStreamSetPushMode() - -void NormStreamFlush(NormObjectHandle streamHandle, bool eom) -{ - NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) stream->Flush(eom); - instance->dispatcher.ResumeThread(); - } -} // end NormStreamFlush() - -void NormStreamMarkEom(NormObjectHandle streamHandle) -{ - NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) stream->Write(NULL, 0, true); - instance->dispatcher.ResumeThread(); - } -} // end NormMarkStreamEom() - -unsigned int NormStreamWrite(NormObjectHandle streamHandle, - const char* buffer, - unsigned int numBytes) -{ - unsigned int result = 0; - NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) - result = stream->Write(buffer, numBytes, false); - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormStreamWrite() - -bool NormStreamRead(NormObjectHandle streamHandle, - char* buffer, - unsigned int* numBytes) -{ - bool result = false; - NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - if (stream) - result = stream->Read(buffer, numBytes); - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormStreamRead() - -bool NormStreamSeekMsgStart(NormObjectHandle streamHandle) -{ - bool result = false; - NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormStreamObject* stream = - static_cast((NormObject*)streamHandle); - unsigned int numBytes = 0; - if (stream) - result = stream->Read(NULL, &numBytes, true); - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormStreamSeekMsgStart() - -NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, - const char* fileName, - const char* infoPtr, - unsigned int infoLen) -{ - NormObjectHandle objectHandle = NORM_OBJECT_INVALID; - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) - { - NormObject* obj = session->QueueTxFile(fileName, infoPtr, infoLen); - if (obj) objectHandle = (NormObjectHandle)obj; - } - instance->dispatcher.ResumeThread(); - } - return objectHandle; -} // end NormFileEnqueue() - -bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, - const char* cachePath) -{ - NormInstance* instance = (NormInstance*)instanceHandle; - if (instance) - return instance->SetCacheDirectory(cachePath); - else - return false; -} // end NormSetCacheDirectory() - -bool NormFileRename(NormObjectHandle fileHandle, - const char* fileName) -{ - bool result = false; - NormInstance* instance = NormInstance::GetInstanceFromObject(fileHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - // (TBD) verify "fileHandle" is a NORM_FILE ?>?? - NormFileObject* file = - static_cast((NormObject*)fileHandle); - result = file->Rename(fileName); - instance->dispatcher.ResumeThread(); - } - return result; -} // end NormFileRename() - bool NormFileGetName(NormObjectHandle fileHandle, char* nameBuffer, unsigned int bufferLen) @@ -1113,42 +1246,92 @@ bool NormFileGetName(NormObjectHandle fileHandle, return result; } // end NormFileGetName() -NormObjectHandle NormDataEnqueue(NormSessionHandle sessionHandle, - const char* dataPtr, - unsigned long dataLen, - const char* infoPtr = NULL, - unsigned int infoLen = 0) -{ - NormObjectHandle objectHandle = NORM_OBJECT_INVALID; - NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle); - if (instance && instance->dispatcher.SuspendThread()) - { - NormSession* session = (NormSession*)sessionHandle; - if (session) - { - NormObject* obj = session->QueueTxData(dataPtr, dataLen, infoPtr, infoLen); - if (obj) objectHandle = (NormObjectHandle)obj; - } - instance->dispatcher.ResumeThread(); - } - return objectHandle; -} // end NormDataEnqueue() - - -bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent) +bool NormFileRename(NormObjectHandle fileHandle, + const char* fileName) { bool result = false; - NormInstance* instance = (NormInstance*)instanceHandle; - if (instance) + NormInstance* instance = NormInstance::GetInstanceFromObject(fileHandle); + if (instance && instance->dispatcher.SuspendThread()) { - if (instance->NotifyQueueIsEmpty()) //(TBD) perform this check??? - instance->WaitForEvent(); - if (instance->dispatcher.SuspendThread()) + // (TBD) verify "fileHandle" is a NORM_FILE ?>?? + NormFileObject* file = + static_cast((NormObject*)fileHandle); + result = file->Rename(fileName); + instance->dispatcher.ResumeThread(); + } + return result; +} // end NormFileRename() + +const char*volatile NormDataAccessData(NormObjectHandle dataHandle) +{ + NormDataObject* dataObj = + static_cast((NormObject*)dataHandle); + return dataObj->GetData(); +} // end NormDataAccessData() + +char* NormDataDetachData(NormObjectHandle dataHandle) +{ + NormDataObject* dataObj = + static_cast((NormObject*)dataHandle); + return dataObj->DetachData(); +} // end NormDataDetachData() + +NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle) +{ + return (NormNodeHandle)(((NormObject*)objectHandle)->GetServer()); +} // end NormObjectGetSender() + + +/** NORM Node Functions */ + +NormNodeId NormNodeGetId(NormNodeHandle nodeHandle) +{ + NormNode* node = (NormNode*)nodeHandle; + if (node) + return node->GetId(); + else + return NORM_NODE_NONE; +} // end NormNodeGetId() + +void NormNodeRetain(NormNodeHandle nodeHandle) +{ + if (NORM_NODE_INVALID != nodeHandle) + { + NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle); + if (instance && instance->dispatcher.SuspendThread()) { - result = instance->GetNextEvent(theEvent); + NormNode* node = (NormNode*)nodeHandle; + node->Retain(); instance->dispatcher.ResumeThread(); } } - return result; -} // end NormGetNextEvent() +} // end NormNodeRetain() +void NormNodeRelease(NormNodeHandle nodeHandle) +{ + if (NORM_NODE_INVALID != nodeHandle) + { + NormInstance* instance = NormInstance::GetInstanceFromNode(nodeHandle); + if (instance && instance->dispatcher.SuspendThread()) + { + NormNode* node = (NormNode*)nodeHandle; + node->Release(); + instance->dispatcher.ResumeThread(); + } + } +} // end NormNodeRelease() + +// (TBD) Some stream i/o performance improvement can be realized +// if the option to make "NormWriteStream()" and +// "NormReadStream()" _blocking_ calls is implemented. +// Right now, the stream read/write are non-blocking +// so applications should use "NormGetNextEvent()" to +// know when to read or write ... This results in the +// underlying NORM thread to be suspended/resumed _twice_ +// per read or write ... It would be more efficient to +// "suspend" the NORM thread while the application +// processes all pending events and _then_ "resume" the +// NORM thread ... an approach to this would be enable +// the app to install an event handler callback and dispatch +// events with a "NormDispatchEvents()" call ... +// diff --git a/common/normApi.h b/common/normApi.h index a8eff0c..df4a095 100644 --- a/common/normApi.h +++ b/common/normApi.h @@ -6,6 +6,8 @@ #include #endif // WIN32 +#include // for "off_t" type + //////////////////////////////////////////////////////////// // IMPORTANT NOTICE // The NORM API is _very_ much in a developmental phase @@ -18,106 +20,27 @@ // is removed, the API shouldn't be considered final. +/** NORM API Data Types and Constants + * These are data types and constants defined + * for the NORM API + */ + typedef const void* NormInstanceHandle; extern const NormInstanceHandle NORM_INSTANCE_INVALID; -NormInstanceHandle NormCreateInstance(); -void NormDestroyInstance(NormInstanceHandle instanceHandle); - -// NORM session creation and control typedef const void* NormSessionHandle; extern const NormSessionHandle NORM_SESSION_INVALID; + +typedef const void* NormNodeHandle; +extern const NormNodeHandle NORM_NODE_INVALID; typedef unsigned long NormNodeId; extern const NormNodeId NORM_NODE_NONE; extern const NormNodeId NORM_NODE_ANY; -NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle, - const char* sessionAddress, - unsigned short sessionPort, - NormNodeId localNodeId); - -void NormDestroySession(NormSessionHandle sessionHandle); - -// Session management and parameters - -void NormSetTransmitRate(NormSessionHandle sessionHandle, - double bitsPerSecond); - -void NormSetGrttEstimate(NormSessionHandle sessionHandle, - double grttEstimate); - -NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle); - -bool NormSetLoopback(NormSessionHandle sessionHandle, bool state); - -// Debug parameters -void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state); -void NormSetTxLoss(NormSessionHandle sessionHandle, double percent); -void NormSetRxLoss(NormSessionHandle sessionHandle, double percent); - -// Sender control & parameters -bool NormStartSender(NormSessionHandle sessionHandle, - unsigned long bufferSpace, - unsigned short segmentSize, - unsigned char numData, - unsigned char numParity); - -void NormStopSender(NormSessionHandle sessionHandle); - -bool NormAddAckingNode(NormSessionHandle sessionHandle, - NormNodeId nodeId); - -void NormRemoveAckingNode(NormSessionHandle sessionHandle, - NormNodeId nodeId); - - -// Receiver control & parameters -bool NormStartReceiver(NormSessionHandle sessionHandle, - unsigned long bufferSpace); - -void NormStopReceiver(NormSessionHandle sessionHandle); - -void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle, - bool state); - -typedef const void* NormNodeHandle; -extern const NormNodeHandle NORM_NODE_INVALID; typedef const void* NormObjectHandle; extern const NormObjectHandle NORM_OBJECT_INVALID; typedef unsigned short NormObjectTransportId; -enum NormNackingMode -{ - NORM_NACK_NONE, - NORM_NACK_INFO_ONLY, - NORM_NACK_NORMAL -}; - -void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, - NormNackingMode nackingMode); - -enum NormRepairBoundary -{ - NORM_BOUNDARY_BLOCK, - NORM_BOUNDARY_OBJECT -}; - -void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, - NormRepairBoundary repairBoundary); - -NormRepairBoundary NormNodeGetRepairBoundary(NormNodeHandle nodeHandle); - -void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, - NormRepairBoundary repairBoundary); - -NormNodeId NormNodeGetId(NormNodeHandle nodeHandle); - -void NormNodeSetNackingMode(NormNodeHandle nodeHandle, - NormNackingMode nackingMode); - - -// General NormObject functions - enum NormObjectType { NORM_OBJECT_NONE, @@ -126,95 +49,27 @@ enum NormObjectType NORM_OBJECT_STREAM }; - -NormObjectType NormObjectGetType(NormObjectHandle objectHandle); - - -bool NormObjectGetInfo(NormObjectHandle objectHandle, - char* infoBuffer, - unsigned short* infoLen); - -NormObjectTransportId NormObjectGetTransportId(NormObjectHandle objectHandle); - -void NormObjectCancel(NormObjectHandle objectHandle); - - -void NormObjectReNormObjectRetaintain(NormObjectHandle objectHandle); -void NormObjectRelease(NormObjectHandle objectHandle); - - -// Receiver-only NormObject functions -NormNackingMode NormObjectGetNackingMode(NormObjectHandle objectHandle); - -void NormObjectSetNackingMode(NormObjectHandle objectHandle, - NormNackingMode nackingMode); - - - - -// Sender-only NormObject functions -bool NormSetWatermark(NormSessionHandle sessionHandle, - NormObjectHandle objectHandle); - - -// NormStreamObject functions - -NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, - unsigned long bufferSize); - -void NormStreamClose(NormObjectHandle streamHandle); - enum NormFlushMode { NORM_FLUSH_NONE, NORM_FLUSH_PASSIVE, NORM_FLUSH_ACTIVE }; + -void NormStreamSetFlushMode(NormObjectHandle streamHandle, - NormFlushMode flushMode); - -void NormStreamSetPushMode(NormObjectHandle streamHandle, - bool state); - -unsigned int NormStreamWrite(NormObjectHandle streamHandle, - const char* buffer, - unsigned int numBytes); - -void NormStreamFlush(NormObjectHandle streamHandle, bool eom = false); - -void NormStreamMarkEom(NormObjectHandle streamHandle); - -bool NormStreamRead(NormObjectHandle streamHandle, - char* buffer, - unsigned int* numBytes); - -bool NormStreamSeekMsgStart(NormObjectHandle streamHandle); - -// NormFileObject Functions -NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, - const char* fileName, - const char* infoPtr = (const char*)0, - unsigned int infoLen = 0); - -bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, - const char* cachePath); - -bool NormFileGetName(NormObjectHandle fileHandle, - char* nameBuffer, - unsigned int bufferLen); - -bool NormFileRename(NormObjectHandle fileHandle, - const char* fileName); - -// NormDataObject Functions -bool NormDataEnqueue(const char* dataPtr, - unsigned long dataLen, - const char* infoPtr = (const char*)0, - unsigned int infoLen = 0); - -// NORM Event Notification Routines - +enum NormNackingMode +{ + NORM_NACK_NONE, + NORM_NACK_INFO_ONLY, + NORM_NACK_NORMAL +}; + +enum NormRepairBoundary +{ + NORM_BOUNDARY_BLOCK, + NORM_BOUNDARY_OBJECT +}; + enum NormEventType { NORM_EVENT_INVALID = 0, @@ -224,11 +79,12 @@ enum NormEventType NORM_TX_OBJECT_PURGED, NORM_LOCAL_SERVER_CLOSED, NORM_REMOTE_SERVER_NEW, - NORM_REMOTE_SERVER_INACTIVE, NORM_REMOTE_SERVER_ACTIVE, + NORM_REMOTE_SERVER_INACTIVE, + NORM_REMOTE_SERVER_PURGED, NORM_RX_OBJECT_NEW, NORM_RX_OBJECT_INFO, - NORM_RX_OBJECT_UPDATE, + NORM_RX_OBJECT_UPDATED, NORM_RX_OBJECT_COMPLETED, NORM_RX_OBJECT_ABORTED }; @@ -240,7 +96,17 @@ typedef struct NormNodeHandle sender; NormObjectHandle object; } NormEvent; + +/** NORM API General Initialization and Operation Functions */ + +NormInstanceHandle NormCreateInstance(); + +void NormDestroyInstance(NormInstanceHandle instanceHandle); + +// This MUST be set to enable NORM_OBJECT_FILE reception! +bool NormSetCacheDirectory(NormInstanceHandle instanceHandle, + const char* cachePath); // This call blocks until the next NormEvent is ready unless asynchronous // notification is used (see below) @@ -252,7 +118,7 @@ bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent); // with system calls like "WaitForSingleEvent()", and on Unix the // returned descriptor can be used in a "select()" call. If this type // of asynchronous notification is used, calls to "NormGetNextEvent()" will -// not block. +// not block when the notification is posted. #ifdef WIN32 typedef HANDLE NormDescriptor; @@ -261,4 +127,184 @@ typedef int NormDescriptor; #endif // if/else WIN32/UNIX NormDescriptor NormGetDescriptor(NormInstanceHandle instanceHandle); +/** NORM Session Creation and Control Functions */ + +NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle, + const char* sessionAddress, + unsigned short sessionPort, + NormNodeId localNodeId); + +void NormDestroySession(NormSessionHandle sessionHandle); + +NormNodeId NormGetLocalNodeId(NormSessionHandle sessionHandle); + +bool NormSetMulticastInterface(NormSessionHandle sessionHandle, + const char* interfaceName); + +bool NormSetTTL(NormSessionHandle sessionHandle, + unsigned char ttl); + +bool NormSetTOS(NormSessionHandle sessionHandle, + unsigned char tos); + +bool NormSetLoopback(NormSessionHandle sessionHandle, + bool loopback); + +// Special functions for debug support +void NormSetMessageTrace(NormSessionHandle sessionHandle, bool state); +void NormSetTxLoss(NormSessionHandle sessionHandle, double percent); +void NormSetRxLoss(NormSessionHandle sessionHandle, double percent); + + +/** NORM Sender Functions */ + +bool NormStartSender(NormSessionHandle sessionHandle, + unsigned long bufferSpace, + unsigned short segmentSize, + unsigned char numData, + unsigned char numParity); + +void NormStopSender(NormSessionHandle sessionHandle); + +void NormSetTransmitRate(NormSessionHandle sessionHandle, + double bitsPerSecond); + +void NormSetCongestionControl(NormSessionHandle sessionHandle, + bool state); + +void NormSetTransmitRateBounds(NormSessionHandle sessionHandle, + double rateMin, + double rateMax); + +void NormSetAutoParity(NormSessionHandle sessionHandle, + unsigned char autoParity); + +void NormSetGrttEstimate(NormSessionHandle sessionHandle, + double grttEstimate); + +bool NormAddAckingNode(NormSessionHandle sessionHandle, + NormNodeId nodeId); + +void NormRemoveAckingNode(NormSessionHandle sessionHandle, + NormNodeId nodeId); + +NormObjectHandle NormFileEnqueue(NormSessionHandle sessionHandle, + const char* fileName, + const char* infoPtr = (const char*)0, + unsigned int infoLen = 0); + +bool NormDataEnqueue(const char* dataPtr, + unsigned long dataLen, + const char* infoPtr = (const char*)0, + unsigned int infoLen = 0); + + + +NormObjectHandle NormStreamOpen(NormSessionHandle sessionHandle, + unsigned long bufferSize); + +void NormStreamClose(NormObjectHandle streamHandle); + +unsigned int NormStreamWrite(NormObjectHandle streamHandle, + const char* buffer, + unsigned int numBytes); + +void NormStreamFlush(NormObjectHandle streamHandle, + bool eom = false, + NormFlushMode flushMode = NORM_FLUSH_PASSIVE); + +void NormStreamSetAutoFlush(NormObjectHandle streamHandle, + NormFlushMode flushMode); + +void NormStreamSetPushEnable(NormObjectHandle streamHandle, + bool pushEnable); + +void NormStreamMarkEom(NormObjectHandle streamHandle); + +bool NormSetWatermark(NormSessionHandle sessionHandle, + NormObjectHandle objectHandle); + +/** NORM Receiver Functions */ + +bool NormStartReceiver(NormSessionHandle sessionHandle, + unsigned long bufferSpace); + +void NormStopReceiver(NormSessionHandle sessionHandle); + +void NormSetSilentReceiver(NormSessionHandle sessionHandle, + bool silent); + +void NormSetDefaultUnicastNack(NormSessionHandle sessionHandle, + bool unicastNacks); + +void NormNodeSetUnicastNack(NormNodeHandle remoteSender, + bool unicastNacks); + +void NormSetDefaultNackingMode(NormSessionHandle sessionHandle, + NormNackingMode nackingMode); + +void NormNodeSetNackingMode(NormNodeHandle nodeHandle, + NormNackingMode nackingMode); + +void NormObjectSetNackingMode(NormObjectHandle objectHandle, + NormNackingMode nackingMode); + +void NormSetDefaultRepairBoundary(NormSessionHandle sessionHandle, + NormRepairBoundary repairBoundary); + +void NormNodeSetRepairBoundary(NormNodeHandle nodeHandle, + NormRepairBoundary repairBoundary); + +bool NormStreamRead(NormObjectHandle streamHandle, + char* buffer, + unsigned int* numBytes); + +bool NormStreamSeekMsgStart(NormObjectHandle streamHandle); + +unsigned long NormStreamGetReadOffset(NormObjectHandle streamHandle); + + +/** NORM Object Functions */ + +NormObjectType NormObjectGetType(NormObjectHandle objectHandle); + +bool NormObjectHasInfo(NormObjectHandle objectHandle); + +unsigned short NormObjectGetInfoLength(NormObjectHandle objectHandle); + +unsigned short NormObjectGetInfo(NormObjectHandle objectHandle, + char* buffer, + unsigned short bufferLen); + +off_t NormObjectGetSize(NormObjectHandle objectHandle); + +void NormObjectCancel(NormObjectHandle objectHandle); + +void NormObjectRetain(NormObjectHandle objectHandle); + +void NormObjectRelease(NormObjectHandle objectHandle); + +bool NormFileGetName(NormObjectHandle fileHandle, + char* nameBuffer, + unsigned int bufferLen); + +bool NormFileRename(NormObjectHandle fileHandle, + const char* fileName); + +const char*volatile NormDataAccessData(NormObjectHandle objectHandle); + +char* NormDataDetachData(NormObjectHandle objectHandle); + +NormNodeHandle NormObjectGetSender(NormObjectHandle objectHandle); + + +/** NORM Node Functions */ + +NormNodeId NormNodeGetId(NormNodeHandle nodeHandle); + +void NormNodeRetain(NormNodeHandle nodeHandle); + +void NormNodeRelease(NormNodeHandle nodeHandle); + + #endif // _NORM_API diff --git a/common/normApp.cpp b/common/normApp.cpp index 9807d5c..55208ed 100644 --- a/common/normApp.cpp +++ b/common/normApp.cpp @@ -761,7 +761,7 @@ bool NormApp::OnCommand(const char* cmd, const char* val) else if (!strncmp("unicastNacks", cmd, len)) { unicast_nacks = true; - if (session) session->SetUnicastNacks(true); + if (session) session->ClientSetUnicastNacks(true); } else if (!strncmp("silentClient", cmd, len)) { @@ -1198,8 +1198,8 @@ void NormApp::Notify(NormController::Event event, } // end switch(object->GetType()) break; - case RX_OBJECT_UPDATE: - //DMSG(0, "NormApp::Notify(RX_OBJECT_UPDATE) ...\n"); + case RX_OBJECT_UPDATED: + //DMSG(0, "NormApp::Notify(RX_OBJECT_UPDATED) ...\n"); switch (object->GetType()) { case NormObject::FILE: @@ -1212,7 +1212,7 @@ void NormApp::Notify(NormController::Event event, { if (object != rx_stream) { - DMSG(0, "NormApp::Notify(RX_OBJECT_UPDATE) update for invalid stream\n"); + DMSG(0, "NormApp::Notify(RX_OBJECT_UPDATED) update for invalid stream\n"); break; } // Read the stream when it's updated @@ -1532,7 +1532,7 @@ bool NormApp::OnStartup(int argc, const char*const* argv) if (output || rx_cache_path) { // StartClient(bufferMax (per-sender)) - session->SetUnicastNacks(unicast_nacks); + session->ClientSetUnicastNacks(unicast_nacks); session->ClientSetSilent(silent_client); if (!session->StartClient(rx_buffer_size, interface_name)) { diff --git a/common/normMessage.h b/common/normMessage.h index 4d0f6c5..82aa624 100644 --- a/common/normMessage.h +++ b/common/normMessage.h @@ -8,6 +8,7 @@ #include // for memcpy(), etc #include #include // for rand(), etc +#include // for off_t #ifdef SIMULATE #define SIM_PAYLOAD_MAX (36+8) // MGEN message size + StreamPayloadHeaderLen() @@ -94,7 +95,9 @@ inline double NormUnquantizeRate(unsigned short rate) } // This class is used to describe object "size" and/or "offset" -// (TBD) This hokey implementation should use "off_t" +// (TBD) This hokey implementation should 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: @@ -109,6 +112,7 @@ class NormObjectSize size >>= 32; ASSERT(0 == (size & 0xffff0000)); msb = size & 0x0000ffff; + msb = 0; } UINT16 MSB() const {return msb;} @@ -159,6 +163,7 @@ class NormObjectSize NormObjectSize operator/(const NormObjectSize& b) const; off_t GetOffset() const { + off_t offset = msb; offset <<= 32; offset += lsb; diff --git a/common/normNode.cpp b/common/normNode.cpp index 6f3d3b0..5d7aeb1 100644 --- a/common/normNode.cpp +++ b/common/normNode.cpp @@ -59,7 +59,7 @@ NormServerNode::NormServerNode(class NormSession& theSession, NormNodeId nodeId) repair_boundary = session.ClientGetDefaultRepairBoundary(); default_nacking_mode = session.ClientGetDefaultNackingMode(); - unicast_nacks = session.UnicastNacks(); + unicast_nacks = session.ClientGetUnicastNacks(); // (TBD) get "max_pending_range" value from NormSession parameter repair_timer.SetListener(this, &NormServerNode::OnRepairTimeout); @@ -1706,6 +1706,7 @@ void NormServerNode::Activate() activity_timer.SetInterval(grtt_estimate*NORM_ROBUST_FACTOR); session.ActivateTimer(activity_timer); server_active = false; + session.Notify(NormController::REMOTE_SERVER_ACTIVE, this, NULL); } else { @@ -1725,7 +1726,7 @@ bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/) DMSG(0, "NormServerNode::OnActivityTimeout() node>%lu server>%lu gone inactive?\n", LocalNodeId(), GetId()); FreeBuffers(); - // (TBD) Notify application + session.Notify(NormController::REMOTE_SERVER_INACTIVE, this, NULL); } else { diff --git a/common/normNode.h b/common/normNode.h index 6c85051..c7e6e31 100644 --- a/common/normNode.h +++ b/common/normNode.h @@ -16,6 +16,8 @@ class NormNode public: NormNode(class NormSession& theSession, NormNodeId nodeId); virtual ~NormNode(); + + NormSession& GetSession() const {return session;} void Retain(); void Release(); diff --git a/common/normObject.cpp b/common/normObject.cpp index 10520a2..9ce8e86 100644 --- a/common/normObject.cpp +++ b/common/normObject.cpp @@ -11,7 +11,7 @@ NormObject::NormObject(NormObject::Type theType, transport_id(transportId), segment_size(0), pending_info(false), repair_info(false), current_block_id(0), next_segment_id(0), max_pending_block(0), max_pending_segment(0), - info(NULL), info_len(0), accepted(false), notify_on_update(true) + info_ptr(NULL), info_len(0), accepted(false), notify_on_update(true) { if (theServer) nacking_mode = theServer->GetDefaultNackingMode(); @@ -22,10 +22,10 @@ NormObject::NormObject(NormObject::Type theType, NormObject::~NormObject() { Close(); - if (info) + if (info_ptr) { - delete info; - info = NULL; + delete info_ptr; + info_ptr = NULL; } } @@ -73,7 +73,7 @@ bool NormObject::Open(const NormObjectSize& objectSize, { pending_info = true; info_len = 0; - if (!(info = new char[segmentSize])) + if (!(info_ptr = new char[segmentSize])) { DMSG(0, "NormObject::Open() info allocation error\n"); return false; @@ -84,20 +84,20 @@ bool NormObject::Open(const NormObjectSize& objectSize, { if (infoPtr) { - if (info) delete []info; + if (info_ptr) delete []info_ptr; if (infoLen > segmentSize) { DMSG(0, "NormObject::Open() info too big error\n"); info_len = 0; return false; } - if (!(info = new char[infoLen])) + if (!(info_ptr = new char[infoLen])) { DMSG(0, "NormObject::Open() info allocation error\n"); info_len = 0; return false; } - memcpy(info, infoPtr, infoLen); + memcpy(info_ptr, infoPtr, infoLen); info_len = infoLen; pending_info = true; } @@ -207,7 +207,7 @@ void NormObject::Close() bool NormObject::HandleInfoRequest() { bool increasedRepair = false; - if (info) + if (info_ptr) { if (!repair_info) { @@ -1047,7 +1047,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, "Warning! info too long.\n", LocalNodeId(), server->GetId(), (UINT16)transport_id); } - memcpy(info, infoMsg.GetInfo(), info_len); + memcpy(info_ptr, infoMsg.GetInfo(), info_len); pending_info = false; session.Notify(NormController::RX_OBJECT_INFO, server, this); } @@ -1219,9 +1219,10 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, block->SetPending(nextSegment); block->IncrementErasureCount(); // Clear any erasure/retrieval segments - for (UINT16 i = 0; i < erasureCount; i++) + UINT16 i; + for (i = 0; i < erasureCount; i++) block->DetachSegment(server->GetErasureLoc(i)); - for (UINT16 i = 0; i < retrievalCount; i++) + for (i = 0; i < retrievalCount; i++) block->DetachSegment(server->GetRetrievalLoc(i)); return; } @@ -1272,7 +1273,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (objectUpdated && notify_on_update) { notify_on_update = false; - session.Notify(NormController::RX_OBJECT_UPDATE, server, this); + session.Notify(NormController::RX_OBJECT_UPDATED, server, this); } } else @@ -1418,7 +1419,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg) default: break; } - if (info) msg->SetFlag(NormObjectMsg::FLAG_INFO); + if (info_ptr) msg->SetFlag(NormObjectMsg::FLAG_INFO); msg->SetFecId(129); msg->SetObjectId(transport_id); @@ -1435,7 +1436,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg) { // (TBD) set REPAIR_FLAG for retransmitted info NormInfoMsg* infoMsg = (NormInfoMsg*)msg; - infoMsg->SetInfo(info, info_len); + infoMsg->SetInfo(info_ptr, info_len); pending_info = false; return true; } @@ -1938,7 +1939,7 @@ NormDataObject::NormDataObject(class NormSession& theSession, const NormObjectId& objectId) : NormObject(DATA, theSession, theServer, objectId), large_block_length(0,0), small_block_length(0,0), - data_ptr(NULL), data_max(0) + data_ptr(NULL), data_max(0), data_released(false) { } @@ -1946,11 +1947,21 @@ NormDataObject::NormDataObject(class NormSession& theSession, NormDataObject::~NormDataObject() { Close(); + if (data_released) + { + if (data_ptr) + { + delete data_ptr; + data_ptr = NULL; + } + data_released = false; + } } // Assign data object to data ptr bool NormDataObject::Open(char* dataPtr, UINT32 dataLen, + bool dataRelease, const char* infoPtr, UINT16 infoLen) { @@ -1976,15 +1987,16 @@ bool NormDataObject::Open(char* dataPtr, } data_ptr = dataPtr; data_max = dataLen; + data_released = dataRelease; large_block_length = NormObjectSize(large_block_size) * segment_size; small_block_length = NormObjectSize(small_block_size) * segment_size; return true; } // end NormDataObject::Open() -bool NormDataObject::Accept(char* dataPtr, UINT32 dataMax) +bool NormDataObject::Accept(char* dataPtr, UINT32 dataMax, bool dataRelease) { ASSERT(NULL == server); - if (Open(dataPtr, dataMax)) + if (Open(dataPtr, dataMax, dataRelease)) { NormObject::Accept(); return true; @@ -2005,6 +2017,11 @@ bool NormDataObject::WriteSegment(NormBlockId blockId, const char* buffer, bool /*msgStart*/) { + if (NULL == data_ptr) + { + DMSG(0, "NormDataObject::WriteSegment() error: NULL data_ptr\n"); + return false; + } UINT16 len; if (blockId == final_block_id) { @@ -2046,6 +2063,11 @@ UINT16 NormDataObject::ReadSegment(NormBlockId blockId, char* buffer, bool* /*msgStart*/) { + if (NULL == data_ptr) + { + DMSG(0, "NormDataObject::ReadSegment() error: NULL data_ptr\n"); + return 0; + } // Determine segment length from blockId::segmentId UINT16 len; if (blockId == final_block_id) @@ -2075,14 +2097,23 @@ UINT16 NormDataObject::ReadSegment(NormBlockId blockId, segmentSize*segmentId; } ASSERT(0 == segmentOffset.MSB()); - ASSERT(data_max >= (segmentOffset.LSB() + len)); + if (data_max <= segmentOffset.LSB()) + return 0; + else if (data_max <= (segmentOffset.LSB() + len)) + len -= (segmentOffset.LSB() + len - data_max); + memcpy(buffer, data_ptr + segmentOffset.LSB(), len); - return true; + return len; } // end NormDataObject::ReadSegment() char* NormDataObject::RetrieveSegment(NormBlockId blockId, NormSegmentId segmentId) { + if (NULL == data_ptr) + { + DMSG(0, "NormDataObject::RetrieveSegment() error: NULL data_ptr\n"); + return NULL; + } // Determine segment length from blockId::segmentId UINT16 len; if (blockId == final_block_id) @@ -2101,7 +2132,7 @@ char* NormDataObject::RetrieveSegment(NormBlockId blockId, if (server) { char* segment = server->GetRetrievalSegment(); - ReadSegment(blockId, segmentId, segment); + len = ReadSegment(blockId, segmentId, segment); memset(segment+len, 0, segment_size-len); return segment; } @@ -2490,7 +2521,7 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId, block->GetFirstPending(read_index.segment); NormBlock* tempBlock = block; UINT32 tempOffset = read_offset; - session.Notify(NormController::RX_OBJECT_UPDATE, server, this); + session.Notify(NormController::RX_OBJECT_UPDATED, server, this); block = stream_buffer.Find(stream_buffer.RangeLo()); if (tempBlock == block) { @@ -2954,6 +2985,18 @@ NormSimObject::~NormSimObject() } +bool NormSimObject::Open(UINT32 objectSize, + const char* infoPtr , + UINT16 infoLen) +{ + return (server ? + true : + NormObject::Open(objectSize, infoPtr, infoLen, + session.ServerSegmentSize(), + session.ServerBlockSize(), + session.ServerNumParity())); +} // end NormSimObject::Open() + UINT16 NormSimObject::ReadSegment(NormBlockId blockId, NormSegmentId segmentId, char* buffer, @@ -2975,6 +3018,12 @@ UINT16 NormSimObject::ReadSegment(NormBlockId blockId, return len; } // end NormSimObject::ReadSegment() +char* NormSimObject::RetrieveSegment(NormBlockId blockId, + NormSegmentId segmentId) +{ + return server ? server->GetRetrievalSegment() : NULL; +} // end NormSimObject::RetrieveSegment() + #endif // SIMULATE ///////////////////////////////////////////////////////////////// diff --git a/common/normObject.h b/common/normObject.h index 5c4cd6a..c8a4a58 100644 --- a/common/normObject.h +++ b/common/normObject.h @@ -51,7 +51,9 @@ class NormObject const NormObjectId& GetId() const {return transport_id;} const NormObjectSize& GetSize() const {return object_size;} bool HaveInfo() const {return (info_len > 0);} - const char* GetInfo() const {return info;} + bool HasInfo() const {return (NULL != info_ptr);} + + const char* GetInfo() const {return info_ptr;} UINT16 GetInfoLength() const {return info_len;} bool IsStream() const {return (STREAM == type);} @@ -257,7 +259,7 @@ class NormObject NormBlockId final_block_id; UINT16 final_segment_size; NackingMode nacking_mode; - char* info; + char* info_ptr; UINT16 info_len; // Here are some members used to let us know @@ -321,12 +323,19 @@ class NormDataObject : public NormObject bool Open(char* dataPtr, UINT32 dataLen, + bool dataRelease, const char* infoPtr = NULL, UINT16 infoLen = 0); - bool Accept(char* dataPtr, UINT32 dataMax); + bool Accept(char* dataPtr, UINT32 dataMax, bool dataRelease); void Close(); const char* GetData() {return data_ptr;} + char* DetachData() + { + char* dataPtr = data_ptr; + data_ptr = NULL; + return dataPtr; + } virtual bool WriteSegment(NormBlockId blockId, NormSegmentId segmentId, @@ -346,6 +355,8 @@ class NormDataObject : public NormObject NormObjectSize small_block_length; char* data_ptr; UINT32 data_max; + bool data_released; // when true, data_ptr is deleted + // on NormDataObject destruction }; // end class NormDataObject @@ -357,7 +368,7 @@ class NormStreamObject : public NormObject const NormObjectId& objectId); ~NormStreamObject(); - bool Open(UINT32 bufferSize, + bool Open(UINT32 bufferSize, const char* infoPtr = NULL, UINT16 infoLen = 0); void Close(); @@ -477,12 +488,9 @@ class NormSimObject : public NormObject const NormObjectId& objectId); ~NormSimObject(); - bool Open(UINT32 objectSize, + bool Open(UINT32 objectSize, const char* infoPtr = NULL, - UINT16 infoLen = 0) - { - return server ? true : NormObject::Open(objectSize, infoPtr, infoLen); - } + UINT16 infoLen = 0); bool Accept() {NormObject::Accept(); return true;} void Close() {NormObject::Close();} @@ -497,10 +505,7 @@ class NormSimObject : public NormObject bool* msgStart = NULL); virtual char* RetrieveSegment(NormBlockId blockId, - NormSegmentId segmentId) - { - return server ? server->GetRetrievalSegment() : NULL; - } + NormSegmentId segmentId); }; // end class NormSimObject #endif // SIMULATE diff --git a/common/normSession.cpp b/common/normSession.cpp index b437dc1..92b4618 100644 --- a/common/normSession.cpp +++ b/common/normSession.cpp @@ -20,7 +20,7 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId) tx_socket(ProtoSocket::UDP), rx_socket(ProtoSocket::UDP), local_node_id(localNodeId), ttl(DEFAULT_TTL), loopback(false), - tx_rate(DEFAULT_TRANSMIT_RATE/8.0), + tx_rate(DEFAULT_TRANSMIT_RATE/8.0), tx_rate_min(-1.0), tx_rate_max(-1.0), backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_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), @@ -112,12 +112,6 @@ bool NormSession::Open(const char* interfaceName) if (address.IsMulticast()) { - if (!rx_socket.JoinGroup(address, interfaceName)) - { - DMSG(0, "NormSession::Open() rx_socket join group error\n"); - Close(); - return false; - } if (!tx_socket.SetTTL(ttl)) { DMSG(0, "NormSession::Open() tx_socket set ttl error\n"); @@ -132,11 +126,27 @@ bool NormSession::Open(const char* interfaceName) } if (interfaceName) { - rx_socket.SetMulticastInterface(interfaceName); - tx_socket.SetMulticastInterface(interfaceName); strncpy(interface_name, interfaceName, 31); interface_name[31] = '\0'; } + if ('\0' != interface_name[0]) + { + bool result = rx_socket.SetMulticastInterface(interface_name); + result &= tx_socket.SetMulticastInterface(interface_name); + if (!result) + { + DMSG(0, "NormSession::Open() error setting multicast interface\n"); + Close(); + return false; + } + interfaceName = interface_name; + } + if (!rx_socket.JoinGroup(address, interfaceName)) + { + DMSG(0, "NormSession::Open() rx_socket join group error\n"); + Close(); + return false; + } } for (unsigned int i = 0; i < DEFAULT_MESSAGE_POOL_DEPTH; i++) { @@ -179,6 +189,24 @@ void NormSession::Close() } // end NormSession::Close() +bool NormSession::SetMulticastInterface(const char* interfaceName) +{ + if (interfaceName) + { + bool result = true; + if (rx_socket.IsOpen()) + result &= rx_socket.SetMulticastInterface(interfaceName); + if (tx_socket.IsOpen()) + result &= tx_socket.SetMulticastInterface(interfaceName); + return result; + } + else + { + interface_name[0] = '\0'; + return true; + } +} // end NormSession::SetMulticastInterface() + void NormSession::SetTxRate(double txRate) { txRate /= 8.0; // convert to bytes/sec @@ -193,7 +221,7 @@ void NormSession::SetTxRate(double txRate) } tx_rate = txRate; } - else if (0.0 == tx_rate) + else if ((0.0 == tx_rate) && IsOpen()) { tx_rate = txRate; tx_timer.SetInterval(0.0); @@ -205,6 +233,37 @@ void NormSession::SetTxRate(double txRate) } } // end NormSession::SetTxRate() +void NormSession::SetTxRateBounds(double rateMin, double rateMax) +{ + // Make sure min <= max + if ((rateMin >= 0.0) && (rateMax >= 0.0)) + { + if (rateMin > rateMax) + { + double temp = rateMin; + rateMin = rateMax; + rateMax = temp; + } + } + if (rateMin < 0.0) + tx_rate_min = -1.0; + else + tx_rate_min = rateMin/8.0; // convert to bytes/second + if (rateMax < 0.0) + tx_rate_max = -1.0; + else + tx_rate_max = rateMax/8.0; // convert to bytes/second + if (cc_enable) + { + if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) + tx_rate = tx_rate_min; + if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) + tx_rate = tx_rate_max; + SetTxRate(tx_rate*8.0); + } +} // end NormSession::SetTxRateBounds() + + bool NormSession::StartServer(UINT32 bufferSpace, UINT16 segmentSize, UINT16 numData, @@ -285,7 +344,15 @@ bool NormSession::StartServer(UINT32 bufferSpace, //probe_timer.SetInterval(0.0); probe_pending = probe_reset = false; - if (cc_enable) tx_rate = segmentSize; + if (cc_enable) + { + tx_rate = segmentSize; + if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) + tx_rate = tx_rate_min; + if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) + tx_rate = tx_rate_max; + } + OnProbeTimeout(probe_timer); ActivateTimer(probe_timer); return true; @@ -782,7 +849,7 @@ NormDataObject* NormSession::QueueTxData(const char* dataPtr, strerror(errno)); return NULL; } - if (!obj->Open((char*)dataPtr, dataLen, infoPtr, infoLen)) + if (!obj->Open((char*)dataPtr, dataLen, false, infoPtr, infoLen)) { DMSG(0, "NormSession::QueueTxData() object open error\n"); delete obj; @@ -1263,6 +1330,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())) { server_tree.AttachNode(theServer); @@ -2821,10 +2889,18 @@ void NormSession::AdjustRate(bool onResponse) }*/ } + + // Don't let tx_rate below MIN(one segment per grtt, one segment per second) double minRate = ((double)segment_size) / grtt_measured; minRate = MIN((double)segment_size, minRate); tx_rate = MAX(tx_rate, minRate); + // Keep "tx_rate" within user set rate bounds (if any) + if ((tx_rate_min >= 0.0) && (tx_rate < tx_rate_min)) + tx_rate = tx_rate_min; + if ((tx_rate_max >= 0.0) && (tx_rate > tx_rate_max)) + tx_rate = tx_rate_max; + struct timeval currentTime; ::ProtoSystemTime(currentTime); double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec); diff --git a/common/normSession.h b/common/normSession.h index 032579c..b7c2e0e 100644 --- a/common/normSession.h +++ b/common/normSession.h @@ -20,11 +20,12 @@ class NormController TX_OBJECT_PURGED, LOCAL_SERVER_CLOSED, REMOTE_SERVER_NEW, - REMOTE_SERVER_INACTIVE, REMOTE_SERVER_ACTIVE, + REMOTE_SERVER_INACTIVE, + REMOTE_SERVER_PURGED, RX_OBJECT_NEW, RX_OBJECT_INFO, - RX_OBJECT_UPDATE, + RX_OBJECT_UPDATED, RX_OBJECT_COMPLETED, RX_OBJECT_ABORTED }; @@ -102,6 +103,7 @@ class NormSession bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());} const ProtoAddress& Address() {return address;} void SetAddress(const ProtoAddress& addr) {address = addr;} + bool SetMulticastInterface(const char* interfaceName); bool SetTTL(UINT8 theTTL) { bool result = tx_socket.IsOpen() ? tx_socket.SetTTL(theTTL) : true; @@ -129,6 +131,7 @@ class NormSession void SetBackoffFactor(double value) {backoff_factor = value;} bool CongestionControl() {return cc_enable;} void SetCongestionControl(bool state) {cc_enable = state;} + void SetTxRateBounds(double rateMin, double rateMax); void Notify(NormController::Event event, class NormServerNode* server, @@ -249,8 +252,8 @@ class NormSession bool IsClient() const {return is_client;} unsigned long RemoteServerBufferSize() const {return remote_server_buffer_size;} - void SetUnicastNacks(bool state) {unicast_nacks = state;} - bool UnicastNacks() const {return unicast_nacks;} + void ClientSetUnicastNacks(bool state) {unicast_nacks = state;} + bool ClientGetUnicastNacks() const {return unicast_nacks;} void ClientSetSilent(bool state) {client_silent = state;} bool ClientIsSilent() const {return client_silent;} @@ -342,6 +345,8 @@ class NormSession bool loopback; // to receive own traffic char interface_name[32]; double tx_rate; // bytes per second + double tx_rate_min; + double tx_rate_max; double backoff_factor; // Server parameters and state diff --git a/common/normSimAgent.cpp b/common/normSimAgent.cpp index 804b0e4..dd6ccf4 100644 --- a/common/normSimAgent.cpp +++ b/common/normSimAgent.cpp @@ -20,7 +20,7 @@ NormSimAgent::NormSimAgent(ProtoTimerMgr& timerMgr, tx_object_size(0), tx_object_interval(0.0), tx_object_size_min(0), tx_object_size_max(0), tx_repeat_count(0), tx_repeat_interval(0.0), - stream(NULL), auto_stream(false), push_stream(false), + stream(NULL), auto_stream(false), push_mode(false), flush_mode(NormStreamObject::FLUSH_PASSIVE), mgen(NULL), msg_sync(false), mgen_bytes(0), mgen_pending_bytes(0), tracing(false), tx_loss(0.0), rx_loss(0.0) @@ -397,6 +397,8 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val) DMSG(0, "NormSimAgent::ProcessCommand(sendStream) error opening stream!\n"); return false; } + stream->SetFlushMode(flush_mode); + stream->SetPushMode(push_mode); auto_stream = true; } else @@ -430,6 +432,8 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val) DMSG(0, "NormSimAgent::ProcessCommand(openStream) error opening stream!\n"); return false; } + stream->SetFlushMode(flush_mode); + stream->SetPushMode(push_mode); auto_stream = false; tx_msg_len = tx_msg_index = 0; } @@ -469,9 +473,9 @@ bool NormSimAgent::ProcessCommand(const char* cmd, const char* val) else if (!strncmp("push", cmd, len)) { if (!strcmp(val, "on")) - push_stream = true; + push_mode = true; else if (!strcmp(val, "off")) - push_stream = false; + push_mode = false; else { DMSG(0, "NormSimAgent::ProcessCommand(push) invalid argument!\n"); @@ -592,13 +596,12 @@ void NormSimAgent::OnInputReady() { unsigned int bytesWrote = stream->Write(tx_msg_buffer+tx_msg_index, tx_msg_len - tx_msg_index, - NormStreamObject::FLUSH_NONE, - false, push_stream); + false); tx_msg_index += bytesWrote; if (tx_msg_index == tx_msg_len) { - // Provide EOM indication to norm stream - stream->Write(NULL, 0, flush_mode, true, false); + // Mark EOM _and_ flush (using set flush mode) + stream->Write(NULL, 0, true); tx_msg_index = tx_msg_len = 0; } } @@ -609,7 +612,7 @@ bool NormSimAgent::FlushStream() { if (stream && session && session->IsServer()) { - stream->Write(NULL, 0, NormStreamObject::FLUSH_ACTIVE, false, false); + stream->Flush(true); return true; } else @@ -636,9 +639,7 @@ void NormSimAgent::Notify(NormController::Event event, // sending a dummy byte stream char buffer[NormMsg::MAX_SIZE]; unsigned int count = - stream->Write(buffer, segment_size, - NormStreamObject::FLUSH_NONE, - false, false); + stream->Write(buffer, segment_size, false); } else { diff --git a/common/normSimAgent.h b/common/normSimAgent.h index 319938d..38c662d 100644 --- a/common/normSimAgent.h +++ b/common/normSimAgent.h @@ -78,8 +78,8 @@ class NormSimAgent : public NormController NormStreamObject* stream; bool auto_stream; - bool push_stream; - NormStreamObject::FlushType flush_mode; + bool push_mode; + NormStreamObject::FlushMode flush_mode; char* tx_msg_buffer; unsigned int tx_msg_len; unsigned int tx_msg_index; diff --git a/common/normTest.cpp b/common/normTest.cpp index 6d9f506..c5ca626 100644 --- a/common/normTest.cpp +++ b/common/normTest.cpp @@ -64,7 +64,7 @@ int main(int argc, char* argv[]) // NORM_FLUSH_PASSIVE automatically flushes full writes to // the stream. - NormStreamSetFlushMode(stream, NORM_FLUSH_PASSIVE); + NormStreamSetAutoFlush(stream, NORM_FLUSH_PASSIVE); // Some variable for stream input/output @@ -143,18 +143,11 @@ int main(int argc, char* argv[]) // Assume info contains '/' delimited string if (NORM_OBJECT_FILE == NormObjectGetType(theEvent.object)) { - NormObjectTransportId id = NormObjectGetTransportId(theEvent.object); - if (0 != (id & 0x01)) - { - //NormObjectCancel(theEvent.object); - //break; - } - char fileName[PATH_MAX]; strcpy(fileName, cachePath); int pathLen = strlen(fileName); unsigned short nameLen = PATH_MAX - pathLen; - NormObjectGetInfo(theEvent.object, fileName+pathLen, &nameLen); + nameLen = NormObjectGetInfo(theEvent.object, fileName+pathLen, nameLen); fileName[nameLen + pathLen] = '\0'; char* ptr = fileName + 5; while ('\0' != *ptr) @@ -170,7 +163,7 @@ int main(int argc, char* argv[]) } break; - case NORM_RX_OBJECT_UPDATE: + case NORM_RX_OBJECT_UPDATED: { //TRACE("normTest: NORM_RX_OBJECT_UPDATE event ...\n"); if (NORM_OBJECT_STREAM != NormObjectGetType(theEvent.object)) diff --git a/common/normVersion.h b/common/normVersion.h index 0be29a5..f35fbde 100644 --- a/common/normVersion.h +++ b/common/normVersion.h @@ -32,6 +32,6 @@ #ifndef _NORM_VERSION #define _NORM_VERSION -#define VERSION "1.2b4" +#define VERSION "1.2b5" #endif // _NORM_VERSION diff --git a/win32/Norm.opt b/win32/Norm.opt index f2abf06..a2a886f 100644 Binary files a/win32/Norm.opt and b/win32/Norm.opt differ