Middleware and Three-Tier Client/Server Development

Transaction managers-server-based software that enable the development and management of application programs-are key to the success of distributed processing. Timothy develops a typical three-tier, client/server system, using Tuxedo as the transaction manager and the Oracle Database Server as a resource manager.


November 01, 1996
URL:http://www.drdobbs.com/architecture-and-design/middleware-and-three-tier-clientserver-d/184409992

November 1996: Middleware

Middleware and Three-Tier Client/Server Development

Transaction managers are key to distributed-processing success

Timothy E. Carone

Tim is a manager in the Innovative Computing Group of Andersen Consulting. He can be contacted at Timothy.E [email protected].


Three-tier client/server solutions have been moving from small workgroup environments to large, mission-critical environments that span an entire business enterprise. A key aspect of distributed processing is transaction management, in which a business is broken up into a set of processes, each of which consists of several business events. Events can consist of one or more transactions that can span one or more database- resource managers. Therefore, it is essential that the atomicity, consistency, isolation, and durability properties of transactions-all of which guarantee integrity-be maintained. This maintenance is synergistically achieved by the DBMS, applications, and transaction manager.

As Figure 1 illustrates, the X/Open specification for distributed-transaction processing defines interfaces among transaction participants. The application program's interface to the resource manager is SQL; to the transaction manager, TX; and to other applications, XATMI. Between the resource manager and the transaction manager, the interface specification is XA. As the participants that respond to business events, applications are responsible for the business logic in the transaction. The transaction is a service of the transaction manager, and more than one service may participate in a logical unit of work. The resource manager maintains the state of the different services' respective resources. The transaction manager supervises the cooperation of the resource manager and multiple processes in a single unit of work.

The X/Open specification addresses a formidable area. Because the specifications can be diffuse, it is virtually impossible to satisfy all aspects of the specifications. Consequently, even though many tools claim X/Open compliance, most are not interoperable right out of the box.

Transaction Managers

A transaction manager is server-based software that enables the development and management of application programs. It is the middleware that enhances the three-tier client/server architecture. The transaction manager provides access to services on one or more application servers, manages the commitment and/or rollback of transactions, and the demarcation of the beginning and end of a transaction within an application program. It also acts as a message server for application programs. The transaction manager provides for reliability, availability, and recovery of online transaction-processing (OLTP) applications and supports a scalable architecture.

The use of a transaction manager allows for service-location independence. An application program can request a service without knowing where the service resides; the transaction manager delivers the request to the appropriate application server. When an application program requests a service, it is not necessary that the client know how the service has been implemented. It may be coded in C, Cobol, or even assembler. This independence allows for both development and maintenance flexibility.

A transaction manager provides a level of fault tolerance not found in other computing models. First, it provides an automatic restart/recovery capability. If a transaction manager detects that a server has failed, the TM attempts to restart it. Also, because of the service-location transparency, if a server goes down, clients may be able to reach the services they need on another device providing the same service.

To illustrate the development of a typical three-tier client/server system, I'll use BEA Systems' Tuxedo (originally developed by Bell Labs) as a representative transaction manager, and Oracle Database Server as a resource manager.

Tuxedo Components

Tuxedo is a distributed-transaction monitor that supports the design, configuration, and operation of reliable distributed applications. On the server side, Tuxedo supports more than 35 platforms ranging from Windows NT and UnixWare to Hewlett-Packard HP-UX and IBM MVS. Client-side support includes Windows, MS-DOS, OS/2, Macintosh, and all versions of UNIX. Tuxedo supports any RDBMS, OODBMS, file manager, or queue manager.

Tuxedo is composed of a number of integrated components. The two I'll examine in this article are System /T and System /WS. The Tuxedo API is a C/C++ or Cobol callable library referred to as the Application-to-Transaction Manager Interface (ATMI). It is a superset of the X/Open XATMI and TX interfaces.

