5.5.3 Forwarding Requests

The tpforward(3c) function allows a service to forward a request to another service for further processing.

Use the following signature to call the tpforward() function:

void
tpforward(char *svc, char *data, long len, long flags)

The following table describes the arguments to the tpreturn() function.

Table 5-3 tpreturn() Function Arguments

Argument Description
svc Character pointer to the name of the service to which the request is to be forwarded.
data Pointer to the reply message that is returned to the client process. The message buffer must have been allocated previously by tpalloc(). If you use the same buffer that was passed to the service in the SVCINFO structure, you need not be concerned with buffer allocation or disposition because both are handled by the system-supplied main(). You cannot free this buffer using the tpfree() command; any attempt to do so quietly fails. You can resize the buffer using the tprealloc() function. If you use another buffer (that is, a buffer other than the one that is passed to the service routine) to return the message, it is your responsibility to allocate it. The system frees the buffer automatically when the application calls the tpreturn() function. If no reply message needs to be returned, set this argument to the NULL pointer.

Note:

If no reply is expected by the client (that is, if TPNOREPLY was set), the tpreturn() function ignores the data and len arguments and returns control to main().
len Length of the reply buffer. The application accesses the value of this argument through the olen parameter of the tpcall() function or the len parameter of the tpgetrply() function. Acting as the client, the process can use this returned value to determine whether the reply buffer has grown. If a reply is expected by the client and there is no data in the reply buffer (that is, if the data argument is set to the NULL pointer), the function sends a reply with zero length, without modifying the client’s buffer. The system ignores the value of this argument if the data argument is not specified.
flag Currently not used.

The functionality of tpforward() differs from a service call: a service that forwards a request does not expect a reply. The responsibility for providing the reply is passed to the service to which the request has been forwarded. The latter service sends the reply to the process that originated the request. It becomes the responsibility of the last server in the forward chain to send the reply to the originating client by invoking tpreturn().

The following figure shows one possible sequence of events when a request is forwarded from one service to another. Here a client initiates a request using the tpcall() function and the last service in the chain (SVC_C) provides a reply using the tpreturn() function.

Figure 5-1 Forwarding a Request


Forwarding a Request Diagram

Service routines can forward requests at specified priorities in the same manner that client processes send requests, by using the tpsprio() function.

When a process calls tpforward(), the system-supplied main() regains control, and the server process is free to do more work.

Note: If a server process is acting as a client and a reply is expected, the server is not allowed to request services from itself. If the only available instance of the desired service is offered by the server process making the request, the call fails, indicating that a recursive call cannot be made. However, if a service routine sends a request (to itself) with the TPNOREPLY communication flag set, or if it forwards the request, the call does not fail because the service is not waiting for itself.

Calling tpforward() can be used to indicate success up to that point in processing the request. If no application errors have been detected, you can invoke tpforward(), otherwise, you can call tpreturn() with rval set to TPFAIL.

The following listing is borrowed from the OPEN_ACCT service routine which is part of the ACCT server. This example illustrates how the service sends its data buffer to the DEPOSIT service by calling tpforward(). The code shows how to test the SQLCODE to determine whether the account insertion is successful. If the new account is added successfully, the branch record is updated to reflect the new account, and the data buffer is forwarded to the DEPOSIT service. On failure, tpreturn() is called with rval set to TPFAIL and the failure is reported on the status line of the form.

Listing tpforward( ) Function

...
/* set pointer to TPSVCINFO data buffer */
transf = (FBFR *)transb->data;
...
/* Insert new account record into ACCOUNT*/
account_id = ++last_acct;    /* get new account number */
tlr_bal = 0.0; /* temporary balance of 0 */
EXEC SQL insert into ACCOUNT (ACCOUNT_ID, BRANCH_ID, BALANCE, 
ACCT_TYPE, LAST_NAME, FIRST_NAME, MID_INIT, ADDRESS, PHONE) values
(:account_id, :branch_id, :tlr_bal, :acct_type, :last_name,
       :first_name, :mid_init, :address, :phone);
if (SQLCODE != SQL_OK) { /* Failure to insert */
      (void)Fchg(transf, STATLIN, 0,
          "Cannot update ACCOUNT", (FLDLEN)0);
      tpreturn(TPFAIL, 0, transb->data, 0L, 0);
}

/* Update branch record with new LAST_ACCT */

EXEC SQL update BRANCH set LAST_ACCT = :last_acct where BRANCH_ID = :branch_id;
if (SQLCODE != SQL_OK) { /* Failure to update */
       (void)Fchg(transf, STATLIN, 0,
            "Cannot update BRANCH", (FLDLEN)0);
       tpreturn(TPFAIL, 0, transb->data, 0L, 0);
}
/* up the priority of the deposit call */
if (tpsprio(PRIORITY, 0L) == -1)
   (void)userlog("Unable to increase priority of deposit\n");

/* tpforward same buffer to deposit service to add initial balance */
tpforward("DEPOSIT", transb->data, 0L, 0);