MDSip Communication Shared Library Details - MdsWiki
Navigation
Personal tools

From MdsWiki

Jump to: navigation, search

Contents

MDSip Communication Shared Libraries to implement communication protocols

When a user connects to a remote server using MDSplus MDSip, the connection string specified will determine the protocol to use for the connection. When the connection is first made, a shared library with the name MdsIp"protocol-name-in-caps" is loaded which will provide the routines necessary to preform the actual transfer of bytes to and from the remote server.

Support for a given protocol includes the implementation of up to 9 routines to provide the following low level I/O operations:

  • Io - return structure containing the addresses of the following support routines
  • Connect - Connect to a remote server
  • Send - Send data buffer to a remote server
  • Recv - Receive a data buffer from the remote server
  • Flush - Flush any remaining bytes in the communication buffers
  • ReuseCheck - Provide a string representation of a proposed connection (explained below)
  • Disconnect - Disconnect from remote server
  • Listen - Server side support. Listen for connections from remote clients
  • Authorize - Server side support. Authenticate client connection

These functions are explained in more detail below.

Io

The shared library needs to export only one entry point, the "Io" function.

  IoRoutines *Io()

This routine take no arguments and simply returns a pointer to a IoRoutines structure defined in the mdsip_connections.h include file. This structure contains pointers to the I/O functions used to implement the protocol.

typedef struct _io_routines {
  int (*connect) (int conid, char *protocol, char *connectString);
  ssize_t (*send)(int conid, const void *buffer, size_t buflen, int nowait);
  ssize_t (*recv)(int conid, void *buffer, size_t len);
  int (*flush) (int conid);
  int (*listen) ( int argc, char **argv);
  int (*authorize) (int conid, char *username);
  int (*reuseCheck) (char *connectString, char *uniqueString, size_t buflen);
  int (*disconnect) (int conid);
} IoRoutines;


Connect

The connect routine is called when a client attempts to connect to a remote server.

 int Connect(int conid, char *protocol, char *connectString)

The conid argument is a connection identifier which is what MDSip uses to keep track of active connections. The protocol is the name of the protocol specified which identified the library to use for these I/O functions. The connectString is the remainder of the "url" specified when the client attempted to open a connection. For example, if the connect string was ssh://twf@cmodws23.psfc.mit.edu, in this case the protocol is "ssh" and the connectString is "twf@cmodws23.psfc.mit.edu".

In the connect function, a connection with a remote server should be established. Any context required to communicate over that connection with the server can be associated with a connection id using a SetConnectionInfo call:

void SetConnectionInfo(int conid, char *info_name, int fd, void *info, size_t len);

If this routine is called a copy of an integer value and a buffer is retained and associated with a particular connection. The other I/O support routines can retrieve this information if necessary to complete the operation.

In the simple case of the original tcp socket connections used to connect clients to a remote server, the connect routine creates a socket, sets various socket characteristics for a connection, connects to the remote server using the hostname and optional port number in the connection string, and then uses SetConnectionInfo to associate the socket with the connection id for this connection passing the socket in the fd argument and 0 for both the info and len arguments.

The Connect call should return -1 for failure and 0 for success.

Send

The send function is to send a buffer over the connection.

  ssize_t Send(int conid, const void *buffer, size_t buflen, int nowait);

The conid argument is the connection identifier. I can be used to call the GetConnectionInfo routine to return connection context information associated with the connection during the connection call. The buffer argument is simply a pointer to a buffer of buflen bytes. The nowait argument is set to non-zero when MDSip would prefer not to wait for completion. This nowait feature is only used for very special purposes and it protocols other than tcp are not expected to support it and should just send the buffer and wait for completion.

The tcp protocol implements this function by retrieving the socket associated with the connection using the GetConnectionInfo call:

void *GetConnectionInfo(int conid, char **info_name, int *fd, size_t *len);

The tcp send function then sends the bytes over the socket using the socket send routine and returns the number of bytes actually sent.

This routine should return the number of bytes sent or a -1 if there was an error. The MDSip layer will automatically close a connection if this routine returns a -1 error indication.

Recv

The recv function is used to receive a buffer over the connection.

  ssize_t Recv(int conid, void *buffer, size_t len);

As in the Send function, the conid argument is the connection identifier which can be used to retrieve the associated context needed to perform the read operation over the connection. In the implementation of the tcp protocol this routine would get the socket number from the conid, use the socket recv routine to read the requested number of bytes and then return the number of bytes actually received. If there was an error this routine should return -1. The MDSip layer will automatically close a connection if this routine returns a -1 error.

Flush

The Flush function is used to empty the connection streams prior to further communication over those streams. This function is optional when implementing a protocol and can be specified as null in the IoRoutines structure returned by the Io() function.

  int Flush(int conid);

Listen

The listen function is what implements the server side of the communication listening for incoming connections and authorizing them and potentially switch accounts.

 int Listen( int argc, char **argv);

The Listen function is invoked by the mdsip program after parsing the standard command options and determining the protocol selected. The standard options are:

Short Form Long Form Description
-P protocol --protocol=protocol Specifies the protocol/communications layer.
-h "hostfile" --hostfile="hostfile" Specifies the hostfile containing mappings between
the connection info and local accounts.
-s --server Specifies that mdsip server should run in "server" mode
which allows multiple connections to the same mdsip
process and sharing common tree and TDI contexts.
-m --multi Specifies that mdsip server should run in "multi" mode
which allows multiple connections to the same mdsip
process but using tree and TDI context switching
giving each connection its own context.
-c --compression Specifies the level of gzip compression of the messages
sent between the client and server. 0-9

The Listen routine should parse the remaining argument list if necessary to obtain settings specific to the protocol. There is a ParseOptions routine available in the MDSip libraries to simplify this. See the IoRoutinesTcp.c in the cvs repository for an example.

After the options are parsed, the Listen routine should check to see if the process is expected to permit multiple connections based on the standard command options. This can be done using the GetMulti() function which will return 1 if multiple connections are to be supported or 0 if only a single client connection is to occur. The Listen routine should then either accept a connection from the client if not providing multiple connections or listen for client connections if GetMulti() returns 1. How this is handled highly depends on the particular protocol being used.

There are a few routines provided in the MDSip libraries that the Listen routine must call to accept connections and to process messages from those connections. When a new connection is received, the Listen routine must call AcceptConnection to establish the connection.

int AcceptConnection(char *protocol,char *info_name, int fd, void *info,size_t infolen, int *conid, char **username);

The protocol argument is the name of the protocol being used. The info_name is the name of the protocol specific information associated with the connection. The fd is an integer file descriptor (if appropriate for the protocol) which can be used by the protocol. The info is a buffer of context information needed by the protocol for communicating with the client (if appropriate for the protocol). The infolen is the size of the info buffer. The conid is the address of the connection identifier to be associated with the connection. The username is the username sent by the client during the initial connection message exchange. The AcceptConnection call will in turn result in a call to the prototype specific Authorize function. If the Authorize function returns an unsuccessful status, the AcceptConnection routine will return a zero indicating the connection was denied. In this case the protocol specific close routine will have already been called and any connection information cleanup will be performed automatically.

If the AcceptConnection returns successfully (return value equals one) then the Listen routine should perform calls to DoMessage when it receives input from the remote client.

int DoMessage(int conid);

The DoMessage routine receives messages from the client, processes those messages and send responses back to the client using the Recv and Send functions of the protocol.

Authorize

The authorize function is called when the client connects to the server. The server can accept or deny the connection. There are help functions the protocol specific authorize function can use to perform a standard mdsip.hosts formatted connection info to account mapping or to call a specialized TDI script for authorization.