Tuxedo System /T provides the basic client/server architecture, request/response and conversational communications interfaces, transaction support, and application administration for a distributed application. System /T guarantees the integrity of the data accessed across several sites whether or not they are using the same resource manager. It manages the transactions involving multiple data stores, tracks transaction participants, and supervises the two-phase commit protocol, thereby ensuring that transaction commit and rollback are properly handled for each data store.

Tuxedo System /WS extends the client-side capability to PCs or workstations that are part of the first tier of the three-tier client/server model. System /WS Client allows applications developed in UNIX, Windows 3.11, and Windows NT to use the ATMI for access to services and transaction management.

Figure 2 shows how the Tuxedo components integrate into the three-tier client/server model architecture. A number of applications executing on a client contain the Tuxedo-supplied ATMI library. This library contains functions for both the XATMI and TX interfaces. When the client application issues a request to join the Tuxedo application, the request is picked up by the /WS Listener process on the application server. The /WS Handler manages the server's connections to the application. The /WS Listener is also responsible for the distribution of connections to the /WS Handlers, and starts new /WS Handlers as necessary.

The client joins Tuxedo by issuing a tpinit(), and communicates with the Tuxedo services using either request/reply or conversational mode. Transactions in the client are demarcated with tpbegin() and either tpcommit() (which performs the two-phase commit) or tpabort() (which performs a rollback). When the /WS Handler receives a service request from a client application, the handler sends a request to the Tuxedo Bulletin Board. The Tuxedo Bulletin Board is a collection of data structures containing information about servers, services, clients, and Tuxedo configuration maintained by the Bulletin Board Liaison (BBL) process. Once the server providing the requested service is identified, the request is put into its message queue.

A Tuxedo application server contains one or more services and is single threaded. It consists of a Tuxedo-provided main() function, initialization and termination functions (tpsvrinit() and tpsvrdone()), as well as the service functions containing the business logic. When a server is started, it advertises its services to the BBL, calls tpsvrinit() and enters into a loop. Requests are retrieved from the queue and dispatched to the service. Upon process completion, a reply is sent back to the client application. When the server receives a termination request, it calls tpsvrdone() and terminates.

The Tuxedo application server communicates with the Oracle database via embedded SQL. Transaction management is performed via the Transaction Manager Server (TMS_Oracle), a Tuxedo-provided server that communicates with Oracle via XA (the TMS is linked with XA libraries provided by Oracle). Therefore, all commands to open and close the database and to begin, commit, or abort transactions are routed via TMS_Oracle. In case of a global transaction (one involving multiple resource managers), the responsibility of the TMS_Oracle is to execute a two-phase commit protocol to manage the updates across all resource managers.

The Satellite Application

To show how you can use Tuxedo, I'll describe the development of a program called "Satellite" that selects information on the orbit of a satellite from an Oracle database. The database was populated using the NORAD two-line orbital element set (published regularly at sci.space.news). Given a future date, the program can calculate where the satellite will be on that day and update the database. To plot the precise position of a satellite over time, you must keep running the program over and over, because the NORAD orbital elements are continually updated. The calculation is done using the program spacetrk.for found in the pub/space directory at archive.afit.af.mil. (Documentation is found in the LaTeX document spacetrk.doc.)

Listing One is sat.h, which contains the Satellite client that begins by first joining Tuxedo. We want to update the position of the Extreme Ultraviolet Explorer (EUVE) astronomical satellite. Satellite invokes the Tuxedo service GetTheSatellite(), which retrieves all information on EUVE from the Oracle database. The client then invokes the Tuxedo service CalcNewSatellitePosition() (the future date chosen is May 8, 1997). This service returns the new information to the client, which invokes UpdateSatellitePosition(), which updates the database. The three calls to Tuxedo are parts of one transaction, demarcated by tpbegin() and tpabort()/tpcommit().

