Sample Applications

 

This section presents a comparison of a sample threadsafe application and a sample of non-threadsafe application, both written in a SwitchKit API development environment.

Sample Non-Threadsafe Application

The following shows a simple application both using the standard SwitchKit library.

What the application does

1. Connects with an LLC

2. Sets up handlers:

A default handler that will receive all messages should other handlers not be enabled to catch a message

A group handler for receiving all inbound call notifications via the RequestForService or RFSWithData messages

3. Registers for PPLEventIndication and DS0StatusChange messages

4. Loops forever waiting for a message from the LLC.

Sample Non-Threadsafe Code

main(int argc, int argv)

{

...

// (1) Establish connections to LLC’s

int status = skts_createConnection(

1, // connection ID
-1, // application ID (allow LLC to select one)
0, //isForced (set to 0)
"host1", // primary LLC host name
1312, // primary LLC port number (1312 is default)
"host2", // redundant LLC hostname
1312); // redundant LLC port number 1312

if (status == NULL)
{
cout << íError has occurred creating connection to LLCî << endl;
return (-1);
}

...

// (2) Define Handler Functions – returns OK always

// (2a) Default Handler

(void)skts_setDefaultHandler(someTag, // tag for hdlr

someDefaultHandlerFunc); // handler func

 

// (2b) Set Group Handler for inbound calls

(void)sk_setGroupHandler("inboundChannelGroup", // group name

NULL, // tag for hdlr

someGroupHandlerFunc); // handler func

...
// (3) Register for unsolicited messages
status = sk_msgRegisterOnConnection(

SK_PPLEIS | SK_DS0S, // registration mask

1); //connection ID

if (status != OK) {
cout << "Error has occurred registering for message with LLC"

<< endl;

return (-1);
}

(4) Register for new calls from the specified channel group

status = sk_watchChannelGroupOnConnection(

"inboundChannelGroup", // group name

1); //connection ID

if status !=OK {

cout << Error requesting watch of channel group"

<< endl;

return (-1);

}

...

...

// (5) SwitchKit receives loop

while(1) {

char *buffer; //where msg will be returned if not handled

int size; // size of msg returned

void *data; //needed for function call. Not used by API

 

status = sk_rcvAndDispatchAutoStorage(

&buffer, // contains packed msg if msg not handled

&size, // size of message returned

-1, // timeout - wait forever

&data); // Not currently used.

 

if (status != OK) {

switch(status) {

case SK_NO_MESSAGE:

// This is a normal return and indicates that

// an internal message was returned.

break;

 

case SK_BAD_MESSAGE:

cout << " Bad Message rcvd from SwitchKit "

<< endl;

break;

 

case SK_LOST_LLC:

cout << " Lost Contact With LLC "

<< endl;

break;

 

case SK_NOT_HANDLED:

{

// Message was not processed by any

// application defined handlers

SKC_Message *inboundMsg;

int retval = skc_unpackMessage(

buffer,

size,

&inboundMsg);

if (retval != OK)

{

cout << "Error unpacking message"

<< endl;

break;

}

cout << "Received message "

<< inboundMsg->getMsgName()

<< endl;

break;

}

} // end switch

} // end if

} // end while

...

}

 

Sample ThreadSafe Application

