11.21 Handling Errors

Your application logic must test for error conditions for the calls that have return values, and take appropriate action when an error occurs. Specifically, you must:

  • Test to determine whether a -1 or NULL value has been returned (depending on the function call).
  • Invoke code that contains a switch statement that tests for specific values of tperrno(5) and performs the appropriate application logic.

The ATMI supports three functions, tpstrerrordetail(3c), tpstrerror(3c), and Fstrerror, Fstrerror32(3fml), for retrieving the text of an error message from the message catalogs for the Oracle Tuxedo system and FML. The functions return pointers to the appropriate error messages. Your program can use a pointer to direct the referenced text to userlog(3c) or to another destination. For details, refer to tpstrerrordetail(3c) and tpstrerror(3c), and Fstrerror, Fstrerror32(3fml) in the Oracle Tuxedo ATMI FML Function Reference.

The following listing shows a typical method of handling errors. The atmicall() function in this example represents a generic ATMI call. Note the code after the switch statement (line 21): it shows how tpurcode can be used to interpret an application-defined return code.

Listing Handling Errors

001     #include <stdio.h>
002     #include "atmi.h"
003 
004     main()
005 
006     {
007     int rtnval;
008 
009     if (tpinit((TPINIT *) NULL) == -1)
010         error message, exit program;
011     if (tpbegin(30, 0) == -1)
012         error message, tpterm, exit program;
013 
014     allocate any buffers,
015     make atmi calls
016     check return value
017 
018     rtnval = atmicall();
019 
020     if (rtnval == -1) {
021         switch(tperrno) {
022         case TPEINVAL:
023           fprintf(stderr, "Invalid arguments were given to atmicall\n");
024           fprintf(stderr, "e.g., service name was null or flags wrong\n");
025             break;
026     case ...:
027         fprintf(stderr, ". . .");
028         break;
029 
030     Include all error cases described in the atmicall(3) reference 031 
page.
032     Other return codes are not possible, so there should be no 033 default 
within the switch statement.
034 
035     if (tpabort(0) == -1) {
036        char *p;
037        fprintf(stderr, "abort was attempted but failed\n");
038        p = tpstrerror(tperrno);
039        userlog("%s", p);
040     }
041     }
042     else
043     if (tpcommit(0) == -1)
044     fprintf(stderr, "REPORT program failed at commit time\n");
045 
046     The following code fragment shows how an application-specific 
047     return code can be examined.
048     .
049     .
050     .
051     ret = tpcall("servicename", (char*)sendbuf, 0, (char **)&rcvbuf, 
&rcvlen, \
052     (long)0);
053     .
054     .
055     .
056     void) fprintf(stdout, "Returned tpurcode is: %d\n", tpurcode);
057 
058
059     free all buffers
060     tpterm();
061     exit(0);
062     }

The values of tperrno(5) provide details about the nature of each problem and suggest the level at which it can be corrected. If your application defines a list of error conditions specific to your processing, the same can be said for the values of tpurcode.

The following listing shows how to use the tpstrerrordetail(3c) function to obtain additional detail when an error is encountered.

Listing Handling Errors Using tpstrerrordetail( )

001     #include <stdio.h>
002     #include <string.h>
003     #include <atmi.h>/* ORACLE Tuxedo Header File */
004     #define LOOP_ITER 100
005     #if defined(__STDC__) || defined(__cplusplus)
006     main(int argc, char *argv[])
007     #else
008     main(argc, argv)
009     int argc;
010     char *argv[];
011     #endif
012     {
013     char *sendbuf, *rcvbuf;
014     long sendlen, rcvlen;
015     int ret;
016     int i;
017     if(argc != 2) {
018             (void) fprintf(stderr, "Usage: simpcl string\n");
019             exit(1);
020     }
021     /* Attach to ORACLE Tuxedo System as a Client Process */
022     if (tpinit((TPINIT *) NULL) == -1) {
023        (void) fprintf(stderr, "Tpinit failed\n");
024         exit(1);
025     }
026     sendlen = strlen(argv[1]);
027 
028     /* Allocate STRING buffers for the request and the reply */
029 
030     if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
031        (void) fprintf(stderr,"Error allocating send buffer\n");
032        tpterm();
033        exit(1);
034     }
035 
036     if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
037        (void) fprintf(stderr,"Error allocating receive buffer\n");
038        tpfree(sendbuf);
039        tpterm();
040        exit(1);
041     }
042 
043     for( i=0; i<LOOP_ITER; i++) {
044      (void) strcpy(sendbuf, argv[1]);
045 
046     /* Request the service TOUPPER, waiting for a reply */
047     ret = tpcall("TOUPPER", (char *)sendbuf, 0, (char **)&rcvbuf, 
&rcvlen, (long)0);
048 
049     if(ret == -1) {
050           (void) fprintf(stderr, "Can't send request to service
TOUPPER\n");
051           (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, 
tpstrerror(tperrno));
052 
053            ret = tperrordetail(0); 
054            if(ret == -1) {
055                  (void) fprintf(stderr, "tperrodetail() failed!\n");
056                  (void) fprintf(stderr, "Tperrno = %d, %s\n", tperrno, 
tpstrerror(tperrno));
057           }
058           else if (ret != 0) {
059                   (void) fprintf( stderr, "errordetail:%s\n",
060                               tpstrerrordetail( ret, 0));
061           }
062           tpfree(sendbuf);
063           tpfree(rcvbuf);
064           tpterm();
065           exit(1);
066     }
067     (void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);
068    }
069 
070     /* Free Buffers & Detach from System/T */
071     tpfree(sendbuf);
072     tpfree(rcvbuf);
073     tpterm();
074     return(0);
}