Before a Tuxedo service can be invoked, a buffer must be allocated for both the input and output data associated with the service. All buffers in Satellite use Tuxedo VIEW buffers. The buffer is created as an ASCII file and contains the view name and a description of each buffer element. The view name is the name of the view description and must be a valid C identifier. The description of each buffer element includes the data type, the name of the element (which must also be a valid C identifier), the number of elements to be allocated, a flag denoting an option list, the size of each element (if it is a string), and the user-defined null value; the "-" indicates the default Tuxedo value. Figure 3 is the view file for Satellite. This file is compiled using the Tuxedo-supplied viewc compiler. The output from this compilation is given at the top of sat.h. They are C structures for use by the example application.

The Tuxedo services I discuss in this article have been split into two parts. The first part is the actual Tuxedo service, but its only function is to extract the contents of the Tuxedo input buffer into a C structure. The C structure is then passed to a function that contains the embedded SQL. After the function returns, the service inserts the results of the query into the output buffer and performs a tpreturn(). tpreturn() and tpforward() are the only ways to exit a service. tpreturn() returns the result to the client and tpforward() forwards the result to another service. The arguments to tpreturn() include the return value as defined by Tuxedo, an application-defined return code, the output buffer, its length, and the value zero. Tuxedo has reserved the last argument for future use as a set of flags; to date, only the zero value can be used.

There are several rationales for splitting the service in this manner. First, it allows architectural components such as security exits, fault tolerance, or performance hooks to be inserted independent of the business logic. Also, even though Tuxedo services can use tpcall() to invoke other services, this is usually bad practice for mission-critical systems. There is substantial overhead involved in a Tuxedo service call. Therefore, by isolating the business logic in a function, a Tuxedo service can invoke another service's business logic using a function call instead of a service call. This approach also makes it easier for you to use other buffer types, such as FML buffers, if the need arises, and only change the extraction and insertion code-not the business logic.

The file sat_svcs.c (available electronically) contains the three Tuxedo services. Every Tuxedo service has one argument, namely the pointer rqst, which has the data type TPSVCINFO. This Tuxedo-supplied data type contains the data passed to the service and other information, such as the length of the data sent by the client and user-defined security information. Next, the service defines pointers pGTS_IN and pGTS_OUT, which hold rqst->data before and after processing. It can be argued that these pointers are superfluous, as they could be replaced by rqst. However, the information passed to the service-logic function is commonly a subset of that needed by the entire service (security information, for example). In addition, it is not uncommon for rqst to contain information for more than one function call. Subsequent function calls may use part of rqst and part of the information returned from the previous function call(s). Therefore, it is useful to have structures for use internally by the service and keep rqst as the pointer to the TPSVCINFO structure.

Next, the service calls the function iGetTheSatellite(pGTS_IN, pGTS_OUT), which carries out the business logic. In this case, iGetTheSatellite(pGTS_IN, pGTS_OUT) is a C program with embedded SQL. This file must be precompiled by Oracle Pro*C/C++ into C. This function selects the 13 orbital parameters needed from the database to update the position of EUVE. If the query fails for some reason (for instance, the database connection was lost), Oracle will set SQLSTATE to a value other than "00000." This will result in the service returning a TPFAIL to the client. Upon receipt of a TPFAIL (=-1), the client has no alternative but to rollback the transaction.

If the query was successful, the service allocates an output buffer pointed to by psvc_GTS. If the allocation fails, the service again returns a TPFAIL to the client. Otherwise, it returns the query set to the client and returns a TPSUCCESS.

The function iCalcNewSatellitePosition(pGTS_IN, pGTS_OUT) is a C wrapper around spacetrk.for. The function takes the orbital parameters from the client and passes them to the spacetrk.for Fortran program, which returns the new position of the satellite. iGetTheSatellite(pGTS_IN, pGTS_OUT) then returns the position of EUVE in terms of its three new spatial coordinates (xpos, ypos, and zpos) and velocity coordinates (xvel, yvel, and zvel). (This functionality is not included in the code listings, nor are the definitions of the orbital parameters. Contact me if you are interested, but please try to work it out yourself using spacetrk.doc and spacetrk.for first.) The function iUpdateSatellitePosition(pGTS_IN, pGTS_OUT), takes the new position of EUVE and updates the database.

