This appendix contains a description of a
one-client, one-server application called
rcpsimp
that uses TxRPC.
The source files for this interactive application are
distributed with the TUXEDO System/T software, except they are not included in
the RTK binary delivery.
Before you can run this example, the TUXEDO System/T software must
be installed so that
the files and commands
referred to in this chapter are available.
rpcsimp
is a very basic TUXEDO System/T application that uses TxRPC.
It has one application client and one server.
The client calls the remote procedure calls (operations)
to_upper()
and
to_lower()
which are implemented in the server.
The operation
to_upper()
converts a string from lower case to upper case
and returns it to the client, while
to_lower()
converts a string from upper case to lower case
and returns it to the client.
When each procedure call returns, the client displays the string output on
the user's screen.
What follows is a procedure
to build and run the example.
Make a directory for
rpcsimp
and
cd
to it:
Set and export the necessary environment variables.
Copy the
rpcsimp
files to the application directory.
List the files.
This list does not include files that are used in the DCE-Gateway
example described in
The files that make up the application are
described in the following sections.
This file defines a single interface,
changecase
version 1.0,
with two operations,
to_upper
and
to_lower.
Each of the operations takes a NULL-terminated character string,
that is both an input and output parameter.
Since no ACF file is provided, status variables are not used
and the client program must be able to handle exceptions.
Each operation has a void return indicating that no return value
is generated.
simp.idl
is used to generate the stub functions
(see below).
The header,
simp.h,
which is generated by the IDL compiler based on
simp.idl,
has the function prototypes for the two operations.
The
simp.h
header also includes the header files for the
RPC runtime functions (none appear in this example) and
exception handling.
The
atmi.h
header file is included because
tpterm()
is called.
If an argument is provided on the command line, then it is used
for the conversion to upper and lower case (the default being "hello world").
Exception handling is used to catch any errors.
For example, exceptions are generated for unavailable
servers, memory allocation failures,
communication failures, and so forth.
The
TRY
block encapsulates the two remote procedure calls.
If an error occurs,
the execution will jump to the
CATCH_ALL
block which converts the exception (
THIS_CATCH)
into a string, prints it to the standard error output using
exc_report,
and exits.
Note that in both the abnormal and normal execution,
tpterm()
is called to leave the application gracefully.
If this is not done,
a warning is printed in the
userlog()
for non-workstation clients,
and resources are tied up (until
the connection times out, for workstation clients).
As with
client.c,
this file includes
simp.h.
It also includes
tx.h
since
tx_open()
is called (as required by
the X/OPEN TxRPC Specification, even if no resource manager is accessed).
A
tpsvrinit()
function is provided to ensure that
tx_open()
is called once at boot time.
This is done automatically, so you may not need to supply it.
On failure, -1 is returned
and the server fails to boot.
The two operation functions are provided to do the application work,
in this case, converting to upper and lower case.
The
makefile
builds the executable client and server programs.
The part of the makefile dealing with the DCE Gateway described in
"Appendix B" is omitted from the figure.
The client is dependent on the
simp.h
header file and the client stub object file.
buildclient
is executed to create the
output client executable, using the
client.c
source file,
the client stub object file, and the
-ltrpc
RPC runtime library.
The server is dependent on the
simp.h
header file and the server stub object file.
buildserver is an
output server executable, using the
server.c
source file, the server stub object file, and the
-ltrpc
RPC runtime library.
The client and server stub object files and the
simp.h
header file are all created by running the
tidl
compiler on the IDL input file.
The
clean
target removes any files that are created while building
or running the application.
The following is a sample ASCII configuration file. The machine name,
TUXCONFIG, TUXDIR, and APPDIR must be set
based on your configuration.
The lines for
MAXWSCLIENTS
and
WSL
are uncommented and are
used for a /WS configuration.
The literal <address> for the /WS listener must be set as described in
the
WSL(5)
manual page.
Building MS-DOS and Windows clients is different enough from
native clients that a separate makefile is desirable.
This
makefile
builds an executable MS-DOS client,
a quick Windows client using Microsoft QuickWin, and a Windows Dynamic Link
Library (DLL).
The
dos
target builds a MS-DOS client.
The first step is to execute
tidl
on the IDL input file (the same one that is used for native
clients and servers), listed above. Due to the filename limitations,
the
-cstub
option is used to rename the output file
simp.c.
Also note that the
-server none
option is used to inhibit output of the server stub.
The client stub is simply compiled into an object file,
simp.obj.
The example uses the "large" memory model and the Microsoft C compiler,
but the model could be "large" and a different compiler could be used.
The
-I
option is used to include the generated header,
simp.h,
in the current directory.
Similarly, the client application program,
client.c,
is compiled to the object file
client.obj.
Finally,
buildclt
is called to link object files and libraries to form the executable,
client.exe.
The
-v
option prints out the commands being executed, the
-m
option
is used to specify the large memory model, and the
-c
option is used to specify the Microsoft C compiler (see
buildclt(1)
for further details).
The first
-f
option sets the stack size, the second
and third
-f
options include the object files, and
mtrpc.lib
(the RPC runtime library)
is also included using a
-f
option.
The networking library,
mlibsock.lib
(Novell's Lan Workplace for MS-DOS),
is included using a
-l
option.
Before running this client, the application must be booted (as described
below) and the
WSNADDR
environment variable must be set
(see the
BEA TUXEDO /Workstation Guide
for further details).
The
win
target builds a Windows client using the Microsoft QuickWin
feature (Borland's Easy Win provides similar functionality).
It allows a character-based C program to be compiled and run as a Windows
program, without modification. The client stub is generated, as above,
with a "w" prefix (
wsimp.c).
The client code is copied to a new name and compiled.
The
/mQ
compilation option invokes the QuickWin feature,
as does the use of the
libcewq
library on the
link
command line.
It is important to remember that when compiling any Windows program
that uses the TUXEDO System software,
-D_TM_WIN
must be defined.
The
buidclt
command cannot be used because non-standard libraries
are being used to link the executable.
The
link
command line contains
the client stub and application object files, the RPC and TUXEDO system
libraries, and the Windows, QuickWin, and networking libraries.
The definition file,
wclient.def,
is listed below; it simply sets a valid heap and stack size.
The
makefile
does not demonstrate building OS/2
programs.
Compilation is similar to the MS-DOS example above, but with
the correct options for these platforms.
Remember to use the
-D_TM_OS2
when compiling for OS/2.
See the
bankapp
sample application under
$TUXDIR/apps/ws
for examples of complete applications for these platforms.
The
makefile
does include a more interesting feature not shown in the
bankapp
sample, the creation of a DLL. One common use of the TxRPC
interface operations is to create one or more interfaces for
use in applications via a dynamic link library.
Use of a DLL is necessary for most visual builders
(such as Visual Basic, Gupta SQL Windows, and others)
where the programmer simply indicates
the name of a DLL, specifies a function prototype, and calls the
function directly from the application.
The
makefile
takes the output of the IDL compiler and creates a DLL,
wsimpdll.dll
(the source for the client application,
assumed to be written with a visual builder, is not provided).
The client stub is generated exactly the same as for the native and
MS-DOS clients (in the
makefile,
it is renamed
simpdll.c
to differentiate it from the MS-DOS client).
Special Windows options (for Microsoft C, for example,
-Aw -G2swx -Zp)
are used to generate the DLL object file,
and the
-D_TM_WIN
option is used for TUXEDO /WS.
Since the DLL always has a different
data segment and text segment from the application code calling it,
all pointers provided to and returned from the operations must be
declared as far (4-byte) pointers.
Similarly, functions are declared as far.
Also, Windows functions are traditionally declared to have the
_pascal
calling convention.
The header file and stub are automatically generated to easily allow
for the declarations to be changed, using C pre-processor definitions.
The definition
_TMF
(for "far") appears before all pointers in the header file
and is automatically defined as "_far" when compiling for Windows or OS/2.
Similarly,
_TMX
(for "eXport") appears before all declared functions.
By default,
_TMX
is defined to nothing. When compiling
a stub for inclusion in a DLL,
_TMX
should be defined using -D_TMX="_far _pascal".
Also, the files to be included in the DLL must be compiled with the
large memory model.
Once the
simpdll.obj
object file is created using the compiler, the DLL,
WSIMPDLL.DLL,
is created using the linker,
including the object file, the RPC and TUXEDO System
libraries, the Windows library, the networking library, and the
definition file,
wsimpdll.def
(listed below).
The resource compiler is run on the resulting DLL, and
implib
is executed to generate the output library,
WSIMPDLL.LIB,
used for linking with applications.
This definition file is used when linking the Windows client program.
This definition file is used when linking the DLL file. Note
that it lists the two operation names.
They are upper case because
functions declared with the
_pascal
modifier are converted to upper case.
Edit the ASCII
ubbconfig
configuration file to provide location-specific information
(for example, your own directory pathnames and machine name),
as described in the next step.
The text to be replaced is enclosed in angle brackets.
You need to substitute the full pathnames for
TUXDIR
TUXCONFIG,
and
APPDIR,
and the name of the machine on which you are running.
Here is a summary of the required values:
For a /WS configuration, the
MAXWSCLIENTS
and
WSL
lines must be uncommented and the
address
must be set for the Workstation Listener (see
WSL(5)
for further details).
Build the client and server programs by running
Load the binary
TUXCONFIG
configuration file by running
Boot the application by running
The native client program can be run by optionally specifying a string
to be converted to upper and then lower case.
The RPC server can be monitored using
tmadmin(1).
In the following example,
psr
and
psc
are used to view the information for the
server
program. Note that the length of the RPC service
name causes it to be truncated in terse mode (indicated by the "+");
verbose mode can be used to get the full name.
> psc
Service Name Routine Name a.out Name Grp Name ID Machine # Done Status
------------ ------------ ---------- -------- -- ------- ------ ------
ADJUNCTBB ADJUNCTBB BBL SITE1 0 SITE1 0 AVAIL
ADJUNCTADMIN ADJUNCTADMIN BBL SITE1 0 SITE1 0 AVAIL
changecasev+ changecasev+ server GROUP1 1 SITE1 2 AVAIL
> verbose
Verbose now on.
> psc -g GROUP1
Service Name: changecasev1_0
Service Type: USER
Routine Name: changecasev1_0
a.out Name: /home/sdf/trpc/rpcsimp/server
Queue Name: 00001.00001
Process ID: 8602, Machine ID: SITE1
Group ID: GROUP1, Server ID: 1
Current Load: 50
Current Priority: 50
Current Trantime: 30
Requests Done: 2
Current status: AVAILABLE
> quit
Shut down the application by running
Clean up the created files by running
Some Preliminaries
The rpcsimp Application
Step 1 - Create an application directory
mkdir rpcsimpdir
cd rpcsimpdir
This is suggested so you will be able to see clearly the
rpcsimp
files you have at the start and the additional files you
create along the way.
Use the standard shell (
/bin/sh)
or the Korn shell, not C shell,
csh.
Step 2 - Set environment variables
TUXDIR=<pathname of the TUXEDO System/T root directory>
TUXCONFIG=<pathname of your present working directory>/TUXCONFIG
PATH=$PATH:$TUXDIR/bin
# SVR4, UnixWare
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# HPUX
SHLIB_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# RS6000
LIBPATH=$LD_LIBRARY_PATH:$TUXDIR/lib
export TUXDIR TUXCONFIG PATH LD_LIBRARY_PATH SHLIB_PATH LIBPATH
You need
TUXDIR
and
PATH
to be able to access files in the TUXEDO System/T directory structure
and to execute TUXEDO System/T commands.
You need to set
TUXCONFIG
to be able to load the configuration file.
It may also be necessary to set an environment variable
(for example,
LD_LIBRARY_PATH)
if shared objects are being used.
Step 3 - Copy files
cp $TUXDIR/apps/rpcsimp/* .
You will be editing some
of the files and making them
executable, so it is best to begin with a copy of the
files rather than the originals delivered with the software.
Step 4 - List files
$ ls
client.c
rpcsimp.mak
rpcsimp.mk
server.c
simp.idl
ubbconfig
wclient.def
wsimpdll.def
$
IDL Input File - simp.idl
Fig. 1:simp.idl
[uuid(C996A680-9FC2-110F-9AEF-930269370000), version(1.0) ]
interface changecase
{
/* change a string to upper case */
void to_upper([in, out, string] char *str);
/* change a string to lower case */
void to_lower([in, out, string] char *str);
}
The Client Source Code - client.c
Fig. 2:client.c
#include <stdio.h>
#include "simp.h"
#include "atmi.h"
main(argc, argv)
int argc;
char **argv;
{
idl_char str[100];
unsigned char error_text[100];
int status;
if (argc > 1) {/* use command line argument if it exists */
(void) strncpy(str, argv[1], 100);
str[99] = '\0';
}
else
(void) strcpy(str, "Hello, world");
TRY
{
to_upper(str);
(void) fprintf(stdout, "to_upper returns: %s\n", str);
to_lower(str);
(void) fprintf(stdout, "to_lower returns: %s\n", str);
/* control flow continues after ENDTRY */
CATCH_ALL
{exc_report(THIS_CATCH); /* print to stderr */
(void) tpterm();
exit(1);
}
ENDTRY
(void) tpterm();
exit(0);
}
}
The Server Source Code - server.c
Fig. 3:server.c
#include <stdio.h>
#include <ctype.h>
#include "tx.h"
#include "simp.h"
int
tpsvrinit(argc, argv)
int argc;
char **argv;
{
if (tx_open() != TX_OK) {
(void) userlog("tx_open failed");
return(-1);
}
(void) userlog("tpsvrinit() succeeds.");
return(1);
}
void
to_upper(str)
idl_char *str;
{
idl_char *p;
for (p=str; *p != '\0'; p++)
*p = toupper((int)*p);
return;
}
void
to_lower(str)
idl_char *str;
{
idl_char *p;
for (p=str; *p != '\0'; p++)
*p = tolower((int)*p);
return;
}
Makefile - rpcsimp.mk
Fig. 4:rpcsimp.mk
CC=cc
CFLAGS=
TIDL=$(TUXDIR)/bin/tidl
LIBTRPC=-ltrpc
all: client server
# TUXEDO client
client: simp.h simp_cstub.o
CC=$(CC) CFLAGS=$(CFLAGS) $(TUXDIR)/bin/buildclient -oclient \
-fclient.c -fsimp_cstub.o -f$(LIBTRPC)
# TUXEDO server
server: simp.h simp_sstub.o
CC=$(CC) CFLAGS=$(CFLAGS) $(TUXDIR)/bin/buildserver -oserver \
-s changecasev1_0 -fserver.c -fsimp_sstub.o -f$(LIBTRPC)
simp_cstub.o simp_sstub.o simp.h: simp.idl
$(TIDL) -cc_cmd "$(CC) $(CFLAGS) -c" simp.idl
#
# THIS PART OF THE FILE DEALING WITH THE DCE GATEWAY IS OMITTED
#
# Cleanup
clean::
rm -f *.o server $(ALL2) ULOG.* TUXCONFIG
rm -f stderr stdout *stub.c *.h simpdce.idl gwinit.c
clobber: clean
The Configuration File - ubbconfig
Fig. 5:ubbconfig
*RESOURCES
IPCKEY 187345
MODEL SHM
MASTER SITE1
PERM 0660
*MACHINES
UNAME LMID=SITE1
TUXCONFIG="<TUXCONFIG>"
TUXDIR="<TUXDIR>"
APPDIR="<APPDIR>"
# MAXWSCLIENTS=10
*GROUPS
GROUP1 LMID=SITE1 GRPNO=1
*SERVERS
server SRVGRP=GROUP1 SRVID=1
#WSL SRVGRP=GROUP1 SRVID=2 RESTART=Y GRACE=0
# CLOPT="-A -- -n <address> -x 10 -m 1 -M 10 -d <device>"
#
# TUXEDO-to-DCE Gateway
#simpgw SRVGRP=GROUP1 SRVID=2
*SERVICES
*ROUTING
MS-DOS and Windows Makefile - rpcsimp.mak
Fig. 6:rpcsimp.mak
# Model for dos client
MODEL=L
WINMODEL=M
# Generate MS-DOS Client
dos: client.exe
simp.c: simp.IDL
TIDL -cstub simp.c -keep c_source -server none simp.IDL
client.obj: client.c
CL -I. -c -A$(MODEL) client.c
simp.obj: simp.c
CL -I. -c -A$(MODEL) simp.c
client.exe: simp.obj client.obj
buildclt -v -m$(MODEL) -cm -o client.exe -f "/ST:15000 /CO" \
-f client.obj -f simp.obj -f$(MODEL)trpc.lib -l$(MODEL)libsock.lib
# Generate Windows client using MSC QuickWin
win: wclient.exe
wsimp.C: simp.IDL
TIDL -cstub wsimp.c -keep c_source -server none simp.IDL
wclient.c: client.c
copy client.c wclient.c
wclient.obj: wclient.c
CL /mQ -A$(WINMODEL) -I. -D_TM_WIN -Od -c wclient.C
wsimp.obj: wsimp.c
CL /mQ -A$(WINMODEL) -I. -D_TM_WIN -Od -c wsimp.C
wclient.exe: wsimp.obj wclient.obj
link wclient.obj wsimp.obj, wclient.exe , NUL, /NOD wtrpc \
wtuxws libw $(WINMODEL)libcewq Wlibsock,wclient.def
# Generate DLL
# Must be built with large model
dll: WSIMPDLL.DLL
simpdll.C: simp.IDL
TIDL -cstub simpdll.c -keep c_source -server none simp.IDL
simpdll.OBJ: simpdll.C
CL -D_TMX="_far _pascal" -AL -I. -Aw -G2swx -Zp -D_TM_WIN -Od -c simpdll.C
WSIMPDLL.DLL: simpdll.OBJ
LINK simpdll.OBJ , WSIMPDLL.DLL /CO /ALIGN:16, NUL, /NOD WLIBTRPC\
WTUXWS WLIBSOCK LIBW LDLLCEW, WSIMPDLL.DEF
RC -K WSIMPDLL.DLL
IMPLIB WSIMPDLL.LIB WSIMPDLL.DLL
clean:
if exist resptmp del resptmp
if exist simp.c del simp.c
if exist simp.h del simp.h
if exist wsimp.c del wsimp.c
if exist wclient.c del wclient.c
if exist simpdll.c del simpdll.c
del *.obj
del *.exe
if exist wsimpdll.lib del wsimpdll.lib
if exist wsimpdll.dll del wsimpdll.dll
Windows Definition Files - wclient.def and wsimpldll.def
Fig. 7:wclient.def
NAME WINDOWAPI
EXETYPE WINDOWS 3.0
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE
HEAPSIZE 1024
STACKSIZE 8096
Fig. 8:wsimpdll.def
LIBRARY WSIMPDLL
PROTMODE
DESCRIPTION 'TUXEDO /RPC SAMPLE DLL'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD SINGLE
HEAPSIZE 1024
SEGMENTS WEPSEG PRELOAD FIXED
;EXETYPE WINDOWS
EXPORTS
TO_UPPER @1
TO_LOWER @2
Step 5 - Modify the Configuration
the full pathname of the root directory of the TUXEDO System/T
software, as set above.
the full pathname of the binary configuration file, as set above.
the full pathname of the directory in which your
application will run.
the machine name of the machine on which your
application will run; this is the output of the UNIX
uname -n
command
Step 6 - Build the Application
make -f rpcsimp.mk TUXDIR=$TUXDIR
Step 7 - Load the Configuration
tmloadcf -y ubbconfig
Step 8 - Boot the Configuration
tmboot -y
Step 9 - Run the client
$ client HeLlO
to_upper returns: HELLO
to_lower returns: hello
$
When running on /WS, the
WSNADDR
environment variable must be set to match the address
specified for the WSL program.
The MS-DOS client program can be run in exactly the same manner
as the native client.
The Windows client can be run by executing
>win wclient
The dynamic link library may be used in a separately developed application
(for example, a visual builder).
Step 10 - Monitor the RPC Server
Fig. 9:tmadmin psr and psc output
$ tmadmin
> psr
a.out Name Queue Name Grp Name ID RqDone Load Done Current Service
---------- ---------- -------- -- ------ --------- ---------------
BBL 587345 SITE1 0 0 0 ( IDLE )
server 00001.00001 GROUP1 1 2 100 ( IDLE )
Step 11 - Shut down the Configuration
tmshutdown -y
Step 12 - Clean up
make -f rpcsimp.mk clean