5.4 Defining a Service

You must define every service routine as a function that receives one argument consisting of a pointer to a TPSVCINFO structure. The TPSVCINFO structure is defined in the atmi.h header file and includes the following information:

char       name[32];
long       flags;
char       *data;
long       len;
int        cd;
int        appkey;
CLIENTID   cltid;

The following table summarizes the TPSVCINFO data structure.

Table 5-1 TPSVCINFO Data Structure

Field Description
name Specifies, to the service routine, the name used by the requesting process to invoke the service.
flags Notifies the service if it is in transaction mode or if the caller is expecting a reply. The various ways in which a service can be placed in transaction mode are discussed in “Writing Global Transactions” on page 9-1.

The TPTRAN flag indicates that the service is in transaction mode. When a service is invoked through a call to tpcall() or tpacall() with the flags parameter set to TPNOTRAN, the service cannot participate in the current transaction. However, it is still possible for the service to be executed in transaction mode. That is, even when the caller sets the TPNOTRAN communication flag, it is possible for TPTRAN to be set in svcinfo->flags. For an example of such a situation, refer to “Writing Global Transactions” on page 9-1.

The flags member is set to TPNOREPLY if the service is called by tpacall() with the TPNOREPLY communication flag set. If a called service is part of the same transaction as the calling process, it must return a reply to the caller.

data Pointer to a buffer that was previously allocated by tpalloc() within the main(). This buffer is used to receive request messages. However, it is recommended that you also use this buffer to send back reply messages or forward request messages.
len Contains the length of the request data that is in the buffer referenced by the data field.
cd For conversational communication, specifies the connection descriptor.
appkey Reserved for use by the application. If application-specific authentication is part of your design, the application-specific authentication server, which is called when a client joins the application, should return a client authentication key as well as an indication of success or failure. The Oracle Tuxedo system holds the appkey on behalf of the client and passes the information to subsequent service requests in this field. By the time the appkey is passed to a service, the client has already been authenticated. However, the appkey field can be used within a service to identify the user invoking the service or some other parameters associated with the user.

If this field is not used, the system assigns it a default value of -1

.
cltid Structure of type CLIENTID used by the system to carry the identification of the client. You should not modify this structure.

When the data field in the TPSVCINFO structure is being accessed by a process, the following buffer types must agree:

  • Type of the request buffer passed by the calling process
  • Type of the corresponding buffer code defined within the called service
  • Type of the associated buffer type defined for the called service in the configuration file

The following listing illustrates a typical service definition. This code is borrowed from the ABAL (account balance) service routine that is part of the banking application provided with the Oracle Tuxedo software. ABAL is part of the BAL server.

Listing Typical Service Definition

#include <stdio.h>           /* UNIX */
#include <atmi.h>            /* ORACLE Tuxedo System */
#include <sqlcode.h>         /* ORACLE Tuxedo System */
#include "bank.flds.h"       /* bankdb fields */
#include "aud.h"             /* BANKING view defines */

EXEC SQL begin declare section;
static long branch_id;  /* branch id */
static float bal;            /* balance */
EXEC SQL end declare section;

 /*
  * Service to find sum of the account balances at a SITE
  */

void
#ifdef __STDC__
ABAL(TPSVCINFO *transb)

#else

ABAL(transb)
TPSVCINFO *transb;
#endif

{
     struct aud *transv;           /* view of decoded message */

     /* Set pointer to TPSVCINFO data buffer */

     transv = (struct aud *)transb->data;

     set the consistency level of the transaction   
       
     /* Get branch id from message, do query */ 

     EXEC SQL declare acur cursor for
       select SUM(BALANCE) from ACCOUNT;
     EXEC SQL open acur;           /* open */
     EXEC SQL fetch acur into :bal;   /* fetch */
     if (SQLCODE != SQL_OK) {      /* nothing found */
      (void)strcpy (transv->ermsg,"abal failed in sql aggregation");
      EXEC SQL close acur;
      tpreturn(TPFAIL, 0, transb->data, sizeof(struct aud), 0);
      }
      EXEC SQL close acur;
      transv->balance = bal;
      tpreturn (TPSUCCESS, 0, transb->data, sizeof(struct aud), 0);
}

In the preceding example, the application allocates a request buffer on the client side by a call to tpalloc() with the type parameter set to VIEW and the subtype set to aud. The ABAL service is defined as supporting the VIEW typed buffer. The BUFTYPE parameter is not specified for ABAL and defaults to ALL. The ABAL service allocates a buffer of the type VIEW and assigns the data member of the TPSVCINFO structure that was passed to the ABAL subroutine to the buffer pointer. The ABAL server retrieves the appropriate data buffer by accessing the corresponding data member, as illustrated in the preceding example.

Note:

After the buffer is retrieved, but before the first attempt is made to access the database, the service must specify the consistency level of the transaction. Refer to Writing Global Transactions for more details on transaction consistency levels.