You can collapse all this functionality into one service (which is what should be done in a mission-critical system). In fact, a number of alternatives are probably evident to you. Remember that there is no one way to design a system involving transaction services.

It is intentional that the three services look similar. Mission-critical systems will have hundreds or more Tuxedo services. This is a significant amount of code to write. Separating the extraction/insertion of data from the functions allows the extraction/insertion to be generated automatically for each service. Much error processing has been left out, as it is possible to completely generate the services and partially generate the functions. Maintenance and tuning are major issues for mission-critical systems, so this approach is one way of accommodating these activities.

Conclusion

If the system you are developing is your first encounter with a transaction manager, start off with a pilot project to build your skill. There are many aspects of transaction managers (such as failover) that I haven't addressed here. Mission-critical three-tier client/server systems usually are required to be available more than 95 percent of the time. This is difficult to do even with existing tools that have failover built into them. This availability requires not only transaction-manager reliability but resource-manager and application-program reliability. A significant amount of prototyping has to be done in order to determine the best approach for high availability for the system being considered.

Performance should be taken into account. It is easy to have a great design for a system using a transaction manager and have Z/80-like performance. Stay away from having services call other services-the overhead is too great. Also stay away from global transactions; design the system so that a transaction is contained in one service. Remember that Tuxedo servers are single threaded, so if you must have services calling services, they cannot be in the same server. Performance is dependent on the configuration and packing of the servers as well as on software design.

Middleware like Tuxedo and similar tools is important for client/server systems. But unless skill sets are built internally before building the mission-critical system, major redesign and rework will be common. Finally, Carl Hall's Building Client/Server Applications Using Tuxedo (John Wiley & Sons, 1996) is a must-have book for anyone doing Tuxedo-based development.

Figure 1: The X/Open distributed processing model.

Figure 2: Conceptual model for Tuxedo.

Figure 3: View file for the Satellite program.

VIEW SVC_GTS_IN
# type cname            fbname     count     flag     size     null
char NameOfSatellite     -         1         -        32       -
END
#
VIEW SVC_GTS_OUT
# type cname             fbname   count    flag     size     null
double p1                -        1        -        -        -
double p2                -        1        -        -        -
double p3                -        1        -        -        -
double p4                -        1        -        -        -
double p5                -        1        -        -        -
double p6                -        1        -        -        -
double p7                -        1        -        -        -
double p8                -        1        -        -        -
double p9                -        1        -        -        -
double p10               -        1        -        -        -
double p11               -        1        -        -        -
double p12               -        1        -        -        -
double p13               -        1        -        -        -
END
#
VIEW SVC_CNSP_IN
# type cname             fbname   count    flag     size     null
double p1                -        1        -        -        -
double p2                -        1        -        -        -
double p3                -        1        -        -        -
double p4                -        1        -        -        -
double p5                -        1        -        -        -
double p6                -        1        -        -        -
double p7                -        1        -        -        -
double p8                -        1        -        -        -
double p9                -        1        -        -        -
double p10               -        1        -        -        -
double p11               -        1        -        -        -
double p12               -        1        -        -        -
double p13               -        1        -        -        -
char NewTimeAndDate      -        1        -        32
END
#
VIEW SVC_CNSP_OUT   
# type cname             fbname   count    flag     size     null
double xpos              -        1        -        -        -
double ypos              -        1        -        -        -
double zpos              -        1        -        -        -
double xvel              -        1        -        -        -
double yvel              -        1        -        -        -
double zvel              -        1        -        -        -
END
#
VIEW SVC_USP_IN
# type cname             fbname   count    flag     size     null
double xpos              -        1        -        -        -
double ypos              -        1        -        -        -
double zpos              -        1        -        -        -
double xvel              -        1        -        -        -
double yvel              -        1        -        -        -
double zvel              -        1        -        -        -
char NewTimeAndDate      -        1        -        32
END
#
VIEW SVC_USP_OUT
char TheResult  -        1        -        256      -
END

