M3UA data functions are implemented as a Natural Access service. Natural Access is a development environment for telephony and signaling applications. It provides a standard application programming interface for services, such as signaling protocol stacks, independent of the underlying hardware.
Natural Access is described in detail in the Natural Access Developer's Reference Manual. Understanding the basic Natural Access programming concepts, including services, queues, contexts, and asynchronous events, is critical to developing applications that utilize the M3UA service.
Before calling any M3UA service functions, the application must:
Initialize the Natural Access environment by calling ctaInitialize once per application, regardless of the number of queues and contexts to be created:
CTA_INIT_PARMS M3UAInitparms = {0};
CTA_SERVICE_NAME M3UAServiceNames[] = {{"M3UA", "M3UAMGR"}};
...
M3UAInitparms.size = sizeof(CTA_INIT_PARMS);
M3UAInitparms.traceflags = CTA_TRACE_ENABLE;
M3UAInitparms.parmflags = CTA_PARM_MGMT_SHARED;
M3UAInitparms.ctacompatlevel = CTA_COMPATLEVEL;
Ret = ctaInitialize(M3UAServiceNames, 1, &M3UAInitparms);
if (Ret != SUCCESS)
{
printf("ERROR code 0x%08x initializing Natural Access.", Ret);
exit( 1 );
}
The application creates the required Natural Access queues and contexts, as described in Contexts and queues. The queue must always be created before any context associated with it.
CTAHD ctaHd; /* CTA context handle */
CTAQUEUEHD ctaQueue; /* Queue */
...
Ret = ctaCreateQueue( NULL, 0, &ctaQueue );
if ( Ret != SUCCESS )
{
ctaGetText( NULL_CTAHD, Ret, sErr, sizeof( sErr ) );
printf( "*ERROR : ctaCreateQueue failed( %s )\n", sErr );
...
}
sprintf( contextName, "M3UASAP-%d", spId ); /* context name is optional */
Ret = ctaCreateContext( ctaQueue, spId, contextName, &ctaHd );
if ( Ret != SUCCESS )
{
ctaGetText( NULL_CTAHD, Ret, sErr, sizeof( sErr ) );
printf( "ERROR : ctaCreateContext failed( %s )\n", sErr );
ctaDestroyQueue( pSap->ctaQueue );
...
}
After the queues and contexts are created, the application must bind itself to each desired M3UA NSAP by calling ctaOpenServices once for each binding. The binding operation specifies the following parameters:
Parameter |
Description |
board |
TX board number. |
srvInfo |
Service information octet. |
sapId |
M3UA NSAP ID (defined in configuration) on which to bind. This parameter must be passed in all functions that make requests to the board. |
srcEnt |
Calling application entity ID. |
srcInst |
Calling application instance ID. |
suId |
Calling application service user ID. This parameter is passed up in future indications from the board. |
poolsize |
Number of messages allowed to be queued to the TX board. Default value is 256. |
Under Natural Access, these parameters are specified in the CTA_SERVICE_ARGS structure, contained in the CTA_SERVICE_DESC structure. An example of the parameter specification is provided:
CTA_SERVICE_DESC M3UAOpenSvcLst[] = {{{"M3UA","M3UAMGR"}, {0}, {0}, {0}}};
M3UAOpenSvcLst[0].svcargs.args[0] = Board; /* board number */
M3UAOpenSvcLst[0].svcargs.args[1] = Sio; /* Service Information
* Octet */
M3UAOpenSvcLst[0].svcargs.args[2] = NSapNmb; /* network SAP number */
M3UAOpenSvcLst[0].svcargs.args[3] = MyEnt; /* application entity ID */
M3UAOpenSvcLst[0].svcargs.args[4] = DFLT_INST; /* Inst ID */
M3UAOpenSvcLst[0].svcargs.args[5] = SuId; /* Service user ID */
M3UAOpenSvcLst[0].svcargs.args[6] = poolsize; /* Pool size */
ctaOpenServices is an asynchronous function. The return from the function indicates that the bind operation was initiated. Once completed, a CTAEVN_OPEN_SERVICES_DONE event is returned to the application.
If multiple contexts are assigned to the same queue, all of those contexts must use the same entity ID in the service arguments parameter. Conversely, contexts bound to different queues must specify unique entity IDs.
CTA_EVENT event; /* Event structure to wait for M3UA events */
...
Ret = ctaOpenServices( ctaHd, M3UAOpenSvcLst, 1 );
if ( Ret != SUCCESS )
{
ctaGetText( NULL_CTAHD, Ret, sErr, sizeof( sErr ) );
printf( "ERROR : ctaOpenServices failed( %s )\n", sErr );
ctaDestroyQueue( ctaQueue ); /* destroys context too */
return(...)
}
/* Wait for "open services" to complete; note: this loop
* assumes no other contexts are already active on the queue
* we're waiting on, so no other events will be received that
* need handling
*/
event.id = CTAEVN_NULL_EVENT;
do
{
ctaWaitEvent( ctaQueue, &event, 5000 );
}
while( (event.id != CTAEVN_OPEN_SERVICES_DONE) &&
(event.id != CTAEVN_WAIT_TIMEOUT) );
/* check if binding succeeded */
if( (pSap->event.id != CTAEVN_OPEN_SERVICES_DONE) ||
(pSap->event.value != CTA_REASON_FINISHED) )
{
ctaGetText( event.ctahd, event.value, sErr, sizeof( sErr ) );
printf( "ERROR opening M3UA service [%s]\n", sErr );
ctaDestroyQueue( pSap->ctaQueue ); /* destroys context too */
return( ... );
}
This example is correct only if the application uses a separate queue for each context and service instance. If the application opens multiple service instances against the same queue, with either multiple SAPs on the same board or on multiple boards (in a redundant configuration), it must process events (call M3UARetrieveMessage) for other contexts while waiting for the CTAEVN_OPEN_SERVICES_DONE event. Failure to do so can result in an infinite loop.