Table of Contents Previous Next PDF


Building RPC Client and Server Programs

Building RPC Client and Server Programs
This topic includes the following sections:
Prerequisite Knowledge
The TxRPC programmer should be familiar with the C compilation system and building Oracle Tuxedo ATMI clients and servers. Information on building Oracle Tuxedo ATMI clients and servers is provided in the Programming an Oracle Tuxedo Application Using C, Programming an Oracle Tuxedo Application Using COBOL, and Programming an Oracle Tuxedo Application Using FM. Building Workstation clients is provided in Using the Oracle Tuxedo Workstation Component.
Building an RPC Server
RPC servers are built and configured in much that same way that ATMI Request/Response servers are. In fact, the service name space for RPC and Request/Response servers is the same. However, the names advertised for RPC services are different. For Request/Response servers, a service name is mapped to a procedure. For RPC servers, a service name is mapped to an IDL interface name. The RPC service advertised will be <interface>v<major>_<minor>, where <interface> is the interface name, and <major> and <minor> are the major and minor numbers of the version, as specified (or defaulted to 0.0) in the interface definition. Because the service name is limited to 127 characters, this limits the length of the interface name to 13 characters minus the number of digits in the major and minor version numbers. This also implies that an exact match is used on major AND minor version numbers because of the way name serving is done in the Oracle Tuxedo system. Note that the interface, and not individual operations, are advertised (similar to DCE/RPC). The server stub automatically takes care of calling the correct operation within the interface.
RPC servers are built using the buildserver(1) command. We recommend using the -s option to specify the service (interface) names at compilation time. The server can then be booted using the -A option to get the services automatically advertised. This approach is used in the sample application, as shown in Appendix , A Sample Application
The buildserver(1) command automatically links in the Oracle Tuxedo libraries. However, the RPC run time must be linked in explicitly. This is done by specifying the -f -ltrpc option after any application files on the buildserver line. Normally, the output of the tidl(1) command is a server stub object file. This can be passed directly to the buildserver command. Note that the server stub and the application source, object, and library files implementing the operations should be specified ahead of the run-time library, also using the -f option. See the makefile rpcsimp.mk, in Appendix , A Sample Application for an example.
Building an RPC Client
A native RPC client is built using the buildclient(1) command. This command automatically links in the Oracle Tuxedo libraries. However, the RPC run time must be linked in explicitly. This is done by specifying the -f -ltrpc option after any application files on the buildclient command line. Generally, the output of the tidl(1) command is a client stub object file. This can be passed directly to the buildclient command. Note that the client stub and the application source, object, and library files executing the remote procedure calls should be specified ahead of the run-time library, also using the -f option. For an example, see the makefile rpcsimp.mk in Appendix , A Sample Application
To build a UNIX Workstation client, simply add the -w option to the buildclient(1) command line so that the Workstation libraries are linked in instead of the native libraries.
Building a Windows Workstation RPC Client
Compilation of the client stub for Windows requires the -D_TM_WIN definition as a compilation option. This ensures that the correct function prototypes for the TxRPC and Oracle Tuxedo ATMI run time functions are used. While the client stub source is the same, it must be compiled specially to handle the fact that the text and data segments for the DLL will be different from the code calling it. The header file and stub are automatically generated to allow for the declarations to be changed easily, using C preprocessor definitions. The definition _TMF (for “far”) appears before all pointers in the header file and _TMF is automatically defined as “_far” if _TM_WIN is defined.
In most cases, using standard libraries, the buildclient(1) command can be used to link the client. The library to be used is wtrpc.lib.
The sample also shows how to create a Dynamic Link Library (DLL) using the client stub. This usage will be very popular when used with a visual application builder that requires DLL use (where the application code cannot be statically linked in). Windows functions are traditionally declared to have the _pascal calling convention. The header file and stub are automatically generated to allow for the declarations to be changed easily, using C preprocessor definitions. _TMX (for “eXport”) appears before all declared functions. By default, this definition is defined to nothing. When compiling a stub for inclusion in a DLL, _TMX should be defined to _far _pascal. Also, the files to be included in the DLL must be compiled with the large memory model. Because using _pascal automatically converts the function names to uppercase in the library, it is a good idea to run with the -port case option turned on, which does additional validation to see if two declared names differ only in case.
A complete example of building a Windows DLL is shown in Appendix A, A Sample Application
Note:
A compilation error may occur if a TxRPC client includes windows.h, due to a duplicate uuid_t definition. It will be necessary for the application to either not include windows.h (because it is included already) or to include it within a different file in the application.
Using C++
Clients and servers can be built using C or C++, interchangeably. The header files and generated stub source files are defined in such a way that all Stub Support functions and generated operations allow for complete interoperability between C++ and C. They are declared with C linkage, that is, as extern “C,” so that name mangling is turned off.
The stub object files can be built using C++ by specifying CC -c for the -cc_cmd option of tidl(1). The CC command can be used to compile and link client and server programs by setting and exporting the CC environment variable before running buildclient(1) and buildserver(1). For example:
tidl -cc_cmd “CC -c” -keep all t.idl
CC=CC buildserver -o server -s tv1_0 -f “-I. t_sstub.o server.c -ltrpc”
In the Windows environment, C++ compilation is normally accomplished via a flag on the compilation command line or a configuration option rather than a different command name. Use the appropriate options to get C++ compilation.
Interoperating with DCE/RPC
The Oracle Tuxedo TxRPC compiler uses the same IDL interface as OSF/DCE but the generated stubs do not use the same protocol. Thus, an Oracle Tuxedo TxRPC stub cannot directly communicate with a stub generated by the DCE IDL compiler.
However, it is possible to have the following interoperations between DCE/RPC and Oracle Tuxedo TxRPC:
The following sections show possible interactions between Oracle Tuxedo TxRPC and OSF/DCE. In each case, the originator of the request is called the requester. This term is used instead of “client” because the requester could, in fact, be a DCE or Oracle Tuxedo ATMI service making a request of another service. The terms “client” and “server” refer to the client and server stubs generated by the IDL compilers (either DCE idl(1) or Oracle Tuxedo tidl(1)); these terms are used for consistency with the DCE and TxRPC terminology. Finally, the term “application service” is used for the application code that implements the procedure that is being called remotely (it is generally transparent whether the invoking software is the server stub generated by DCE or Oracle Tuxedo).
Oracle Tuxedo Requester to DCE Service via Oracle Tuxedo Gateway
Figure 4‑1 Oracle Tuxedo Requester to DCE Service via Oracle Tuxedo Gateway
The first approach uses a “gateway” such that the Oracle Tuxedo ATMI client stub invokes an Oracle Tuxedo ATMI server stub, via TxRPC, that has a DCE client stub linked in (instead of the application services) that invokes the DCE services, via DCE RPC. The advantage to this approach is that it is not necessary to have DCE on the client platform. In fact, the set of machines running Oracle Tuxedo and the set of machines running DCE could be disjoint except for one machine where all such gateways are running. This also provides a migration path with the ability to move services between Oracle Tuxedo and DCE. A sample application that implements this approach is described in Appendix B, A DCE-Gateway Application
In this configuration, the requester is built as a normal Oracle Tuxedo ATMI client or server. Similarly, the server is built as a normal DCE server. The additional step is to build the gateway process which acts as an Oracle Tuxedo ATMI server using a TxRPC server stub and a DCE client using a DCE/RPC client stub.
The process of running the two IDL compilers and linking the resultant files is simplified with the use of the blds_dce(1) command, which builds an Oracle Tuxedo ATMI server with DCE linked in.
The usage for blds_dce is as follows:
blds_dce [-o output_file] [-i idl_options] [-f firstfiles] [-l lastfile] \
[idl_file . . . ]
The command takes as input one or more IDL files so that the gateway can handle one or more interfaces. For each one of these files, tidl is run to generate a server stub and idl is run to generate a client stub.
This command knows about various DCE environments and provides the necessary compilation flags and DCE libraries for compilation and linking. If you are developing in a new environment, it may be necessary to modify the command to add the options and libraries for your environment.
This command compiles the source files in such a way (with -DTMDCEGW defined) that memory allocation is always done using rpc_ss_allocate(3c) and rpc_ss_free(3c), as described in the Oracle Tuxedo C Function Reference. This ensures that memory is freed on return from the Oracle Tuxedo ATMI server. The use of -DTMDCEGW also includes DCE header files instead of Oracle Tuxedo TxRPC header files.
The IDL output object files are compiled, optionally with specified application files (using the -f and -l options), to generate an Oracle Tuxedo ATMI server using buildserver(1). The name of the executable server can be specified with the -o option.
When running this configuration, the DCE server would be started first in the background, then the Oracle Tuxedo configuration including the DCE gateway would be booted, and then the requester would be run. Note that the DCE gateway is single-threaded so you will need to configure and boot as many gateway servers as you want concurrently executing services.
There are several optional things to consider when building this gateway.
Setting the DCE Login Context
First, as a DCE client, it is normal that the process runs as some DCE principal. There are two approaches to getting a login context. One approach is to “log in” to DCE. In some environments, this occurs simply by virtue of logging into the operating system. In many environments, it requires running dce_login. If the Oracle Tuxedo ATMI server is booted on the local machine, then it is possible to run dce_login, then run tmboot(1) and the booted server will inherit the login context. If the server is to be booted on a remote machine which is done indirectly via tlisten(1), it is necessary to run dce_login before starting tlisten. In each of these cases, all servers booted in the session will be run by the same principal. The other drawback to this approach is that the credentials will eventually expire.
The other alternative is to have the process set up and maintain its own login context. The tpsvrinit(3c) function provided for the server can set up the context and then start a thread that will refresh the login context before it expires. Sample code to do this is provided in $TUXDIR/lib/dceserver.c; it must be compiled with the -DTPSVRINIT option to generate a simple tpsvrinit() function. (It can also be used as the main() for a DCE server, as described in the following section.) This code is described in further detail in Appendix B, A DCE-Gateway Application
Using DCE Binding Handles
Oracle Tuxedo TxRPC does not support binding handles. When sending an RPC from the requester’s client stub to the server stub within the gateway, the Oracle Tuxedo system handles all of the name resolution and choosing the server, doing load balancing between available servers. However, when going from the gateway to the DCE server, it is possible to use DCE binding. If this is done, it is recommended that two versions of the IDL file be used in the same directory or that two different directories be used to build the requester, and the gateway and server. The former approach of using two different filenames is shown in the example with the IDL file linked to a second name. In the initial IDL file, no binding handles or binding attributes are specified. With the second IDL file, which is used to generate the gateway and DCE server, there is an associated ACF file that specifies [explicit_handle] such that a binding handle is inserted as the first parameter of the operation. From the Oracle Tuxedo server stub in the gateway, a NULL handle will be generated (because handles aren’t supported). That means that somewhere between the Oracle Tuxedo ATMI server stub and the DCE client stub in the gateway, a valid binding handle must be generated.
This can be done by making use of the manager entry point vector. By default, the IDL compiler defines a structure with a function pointer prototype for each operation in the interface, and defines and initializes a structure variable with default function names based on the operation names. The structure is defined as:
<INTERF>_v<major>_<minor>_epv_t<INTERF>_v<major>_<minor>_s_epv
where <INTERF> is the interface name and <major>_<minor> is the interface version. This variable is dereferenced when calling the server stub functions. The IDL compiler option, -no_mepv, inhibits the definition and initialization of this variable, allowing the application to provide it in cases where there is a conflict or difference in function names and operation names. In the case where an application wants to provide explicit or implicit binding instead of automatic binding, the -no_mepv option can be specified, and the application can provide a structure definition that points to functions taking the same parameters as the operations but different (or static) names. The functions can then create a valid binding handle that is passed, either explicitly or implicitly, to the DCE/RPC client stub functions (using the actual operation names).
This is shown in the example in Appendix B, A DCE-Gateway Application The file dcebind.c generates the binding handle, and the entry point vector and associated functions are shown in dceepv.c.
Note that to specify the -no_mepv option when using the blds_dce, the -i -no_mepv option must be specified so that the option is passed through to the IDL compiler. This is shown in the makefile, rpcsimp.mk, in Appendix B, A DCE-Gateway Application
Authenticated RPC
Now that we have a login context and a handle, it is possible to use authenticated RPC calls. As part of setting up the binding handle, it is also possible to annotate the binding handle for authentication by calling rpc_binding_set_auth_info(), as described in the Oracle Tuxedo C Function Reference. This is shown as part of generating the binding handle in dcebind.c in Appendix B, A DCE-Gateway Application This sets up the authentication (and potentially encryption) between the gateway and the DCE server. If the requester is an Oracle Tuxedo ATMI server, then it is guaranteed to be running as the Oracle Tuxedo administrator. For more information about authentication for Oracle Tuxedo clients, see Administering the Oracle Tuxedo System.
Transactions
OSF/DCE does not support transactions. That means that if the gateway is running in a group with a resource manager and the RPC comes into the Oracle Tuxedo ATMI client stub in transaction mode, the transaction will not carray to the DCE server. There is not much you can do to solve this; just be aware of it.
DCE Requester to Oracle Tuxedo Service Using Oracle Tuxedo Gateway
Figure 4‑2 DCE Requester to Oracle Tuxedo Service Using Oracle Tuxedo Gateway
In the preceding figure, the DCE requester uses a DCE client stub to invoke a DCE service which calls the Oracle Tuxedo ATMI client stub (instead of the application services), which invokes the Oracle Tuxedo ATMI service (via TxRPC). Note that in this configuration, the client has complete control over the DCE binding and authentication. The fact that the application programmer builds the middle server means that the application also controls the binding of the DCE server to Oracle Tuxedo ATMI service. This approach would be used in the case where the DCE requester does not want to directly link in and call the Oracle Tuxedo system.
The main() for the DCE server should be based on the code provided in $TUXDIR/lib/dceserver.c. If you already have your own template for the main() of a DCE server, there are a few things that may need to be added or modified.
First, tpinit(3c) should be called to join the ATMI application. If application security is configured, then additional information may be needed in the TPINIT buffer such as the username and application password. Prior to exiting, tpterm(3c) should be called to cleanly terminate participation in the ATMI application. If you look at dceserver.c, you will see that by compiling it with -DTCLIENT, code is included that calls tpinit and tpterm. The code that sets up the TPINIT buffer must be modified appropriately for your application. To provide more information with respect to administration, it might be helpful to indicate that the client is a DCE client in either the user or client name (the example sets the client name to DCECLIENT). This information shows up when printing client information from the administration interface.
Second, since the Oracle Tuxedo ATMI system software is not thread-safe, the threading level passed to rpc_server_listen must be set to 1. In the sample dceserver.c, the threading level is set to 1 if compiled with -DTCLIENT and to the default, rpc_c_listen_max_calls_default, otherwise. (For more information, refer to the Oracle Tuxedo C Function Reference.)
In this configuration, the requester is built as a normal DCE client or server. Similarly, the server is built as a normal Oracle Tuxedo ATMI server. The additional step is to build the gateway process, which acts as an Oracle Tuxedo ATMI client using a TxRPC client stub, and a DCE server, using a DCE/RPC server stub.
The process of running the two IDL compilers and linking the resultant files is simplified with the use of the bldc_dce(1) command which builds an Oracle Tuxedo ATMI client with DCE linked in.
The usage for bldc_dce is as follows:
bldc_dce [-o output_file] [-w] [-i idl_options] [-f firstfiles] \
[-l lastfiles] [idl_file . . . ]
The command takes as input one or more IDL files so that the gateway can handle one or more interfaces. For each one of these files, tidl is run to generate a client stub and idl is run to generate a server stub.
This command knows about various DCE environments and provides the necessary compilation flags and DCE libraries. If you are developing in a new environment, it may be necessary to modify the command to add the options and libraries for your environment. The source is compiled in such a way (with -DTMDCEGW defined) that memory allocation is always done using rpc_ss_allocate and rpc_ss_free (described in the Oracle Tuxedo C Function Reference) to ensure that memory is freed on return. The use of -DTMDCEGW also includes DCE header files instead of Oracle Tuxedo TxRPC header files.
The IDL output object files are compiled, optionally with specified application files (using the -f and -l options), to generate an Oracle Tuxedo ATMI client using buildclient(1). Note that one of the files included should be the equivalent of the dceserver.o, compiled with the -DTCLIENT option.
The name of the executable client can be specified with the -o option.
When running this configuration, the Oracle Tuxedo ATMI configuration must be booted before starting the DCE server so that it can join the Oracle Tuxedo ATMI application before listening for DCE requests.
Oracle Tuxedo Requester to DCE Service Using DCE-only
Figure 4‑3 Oracle Tuxedo Requester to DCE Service Using DCE-only
This approach assumes that the DCE environment is directly available to the client (this can be a restriction or disadvantage in some configurations). The client program has direct control over the DCE binding and authentication. Note that this is presumably a mixed environment in which the requester is either an Oracle Tuxedo ATMI service that calls DCE services, or an Oracle Tuxedo client (or server) that calls both Oracle Tuxedo and DCE services.
When compiling Oracle Tuxedo TxRPC code that will be used mixed with DCE code, the code must be compiled such that DCE header files are used instead of the TxRPC header files. This is done by defining -DTMDCE at compilation time, both for client and server stub files and for your application code. If you are generating object files from tidl(1), you must add the -cc_opt -DTMDCE option to the command line. The alternative is to generate c_source from the IDL compiler and pass this C source (not object files) to bldc_dce or blds_dce as in the following examples:
tidl -keep c_source -server none t.idl
idl -keep c_source -server none dce.idl
bldc_dce -o output_file -f client.c -f t_cstub.c -f dce_cstub.c
or
blds_dce -o output_file -s service -f server.c -f t_cstub.c -f dce_cstub.c
In this example, we are not building a gateway process so .idl files cannot be specified to the build commands. Also note that the blds_dce command cannot figure out the service name associated with the server so it must be supplied on the command line using the -s option.
DCE Requester to Oracle Tuxedo Service Using Oracle Tuxedo-only
Figure 4‑4 DCE Requester to Oracle Tuxedo Service Using Oracle Tuxedo-only
In this final case, the DCE requester calls the Oracle Tuxedo client stub directly.
Again, -DTMDCE must be used at compilation time, both for client and server stub files and for your application code. In this case the requester must be an Oracle Tuxedo ATMI client:
tidl -keep c_source -client none t.idl
bldc_dce -o output_file -f -DTCLIENT -f dceserver.c -f t_cstub.c
Note that dceserver.c should call tpinit(3c) to join the application and tpterm(3c) to leave the application, as was discussed earlier.
Building Mixed DCE/RPC and Oracle Tuxedo TxRPC Clients and Servers
This section summarizes the rules to follow if you are compiling a mixed client or server without using the bldc_dce(1) or blds_dce(1) commands:
When compiling the generated client and server stubs, and compiling the client and server application software that includes the header file generated by tidl(1), TMDCE must be defined (for example, -DTMDCE=1). This causes some DCE header files to be used instead of the Oracle Tuxedo TxRPC header files. Also, some versions of DCE have a DCE compilation shell that adds the proper directories for the DCE header files and ensures the proper DCE definitions for the local environment. This shell should be used instead of directly using the C compiler. The DCE/RPC compiler and TMDCE definition can be specified using the -cc_cmd option on tidl. For example:
tidl -cc_cmd “/opt/dce/bin/cc -c -DTMDCE=1” simp.idl
or
tidl -keep c_source simp.idl
/opt/dce/bin/cc -DTMDCE=1 -c -I. -I$TUXDIR/include simp_cstub.c
/opt/dce/bin/cc -DTMDCE=1 -c -I. -I$TUXDIR/include client.c
On a system without such a compiler shell, it might look like the following:
cc <DCE options> -DTMDCE=1 -c -I. -I$(TUXDIR)/include \
-I/usr/include/dce simp_cstub.c
Refer to the DCE/RPC documentation for your environment.
If the server makes an RPC call, then set_client_alloc_free() should be called to set the use of rpc_ss_allocate() and rpc_ss_free(), as described earlier. (For more information, refer to the Oracle Tuxedo C Function Reference.)
When linking the executable, use -ldrpc instead of -ltrpc to get a version of the Oracle Tuxedo TxRPC runtime that is compatible with DCE/RPC. For example:
buildclient -o client -f client.o -f simp_cstub.o -f dce_cstub.o \
-f-ldrpc -f-ldce -f-lpthreads -f-lc_r
or
CC=/opt/dce/bin/cc buildclient -d “ “ -f client.o -f simp_cstub.o \
-f dce_cstub.o -f -ldrpc -o client
Assume that simp_cstub.o was generated by tidl(1) and dce_cstub.o was generated by idl. The first example shows building the client without a DCE compiler shell; in this case, the DCE library (-ldce), threads library (-lpthreads), and re-entrant C library (-lc_r) must be explicitly specified. The second example shows the use of a DCE compiler shell which transparently includes the necessary libraries. In some environments, the libraries included by buildserver and buildclient for networking and XDR will conflict with the libraries included by the DCE compiler shell (there may be re-entrant versions of these libraries). In this case, the buildserver(1) and buildclient(1) libraries may be modified using the -d option. If a link problem occurs, trying using -d “ “ to leave out the networking and XDR libraries, as shown in the example above. If the link still fails, try running the command without the -d option and with the -v option to determine the libraries that are used by default; then use the -d option to specify a subset of the libraries if there is more than one. The correct combination of libraries is environment-dependent because the networking, XDR, and DCE libraries vary from one environment to another.
Note:

Copyright © 1994, 2017, Oracle and/or its affiliates. All rights reserved.