For More Information

BEA Systems

385 Moffett Park Drive

Sunnyvale, CA 94089-1208

408-743-4000

http://www.beasys.com

Listing One

/* File: sat.h -- Include file for satellite program -- T.E. Carone */
/* Define the TUXEDO error code used to determine if a particular TUXEDO
function call failed.  If so, a transaction rollback occurs. */
#define     TUXEDO_ERROR        -1

/* Flags for TUXEDO service calls. Most TUXEDO functions have reserved FLAGS
argument for future use.  Therefore, they are not used here. */
#define     SAT_TUXEDO_FLAGS    0L
#define     SAT_SUCCESS          0   
#define     SAT_FAIL            -1

/* Structures for use in the marshaling functions. They are used to transfer 
information to the service logic function and then back to the client. */
struct GTS_IN{
    char    NameOfSatellite[32];
};
struct GTS_OUT{
    double  p1; 
    double  p2; 
    double  p3; 
    double  p4; 
    double  p5; 
    double  p6; 
    double  p7; 
    double  p8; 
    double  p9; 
    double  p10;    
    double  p11;    
    double  p12;    
    double  p13;    
};
struct CNSP_IN{
    double  p1; 
    double  p2; 
    double  p3; 
    double  p4; 
    double  p5; 
    double  p6; 
    double  p7; 
    double  p8; 
    double  p9; 
    double  p10;    
    double  p11;    
    double  p12;    
    double  p13;    
    char    NewTimeAndDate[32];
};
struct CNSP_OUT{
    double  xpos;
    double  ypos;
    double  zpos;
    double  xvel;   
    double  yvel;   
    double  zvel;   
};
struct USP_IN{
    double  xpos;
    double  ypos;
    double  zpos;
    double  xvel;   
    double  yvel;   
    double  zvel;   
    char    NewTimeAndDate[32];
};
struct USP_OUT{
    char    TheResult[256];
};
/* Output from the viewc32 compiler. It took the file sat_TUXEDO_VIEWS.v file 
and produced this file which is then included in the source code files. */
/* The input and output buffers for GetTheSatellite. The p1 - p13 structure 
elements are the 13 elements that make up the NORAD general perturbation 
elements. Their precise definition can be found in pub/space/spacetrk.doc 
(a LaTeX file) at archive.afit.af.mil. */
struct SVC_GTS_IN {
    char    NameOfSatellite[32];
};
struct SVC_GTS_OUT {
    double  p1; 
    double  p2; 
    double  p3; 
    double  p4; 
    double  p5; 
    double  p6; 
    double  p7; 
    double  p8; 
    double  p9; 
    double  p10;    
    double  p11;    
    double  p12;    
    double  p13;    
};
/* Input and output buffers for CalcNewSatellitePosition. Output buffer 
contains the new three positional coordinates for the satellite and new 
three velocity coordinates for the satellite. */
struct SVC_CNSP_IN {
    double  p1; 
    double  p2; 
    double  p3; 
    double  p4; 
    double  p5; 
    double  p6; 
    double  p7; 
    double  p8; 
    double  p9; 
    double  p10;    
    double  p11;    
    double  p12;    
    double  p13;    
    char    NewTimeAndDate[32];
};
struct SVC_CNSP_OUT {
    double  xpos;
    double  ypos;
    double  zpos;
    double  xvel;   
    double  yvel;   
    double  zvel;   
};
/* Input and output buffers for UpdateSatellitePosition. */
struct SVC_USP_IN {
    double  xpos;
    double  ypos;
    double  zpos;
    double  xvel;   
    double  yvel;   
    double  zvel;   
    char    NewTimeAndDate[32];
};
struct SVC_USP_OUT {
    char    TheResult[256];
};

