NormSocket API Extension Notes

The NormSocket API (currently defined in examples/normSocket.h) is an in-development extension to the
base (low-level) NORM API (defined in include/normApi.h) that provides a more familiar (socket-like),
easier-to-use API for some specific NORM use patterns.  The use patterns supported here are those of a
client-server paradigm where "clients" have individual, reliable connections to the server and the
"server" can have either a one-to-many multicast connection or individual unicast connections to the set
of clients.  The paradigm follows a connection-oriented socket model where the server "listens" for
incoming connections initiated by clients.  The low-level NORM API is used to establish multiple NORM
sessions as needed to support the necessary data exhange relationships. Since this is a
connection-oriented model, explicit ACK-based flow control used for both client-to-server and
server-to-client(s) data transfers.  This is a more controlled model of NORM use as compared to the
looser "connection-free" model of operation NORM use has typically observed.

The NormSocket API code makes careful use of operating system socket-binding to enable port reuse and
simpler session establishment where clients can "connect" to the server listening on a well-known port
as compared to typical base NORM API use where participants can exchange data on a a priori known common
port number (and group address if multicast).  However, the clients do need to know the unicast address
of the server and the paradigm is somewhat that of Single-Source Multicast (SSM).  Client application
can, of course, using multiple NormSocket instances connect to multiple multicast (or unicast) servers.. 
THere
A server application can use the NormListen() call to establish a session that listens for incoming
connection requests, Client applications can use the NormConnect() call to initiate a connection to a
listening server.  In response, the server application can use NormAccept() to establish connections with
the clients.  

At the moment a NormGetSocketEvent() (analogous to the NormGetNextEvent() call in the base NORM API) can
be used to provide cues to changes in NormSocket state (notification of incoming connections, connection
establishment, read/write readiness, etc.).  A descriptor is provided for asynchronous I/O notification
of pending events.  At the moment, the default behavior is a single NormInstance, and hence a single
descriptor, can be used for multiple NormSockets, but it is possible to call NormCreateInstance() and
associate a separate NormInstance (and hence separate descriptor) with each NormSocket that is
listending, connected or accepted if desired.  

As the NormSocket API extension matures, more examples and documentation will be provided as well as
incorporating it (possibly directly) into the "normApi.h" header file and NORM library.  At the moment,
"examples/normClient.cpp" and "examples/normServer.cpp" illustrate (and test) basic usage of the API. 
The "normServer" can be run as a unicast server using the syntax:

./normServer listen <serverPort>

or a multicast server using the syntax:

./normServer listen <groupAddr>/<serverPort>

Corresponding "normClient" instances can connect to unicast server using the syntax:

./normClient connect <serverAddr>/<serverPort>

or to a multicast server using the syntax:

./normClient connect <serverAddr>/<serverPort>,<groupAddr>

There are some additional command-line options shared by these examples such as "trace" to enable NORM's
message trace output and "debug <debugLevel>" to invoke different levels of debug output.  Note that an
option to specify the multicast interface is planned but not yet implemented in these examples.
Similarly, an option to set a specific unicast server binding will also be provided.

TODO (not in priority order):

1) When client initiates connection and server-listener receives NORM_CMD(CC), add code
   to directly "inject" the NORM_CMD(CC) into the newly created server-side client
   session such that NORM_ACK is immediately sent.  This will give client a more immediate
   RTT measurement, etc.
   
2) Add options to set transmit rate, congestion control, etc options via NormSocketHandle
   (current code works at default tx rate of 64 kbps)
   
3) The server-listener session should be modified so NORM_DATA messages are ignored.  Also,
   NormSetServerListener() could also set the session a silent receiver, too?
      
4) Add support for additional transport modes in addition to current byte stream:
`   1) Message stream
    2) NORM_OBJECT_DATA (w/ data copy option?)
    3) NORM_OBJECT_FILE
    
5) Add option to specify multicast "interface" and use in examples.

6) Enable setting a specific unicast server binding address.    


===========================================================================
MISC. DEVELOPMENT NOTES

// Notional  program outline
// (optional mcastAddr iff asymm multicast/unicast (i.e. SSM))

normSocket = NormListen(port, [mcastAddr])

_or_

normSocket = NormConnect(addr, port, [mcastAddr])

while NormGetSocketEvent(normSocket)
{

    switch (event.GetType())
        NORM_ACCEPT:
            clientSocket = NormAccept(normSocket, client, [instance]);  // rx-only for asymm mcast case
            
        NORM_CONNECTED:
            // in response to NormConnect when "server" is detected (NEW_REMOTE_SENDER)
            
        NORM_TX_READY:
            upon QUEUE_VACANCY, etc ... socket _might_ be write() ready
            
        NORM_RX_READY:

            upon RX_OBJECT_NEW, RX_OBJECT_UPDATE ... socket _might_ be read() ready
            
        NORM_CLOSING: ???
            upon stream end received from remote sender
            
        NORM_CLOSED: ???
            upon stream end _and_ ack to our stream end
}



 *** Server listen on a port (optional mcast address):

- Create NormSession that receive-only on given port (if it's asymm mcast, then sender enabled, too)

- For each client (detected via NEW_REMOTE_SENDER yielding a NormSocket::NORM_ACCEPT event)
      Create tightly binded session for rx (and tx if unicast) ... this will fail if binding already exists
      

*** Client connect

- Create single socket (common ephemeral tx/rx port) NormSession for server destination addr/port.
- Call NormStartSender() to initiate probing of server
- NORM_CONNECTED upon NEW_REMOTE_SENDER (from server) ???


QUESTIONS:

1) How does a server reject a connection request?  (for now, just ignore)

2) How is a "connection" gracefully terminated? (NormShutdown() vs. NormClose()?)


NormClose(graceful = false) ... 
 a) stop sender/receiver, destroy everything

NormShutdown(graceful = true) ... 
 a) close stream (gracefully, w/ ack request)
 b) upon ack receipt (or timeout) _and_ rx stream end, destroy everything
 

Upon receipt of rx stream end, close tx stream gracefully ...

 initiator -> stream end; upon ack set tx_stream = NULL and wait for rx_stream end
 
 receptor -> upon rx_stream end, initiate tx_stream shutdown and wait for ack
 
