![]() |
![]() |
|
|
Sending Synchronous Messages
The tpcall(3c) function sends a request to a service subroutine and synchronously waits for a reply. Use the following signature to call the tpcall() function.
int
tpcall(char *svc, char *idata, long ilen, char **odata, long *olen, long flags)
The following table describes the arguments to the tpcall() function.
tpcall( ) Function Arguments
tpcall() waits for the expected reply.
Note: Calling the tpcall() function is logically the same as calling the tpacall() function immediately followed by tpgetrply(), as described in Sending Asynchronous Messages.
The request carries the priority set by the system for the specified service (svc) unless a different priority has been explicitly set by a call to the tpsprio() function (described in Setting and Getting Message Priorities).
tpcall() returns an integer. On failure, the value of this integer is -1 and the value of tperrno(5) is set to a value that reflects the type of error that occurred. For information on valid error codes, refer to tpcall(3c) in the BEA Tuxedo C Function Reference.
Note: Communication calls may fail for a variety of reasons, many of which can be corrected at the application level. Possible causes of failure include: application defined errors (TPESVCFAIL), errors in processing return arguments (TPESVCERR), typed buffer errors (TPEITYPE, TPEOTYPE), time-out errors (TPETIME), and protocol errors (TPEPROTO), among others. For a detailed discussion of errors, refer to Managing Errors. For a complete list of possible errors, refer to tpcall(3c) in the BEA Tuxedo C Function Reference.
The BEA Tuxedo system automatically adjusts a buffer used for receiving a message if the received message is too large for the allocated buffer. You should test for whether or not the reply buffers have been resized.
To access the new size of the buffer, use the address returned in the *olen parameter. To determine whether a reply buffer has changed in size, compare the size of the reply buffer before the call to tpcall() with the value of *olen after its return. If *olen is larger than the original size, the buffer has grown. If not, the buffer size has not changed.
You should reference the output buffer by the value returned in odata after the call because the output buffer may change for reasons other than an increase in buffer size. You do not need to verify the size of request buffers because the request data is not adjusted once it has been allocated.
Note: If you use the same buffer for the request and reply message, and the pointer to the reply buffer has changed because the system adjusted the size of the buffer, then the input buffer pointer no longer references a valid address.
Example: Using the Same Buffer for Request and Reply Messages
The following example shows how the client program, audit.c, makes a synchronous call using the same buffer for both the request and reply messages. In this case, using the same buffer is appropriate because the *audv message buffer has been set up to accommodate both request and reply information. The following actions are taken in this code:
Using the Same Buffer for Request and Reply Messages
. . .
/* Create buffer and set data pointer */
audv = (struct aud *)tpalloc("VIEW", "aud", sizeof(struct aud));
/* Prepare aud structure */
audv->b_id = q_branchid;
audv->balance = 0.0;
(void)strcpy(audv->ermsg, "");
/* Do tpcall */
if (tpcall(svc_name,(char *)audv,sizeof(struct aud),
(char **)&audv,(long *)&audrl,0)== -1){
(void)fprintf (stderr, "%s service failed\n %s: %s\n",
svc_name, svc_name, audv->ermsg);
retc = -1;
}
else
(void)printf ("Branch %ld %s balance is $%.2f\n",
audv->b_id, hdr_type, audv->balance);
. . .
Example: Testing for Change in Size of Reply Buffer
The following code provides a generic example of how an application test for a change in buffer size after a call to tpcall(). In this example, the input and output buffers must remain equal in size.
Testing for Change in Size of the Reply Buffer
char *svc, *idata, *odata;
long ilen, olen, bef_len, aft_len;
. . .
if (idata = tpalloc("STRING", NULL, 0) == NULL)
error
if (odata = tpalloc("STRING", NULL, 0) == NULL)
error
place string value into idata buffer
ilen = olen = strlen(idata)+1;
. . .
bef_len = olen;
if (tpcall(svc, idata, ilen, &odata, &olen, flags) == -1)
error
aft_len = olen;
if (aft_len > bef_len){ /* message buffer has grown */
if (idata = tprealloc(idata, olen) == NULL)
error
}
Example: Sending a Synchronous Message with TPSIGRSTRT Set
The following example is based on the TRANSFER service, which is part of the XFER server process of bankapp. (bankapp is a sample application delivered with the BEA Tuxedo system.) The TRANSFER service assumes the role of a client when it calls the WITHDRAWAL and DEPOSIT services. The application sets the communication flag to TPSIGRSTRT in these service calls to give the transaction a better chance of committing. The TPSIGRSTRT flag specifies the action to take if there is a signal interrupt. For more information on communication flags, refer to tpcall(3c) in the BEA Tuxedo C Function Reference.
Sending a Synchronous Message with TPSIGRSTRT Set
/* Do a tpcall to withdraw from first account */
if (tpcall("WITHDRAWAL", (char *)reqfb,0, (char **)&reqfb,
(long *)&reqlen,TPSIGRSTRT) == -1) {
(void)Fchg(transf, STATLIN, 0,
"Cannot withdraw from debit account", (FLDLEN)0);
tpfree((char *)reqfb);
}
...
/* Do a tpcall to deposit to second account */
if (tpcall("DEPOSIT", (char *)reqfb, 0, (char **)&reqfb,
(long *)&reqlen, TPSIGRSTRT) == -1) {
(void)Fchg(transf, STATLIN, 0,
"Cannot deposit into credit account", (FLDLEN)0);
tpfree((char *)reqfb);
}
Example: Sending a Synchronous Message with TPNOTRAN Set
The following example illustrates a communication call that suppresses transaction mode. The call is made to a service that is not affiliated with a resource manager; it would be an error to allow the service to participate in the transaction. The application prints an accounts receivable report, accrcv, generated from information obtained from a database named accounts.
The service routine REPORT interprets the specified parameters and sends the byte stream for the completed report as a reply. The client uses tpcall() to send the byte stream to a service called PRINTER, which, in turn, sends the byte stream to a printer that is conveniently close to the client. The reply is printed. Finally, the PRINTER service notifies the client that the hard copy is ready to be picked up.
Note: The example Sending an Asynchronous Message with TPNOREPLY | TPNOTRAN shows a similar example using an asynchronous message call.
Sending a Synchronous Message with TPNOTRAN Set
#include <stdio.h>
#include "atmi.h"
main()
{
char *rbuf; /* report buffer */
long r1len, r2len, r3len; /* buffer lengths of send, 1st reply,
and 2nd reply buffers for report */
join application
if (rbuf = tpalloc("STRING", NULL, 0) == NULL) /* allocate space for report */
leave application and exit program
(void)strcpy(rbuf,
"REPORT=accrcv DBNAME=accounts"); /* send parms of report */
r1len = strlen(rbuf)+1; /* length of request */
start transaction
if (tpcall("REPORT", rbuf, r1len, &rbuf,
&r2len, 0) == -1) /* get report print stream */
error routine
if (tpcall("PRINTER", rbuf, r2len, &rbuf,
&r3len, TPNOTRAN) == -1) /* send report to printer */
error routine
(void)printf("Report sent to %s printer\n",
rbuf); /* indicate which printer */
terminate transaction
free buffer
leave application
}
Note: In the preceding example, the term error routine indicates that the following tasks are performed: an error message is printed, the transaction is aborted, allocated buffers are freed, the client leaves the application, and the program is exited.
Example: Sending a Synchronous Message with TPNOCHANGE Set
The following example shows how the TPNOCHANGE communication flag is used to enforce strong buffer type checking by indicating that the reply message must be returned in the same type of buffer that was originally allocated. This example refers to a service routine called REPORT. (The REPORT service is also shown in Example: Sending a Synchronous Message with TPNOTRAN Set.)
In this example, the client receives the reply in a VIEW typed buffer called rview1 and prints the elements in printf() statements. The strong type check flag, TPNOCHANGE, forces the reply to be returned in a buffer of type VIEW and of subtype rview1.
A possible reason for this check is to guard against errors that may occur in the REPORT service subroutine, resulting in the use of a reply buffer of an incorrect type. Another reason is to prevent changes that are not made consistently across all areas of dependency. For example, another programmer may have changed the REPORT service to standardize all replies in another VIEW format without modifying the client process to reflect the change.
Sending a Synchronous Message with TPNOCHANGE Set
#include <stdio.h>
#include "atmi.h"
#include "rview1.h"
main(argc, argv)
int argc;
char * argv[];
{
char *rbuf; /* report buffer */
struct rview1 *rrbuf; /* report reply buffer */
long rlen, rrlen; /* buffer lengths of send and reply
buffers for report */
if (tpinit((TPINIT *) tpinfo) == -1)
fprintf(stderr, "%s: failed to join application\n", argv[0]);
if (rbuf = tpalloc("STRING", NULL, 0) == NULL) { /* allocate space for report */
tpterm();
exit(1);
}
/* allocate space for return buffer */
if (rrbuf = (struct rview1 *)tpalloc("VIEW", "rview1", sizeof(struct rview1)) \ == NULL{
tpfree(rbuf);
tpterm();
exit(1);
}
(void)strcpy(rbuf, "REPORT=accrcv DBNAME=accounts FORMAT=rview1");
rlen = strlen(rbuf)+1; /* length of request */
/* get report in rview1 struct */
if (tpcall("REPORT", rbuf, rlen, (char **)&rrbuf, &rrlen, TPNOCHANGE) == -1) {
fprintf(stderr, "accounts receivable report failed in service call\n");
if (tperrno == TPEOTYPE)
fprintf(stderr, "report returned has wrong view type\n");
tpfree(rbuf);
tpfree(rrbuf);
tpterm();
exit(1);
}
(void)printf("Total accounts receivable %6d\n", rrbuf->total);
(void)printf("Largest three outstanding %-20s %6d\n", rrbuf->name1, rrbuf->amt1);
(void)printf("%-20s %6d\n", rrbuf->name2, rrbuf->amt2);
(void)printf("%-20s %6d\n", rrbuf->name3, rrbuf->amt3);
tpfree(rbuf);
tpfree(rrbuf);
tpterm();
}
![]() |
![]() |
![]() |
|
Copyright © 2000 BEA Systems, Inc. All rights reserved.
|