/* sat_client.c -- Shows a simple use of Tuxedo. A client program performs
a simple transaction.  The client needs to estimate the future position of the 
Extreme Ultraviolet Explorer (EUVE) astronomical satellite using the general 
orbital perturbation element sets generated and maintained by the NORAD. This 
information has been stored in an Oracle database. This is the client program 
that will use Tuxedo to manage the transaction and return information from the 
Oracle database. The client performs the following steps:
1.  Joins Tuxedo using tpinit().
2.  Starts a transaction using tpbegin().
3.  Calls the GetTheSatellite Tuxedo service to get the information on the 
EUVE satellite that is contained in the Oracle database.
4.  Calls the CalcNewSatellitePosition Tuxedo service to calculate the future 
position of the EUVE satellite given the NORAD information.
5.  Calls the UpdateSatellitePosition Tuxedo service to update the position of 
the EUVE satellite at a future time.  This information is also contained in 
the database.
6.  Commits the transaction using tpcommit() if all Tuxedo services executed 
properly or it issues a tpabort() to rollback the transaction.
7.  Disconnects from Tuxedo using tpterm().
This example shows the request/reply mode of communication.
Uses the NORAD two-line general orbital perturbation element sets. Information 
is posted regularly to sci.space.news and to rec.radio.amateur.space. */

#include <stdio.h>
/* Client header file. */
#include <sat.h>

/* atmi.h is the TUXEDO-supplied include file. */
#include <atmi.h>

#define USER_NAME       "Carone"
#define PASSWORD        "EUVE"
 
