Download tutorial source code |
Click here to download |
Last update | Dec 2020 |
Compilers | Refer to the ETA Compiler Guides for a complete list. |
Prerequisites | ETA Consumer - Establishing a connection to a Provider |
The goal of this tutorial is to extend Tutorial 2 to establish a session with the OMM-based Provider by submitting valid login credentials and to request and retrieve the source directory. The source directory is a collection of services that are supported by the connected Provider. Each service within this directory contains a number of important details that identify attributes such as the state of the service, the data supported by that service, etc.. Depending on the features of your application, certain details retrieved from the source directory are mandatory when requesting additional content from the OMM-based Provider.
In this tutorial, we introduce a new file "basicDirectoryHandler.c" to process events related to the source directory details provided by our OMM-based Provider. Derived from Tutorial 2, we will enhance the "basicConsumer.c" functionality to define our login and directory requests to our Provider. One of the key benefits of the Transport API Reactor module is the management of the RDM administrative functions, login and directory. By registering interest in these capabilities, the Reactor will manage the submission and event processing on the Consumer's behalf.
Piggybacking off of our existing code, to handle these new RDM administrative functions, we define the following:
/* RDM objects used at startup */
RsslReactorConnectOptions connectionOptions;
RsslRDMLoginRequest loginRequest; // Login Object
RsslRDMDirectoryRequest directoryRequest; // Directory Object
void init()
{
...
/* After this consumer successfully connects to a server (Real-Time Distribution System), we must log in.*/
/* Initialize a default login request (Use 1 as the Login Stream ID). */
if (rsslInitDefaultRDMLoginRequest(&loginRequest, 1) != RSSL_RET_SUCCESS)
{
printf("rsslInitDefaultRDMLoginRequest() failed\n");
cleanUpAndExit(-1);
}
/* Initialize the default directory request (Use 2 as the Directory Stream Id) */
if (rsslInitDefaultRDMDirectoryRequest(&directoryRequest, 2) != RSSL_RET_SUCCESS)
{
printf("rsslInitDefaultRDMDirectoryRequest() failed\n");
cleanUpAndExit(-1);
}
...
/* Set the messages to send when the channel is up */
consumerRole.pLoginRequest = &loginRequest;
consumerRole.pDirectoryRequest = &directoryRequest;
/**************************************************************************
* Setup callback functions for our connection channel - consumer role
**************************************************************************/
/* Login callback */
consumerRole.loginMsgCallback = loginMsgCallback;
/* Directory callback */
consumerRole.directoryMsgCallback = directoryMsgCallback;
...
}
In the above code segment, the consumer role defines additional RDM administrative callbacks to establish our basic session. Once we successfully connect into our Provider, the Transport API Reactor will automatically submit the supplied login request on our behalf. By initializing the login object RsslRDMLoginRequest, it will default to your system login credentials. If there is a requirement to override the default credentials, it can occur after this initializing call. Refer to the Value Add Developers Guide - Administration Domain Models for more details.
Based on the credentials, the Provider will validate the login request and respond appropriately. The response is captured within the specified callback:
RsslReactorCallbackRet loginMsgCallback(RsslReactor *pReactor, RsslReactorChannel *pChannel, RsslRDMLoginMsgEvent *pLoginMsgEvent)
{
...
// Determine login type
switch (pLoginMsg->rdmMsgBase.rdmMsgType)
{
case RDM_LG_MT_REFRESH:
{
RsslRDMLoginRefresh *pLoginRefresh = &pLoginMsg->refresh;
/* get state information */
rsslStateToString(&tempBuffer, &pLoginRefresh->state);
printf("\nReceived Login response: %.*s\n\n", tempBuffer.length, tempBuffer.data);
break;
}
case RDM_LG_MT_STATUS:
printf("\nReceived Login StatusMsg\n");
if (pLoginMsg->status.flags & RDM_LG_STF_HAS_STATE)
{
/* get state information */
rsslStateToString(&tempBuffer, &pLoginMsg->status.state);
printf(" %.*s\n\n", tempBuffer.length, tempBuffer.data);
}
break;
...
}
return RSSL_RC_CRET_SUCCESS;
}
The above code segment simply reports the result of the login. The Transport API Reactor will automatically evaluate the details of the login result to determine if it should submit a source directory request. Upon a successful login, the Reactor will submit the source directory request to the Provider.
The source directory callback is responsible for processing the details of the Directory response from the Provider. Depending on the requirements of an application, some of the details returned within the source directory are mandatory for additional communication to the OMM-based data Provider. The Source Directory response provides a list of services with the following details:
The service ID is a mandatory element necessary when requesting for market data - which will be used in future tutorials within this series. As such, a simple Service data structure has been defined to house these details. Within the "basicDirectoryHandler.h" file, we have defined the BasicService structure to capture the relevant details utilized within our Consumer application.
/* Directory details */
typedef struct
{
char serviceName[256]; /* Name of the service we're interested in */
RsslUInt16 serviceId; /* Corresponding ID for service Name defined within directory */
} BasicService;
Within our callback, we execute the call to process the Source Directory details. Although we could have housed the entire processing within the "basicConsumer.c" module, the intention was to offload the functionality into a separate file "basicDirectoryHandler.c" for purposes of modularity and possible future enhancements.
/* Name of our market data service */
#define SERVICE "ELEKTRON_AD"
BasicService service = { SERVICE, 0 }; // Service Object
...
RsslReactorCallbackRet directoryMsgCallback(RsslReactor *pReactor, RsslReactorChannel *pChannel,
RsslRDMDirectoryMsgEvent *pDirectoryMsgEvent)
{
RsslRDMDirectoryMsg *pDirectoryMsg = pDirectoryMsgEvent->pRDMDirectoryMsg;
...
/* Process the directory response */
return(processDirectoryResponse(pDirectoryMsgEvent, &service));
}
The "basicDirectoryHandler.c" source file contains the details to walk through and pull out the relevant elements of interest. In our case, we're interested in retrieving the serviceId and populating our supplied structure. While the processing details are important, the codebase and the decoding of elements are beyond the scope of this tutorial. The basic processing was derived from the example VAConsumer which will act as a good reference for additional processing requirements.
For these instructions, refer to the Build and Run section within the first tutorial of this series.
Note: Ensure you can connect into a valid LSEG Real-Time Distribution System to test. Defined within the basicConsumer.c file, these tutorials assume the following server has been defined:
/* Server/Provider connection details */
#define RTDS_SERVER_NAME "rtds"
#define RTDS_SERVER_PORT "14002"
...
You can either define the server name 'rtds' within your environment to point to a valid market data server or simply modify these server configuration paramters to suit your setup. Running the tutorial will display the login results and some general statistics regarding the Source Directory response from the OMM-based Provider.
Note: The OMM-based Provider you are connected into will yield different Directory details.
> Received Login response: State: Open/Ok/None - text: "Login accepted by host cil-p2ps6-2."
>
> Received Source Directory Response: State: Open/Ok/None - text: ""
> Received serviceName: DDN_SSL. Service State: Up
> Received serviceName: ELEKTRON_AD. Service State: Up
> Found your service ELEKTRON_AD using serviceId: 105
> Received serviceName: DDN_RDF. Service State: Up
> Received serviceName: MLIP_NGN. Service State: Up
> Received serviceName: IDN_RDF. Service State: Up
> Received serviceName: EZD_RSSL. Service State: Up
> Received serviceName: MLIP_MPLS. Service State: Up
> Received serviceName: EZD_SSL. Service State: Up
>Channel is ready.
For more information, refer to the Transport API - C Development Guides.