In order to convert the simple application presented above into a threadsafe application, you must make the following changes (the text in the right column show how to update the previous application’s code to make the application threadsafe.

What the non- threadsafe application does...

What to do to make the previous application threadsafe....

(0) Not applicable

The skts_enableThreadSafeLib() function initializes some global process level data and enables detection of the mixing of threadsafe and non threadsafe functions. This function must be called first in a multi-threaded environment before any other SwitchKit calls. Failure to call this function first will result in unexpected behavior.

(1) Connects with an LLC

Convert sk_createConnectionWithID() to the threadsafe version of the function, skts_createConnection(). The arguments to both functions are the same. The only difference is the sk_createConnectionWithID() returns the opaque SK_Connection * while the threadsafe version returns a status code. The status value of OK means that the function call was successful.

Your application may currently use one of several other ways to establish a connection including sk_initializeConnection(), sk_initializeConnectionForced() and sk_createConnection(). Or, it may not even explicitly connect to the LLC (in which case, the environment variables are used to determine the location of primary and redundant LLC). These functions are not supported for threadsafe applications. The only way to connect to the LLC for thread safe applications is using skts_createConnection().

The connection ID concept allows an application to connect to multiple redundant LLC pairs for scalability. Specifying a connection ID dictates which LLC the SK API will use as the target of a function or message. All threadsafe functions that result in messages being sent to an LLC require a connection ID as the last argument.

(2) Sets up handlers:

(a) A default handler that will receive all messages should other handlers not be enabled to catch a message

(b) A group handler for receiving all inbound call notifications via the RequestForService or RFSWithData messages

 

(a) Convert sk_setDefaultHandler() to the threadsafe version of the function, skts_setDefaultHandler(). The arguments to both functions are the same.

(b) Convert sk_setGroupHandler() to the threadsafe version of the function, skts_setGroupHandler().The arguments to both functions are the same.

(3) Registers for PPLEventIndication and DS0StatusChange messages

 

Convert sk_msgRegisterOnConnection() to the threadsafe version of the function, skts_msgRegister(). The arguments to both functions are the same.

Your application may use a slightly different registration function sk_msgRegister(). As mentioned in (1) above, all threadsafe functions require the use of a connection ID to indicate which LLC to target. Note: If your application previously used sk_msgRegister(), use the same connection ID value specified in a previous skts_createConnection() function.

(4) Registers with the LLC for new calls arriving on channels within the specified group.

 

Convert sk_watchChannelGroupOnConnection() to the threadsafe version of the function, skts_watchChannelGroup(). The arguments are identical. Your application may use a slightly different watch channel group function, sk_watchChannelGroup().As mentioned in (1) above, all threadsafe functions require the use of a connection ID to indicate which LLC to target. Note: If your application previously used sk_watchChannelGroup(), use the same connection ID value specified in a previous skts_createConnection() function.

(5) Loops forever waiting for a message from the LLC.

Convert sk_rcvAndDispatchAutoStorage() to the threadsafe version of the function, skts_rcvAndDispatchAutoStorage(). The arguments are nearly identical with the exception of the last argument, a connection ID. For skts_rcvAndDispatchAutoStorage() and skts_rcvAndDispatch(), the connection ID argument is an output argument and is used to indicate which LLC connection generated the message should the message be returned in skts_rcvAndDispatch()/skts_rcvAndDispatchAutoStorage(). This would only happen if skts_rcvAndDispatch()/ skts_rcvAndDispatchAutoStorage() returns SK_NOT_HANDLED.

Sample Threadsafe Code

The modified code is shown below. Any changes that are necessary are noted in bold text.

 

main(int argc, int argv)

{

...

// (0) Initialize the threadsafe library.

// This function will initialize some global process level data and

// enable the detection of the mixing of Threadsafe with non Threadsafe // //functions. This function MUST be called first. Failure to call

// this function first or at all will result in unexpected behavior.

skts_enableThreadSafeLib();

 

// (1) Establish connections to LLC’s

int status = skts_createConnection(

1, // connection ID
example, // a const char * to label the connection
-1, // application ID (allow LLC to select one)
0, // isForcedFlag (set to 0)
"host1",// primary LLC host name
1312, // primary LLC port number (1312 is default)
"host2", // redundant LLC hostname
1312); // redundant LLC port number (1312)

if (status != OK)
{
cout << íError has occurred creating connection to LLCî << endl;
return (-1);
}

...

// (2) Define Handler Functions – returns OK always

// (2a) Default Handler

(void)skts_setDefaultHandler(someTag,// tag for hdlr

someDefaultHandlerFunc);

 

// (2b) Group Handler to register for inbound calls

(void)skts_setGroupHandler("inboundChannelGroup", // group name

NULL, // tag for hdlr

someGroupHandlerFunc); // handler func

...
// (3) Register for unsolicited messages
status = skts_msgRegister(

SK_PPLEIS | SK_DS0S, //registration mask

1); // connection ID

if (status != OK) {
cout << "Error has occurred registering for message with LLC"

<< endl;

return (-1);
}

...

// (4) Register for new calls from a specified group

status = skts_watchChannelGroup (

"inboundChannelGroup", // group name

1); // connection ID

if (status != OK) {

cout << "Error requesting watch of channel group"

<< endl;

return (-1);

 

(5) SwitchKit receive loop

while(1) {

char *buffer; // where msg will be return if not handled

int size; // size of msg returned

void *data; // needed for function call. Not used by API.

int retConID; // conn ID of LLC the message was received from

 

status = skts_rcvAndDispatchAutoStorage(

&buffer, // contains packed msg if msg not handled

&size, // size of message returned

-1, // timeout - wait forever

&data, // Not currently used.
&retConID); // connection ID on which msg was rcvd

 

if (status != OK) {

// The code here is exactly the same as in

// Sample Non-Threadsafe Code and is excluded for brevity

} // end if

} // end while

...

}