int main()
{
/* Declare input and output buffer names for each of the three services. These 
will point to the buffers defined in sat_TUXEDO_VIEWS.v and sat_TUXEDO_VIEWS.h.
GTS refers to the GetTheSatellite TUXEDO service, CNSP refers to the 
CalcNewSatellitePosition TUXEDO service, and USP refers to the 
UpdateSatellitePosition TUXEDO service. */

struct  SVC_GTS_IN  *svc_GTS_inbuf;
struct  SVC_GTS_OUT *svc_GTS_outbuf; 
struct  SVC_CNSP_IN *svc_CNSP_inbuf;
struct  SVC_CNSP_OUT    *svc_CNSP_outbuf; 
struct  SVC_USP_IN  *svc_USP_inbuf;
struct  SVC_USP_OUT *svc_USP_outbuf; 

/* Declare return code variable that is assigned the return code from TUXEDO 
service invocations. */
int     iRetCode;
 
/* Declare the variable that will contain the length of the output buffer that
is returned from TUXEDO service invocations. */
long    lRetLen;
 
/* Connect to TUXEDO using tpinit().  If the connection is successful then 
allocate the TUXEDO buffers (both the buffer sent to the service with the name
of the satellite and the buffer that returns the satellite information from 
the service) for the first service, GetTheSatellite. */
iRetCode = tpinit(NULL);
if (iRetCode != TUXEDO_ERROR){

/* Allocate the buffers using tpalloc(). */
    svc_GTS_inbuf = (struct SVC_GTS_IN *) tpalloc("VIEW", "GTS_IN", 
            sizeof(struct SVC_GTS_IN)); 
    svc_GTS_outbuf = (struct SVC_GTS_OUT *) tpalloc("VIEW", "GTS_OUT",
            sizeof(struct SVC_GTS_OUT));
    svc_CNSP_inbuf = (struct SVC_CNSP_IN *) tpalloc("VIEW", "CNSP_IN", 
            sizeof(struct SVC_CNSP_IN)); 
    svc_CNSP_outbuf = (struct SVC_CNSP_OUT *) tpalloc("VIEW", "CNSP_OUT",
            sizeof(struct SVC_CNSP_OUT));
    svc_USP_inbuf = (struct SVC_USP_IN *) tpalloc("VIEW", "USP_IN", 
            sizeof(struct SVC_USP_IN)); 
    svc_USP_outbuf = (struct SVC_USP_OUT *) tpalloc("VIEW", "USP_OUT",
            sizeof(struct SVC_USP_OUT));

/* Fill the GetTheSatellite TUXEDO service input buffer with the name of the
satellite that is to be retrieved from the Oracle database. */
    strcpy(svc_GTS_inbuf->NameOfSatellite, "EUVE");
 
/* Begin transaction using tpbegin(). The 60 sets the transaction timeout to 
60 seconds. */
        iRetCode = tpbegin(60, SAT_TUXEDO_FLAGS);
        if (iRetCode != TUXEDO_ERROR){

/* Invoke the GetTheSatellite TUXEDO service using tpcall(). This is a 
synchronous call; therefore the client must wait until TUXEDO returns control.
It is necessary to recast the pointers to the input and output buffers. */
        iRetCode = tpcall("GetTheSatellite", (char *)svc_GTS_inbuf, 
                   sizeof(struct SVC_GTS_IN), (char **)&svc_GTS_outbuf, 
                   &lRetLen, SAT_TUXEDO_FLAGS);
        if (iRetCode != TUXEDO_ERROR){

/* Copy the contents of the svc_GTS_outbuf TUXEDO buffer to the svc_CNSP_inbuf
buffer and invoke the CalcNewSatellitePosition TUXEDO service. */
            svc_CNSP_inbuf = (struct SVC_CNSP_IN *) svc_GTS_outbuf;
            strcpy(svc_CNSP_inbuf->NewTimeAndDate, "5/8/1997");
            iRetCode = tpcall("CalcNewSatellitePosition",
                    (char *)svc_CNSP_inbuf, sizeof(struct SVC_CNSP_IN),
                    (char **)&svc_CNSP_outbuf, &lRetLen,
                    SAT_TUXEDO_FLAGS);
            if (iRetCode != TUXEDO_ERROR){
/* Copy the contents of the svc_CNSP_outbuf TUXEDO buffer to the svc_USP_inbuf
buffer and invoke the UpdateSatellitePosition TUXEDO service. */
         svc_USP_inbuf = (struct SVC_USP_IN *) svc_CNSP_outbuf;
         strcpy(svc_USP_inbuf->NewTimeAndDate, svc_CNSP_inbuf->NewTimeAndDate);

         iRetCode = tpcall("UpdateSatellitePosition",
                    (char *)svc_USP_inbuf, sizeof(struct SVC_USP_IN),
                    (char **)&svc_USP_outbuf, &lRetLen,
                    SAT_TUXEDO_FLAGS);
/* If the UpdateSatellitePosition was successful then commit the transaction.
Otherwise, rollback the transaction. */
            if (iRetCode != TUXEDO_ERROR)
                tpcommit(SAT_TUXEDO_FLAGS);
            else
                tpabort(SAT_TUXEDO_FLAGS);
            }
/* If the GetSatellitePosition or the CalcNewSatellitePosition TUXEDO services
failed then rollback the transaction. */
        else
            tpabort(SAT_TUXEDO_FLAGS);
        }
    else
        tpabort(SAT_TUXEDO_FLAGS);
    }
/* Free the allocated buffers and disconnect from TUXEDO using tpterm(). */
        tpfree((char *) svc_GTS_inbuf);
        tpfree((char *) svc_GTS_outbuf);
        tpfree((char *) svc_CNSP_inbuf);
        tpfree((char *) svc_CNSP_outbuf);
        tpfree((char *) svc_USP_inbuf);
        tpfree((char *) svc_USP_inbuf);
        iRetCode = tpterm();
    }
return;

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.