Initializing the M3UA service under Natural Access

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:

  1. Initialize the Natural Access run-time environment.

  2. Create the desired queues and contexts.

  3. Open the M3UA service to bind it to the desired M3UA service access points (SAPs).

Initializing the Natural Access environment

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 );
}

Creating queues and contexts

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 );
     ...
}

Using ctaOpenServices

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.