## TCPware V5.7 Programmer's Guide

- Introduction
- Distributed Application Components
- What You Need to Do
- Step 1: Design the Application
- Step 2: Write and Compile the Interface Definition
- Step 3: Write the Necessary Code
  - Building a Structure
- Step 4: Compile All Files
- Step 5: Link the Object Code
- Step 6: Start the Port Mapper
- Step 7: Execute the Client and Server Programs
  - Using Asynchronous Transports
  - Writing an Asynchronous Server
  - Before You Begin
  - Writing the Code
  - How Asynchronous Transports Affect Memory
  - Asynchronous System Traps
- RPCINFO Utility
  - Requesting a Program Listing
  - Calling a NULL Routine

Chapter 13

Building Distributed Applications with RPC

# Introduction

This chapter is for RPC programmers. It explains:

• What components a distributed application contains

• How to use ONC RPC to develop a distributed application, step by step

• How to use the RPCINFO utility

# Distributed Application Components

Table 13-1 lists the components of a distributed application.

Table 13-1 Application Components

Component | Description
Main program (client) | An ordinary main program that calls a remote procedure as if local
Network interface | Client and server stubs, header files, XDR routines for input arguments and results
Server procedure | Carries out the client's request (at least one is required)

These components may be written in any high-level language. The ONC RPC Run-Time Library (RTL) routines are written in C language.

# What You Need to Do

The following steps summarize what you need to do to build a distributed application:

1 Design the application.

2 Write an RPC interface definition. Compile it using RPCGEN, then edit the output files as necessary. (This step is optional. An RPC interface definition is not required. If you do not write one, proceed to step 3.)

3 Write any necessary code that RPCGEN did not generate.

4 Compile the RPCGEN output files, server procedures, and main program using the appropriate language compiler(s).

5 Link the object code, making sure you link in the ONC RPC RTL.

6 Start the Port Mapper on the server host.

7 Execute the client and server programs.

# Step 1: Design the Application

You must write a main (client) program and at least one server procedure. The network interface, however, may be hand-written or created by RPCGEN. The network interface files contain client and server stubs, header files, and XDR routines. You may edit any files that RPCGEN creates.

When deciding whether to write the network interface yourself, consider these factors:

Is execution time critical? | Your hand-written code may execute faster than code that RPCGEN creates.
Which RPC interface layer do you want to use? | RPCGEN permits you to use only the highest layer interface. If you want to use the lower layers, you must write original code. The ONC RPC Fundamentals, Chapter 12, describes the characteristics of each RPC interface layer.
Which transport protocol do you want to use? |

ONC: If you use an asynchronous transport (UDPA or TCPA), you must either write original code for the server stubs or edit the RPCGEN output.

You may write your own XDR programs, but it is usually best to let RPCGEN handle these.

# Step 2: Write and Compile the Interface Definition

An interface definition is a program the RPCGEN compiler accepts as input. The RPCGEN Compiler, Chapter 14, explains exactly what interface definitions must contain.

Interface definitions are optional. If you write the all of the network interface code yourself, you do not need an interface definition.

You must write an interface definition if you want RPCGEN to generate network interface code.

After compiling the interface definition, edit the output file(s).

If you are not writing an interface definition, skip this step and proceed to step3.

# Step 3: Write the Necessary Code

Write any necessary code that RPCGEN did not create for you. Table 13-2 lists the texts you may use as references.

Table 13-2 Coding References

Reference | Purpose
RFC 1057 | Defines the RPC language. Use for writing interface definitions.
RFC 1014 | Defines the XDR language. Use for writing XDR filter routines.
The ONC RPC RTL Client Routines chapter and those that follow | Defines each routine in the ONC RPC RTL. Use for writing stub procedures and XDR filter routines.

## Building a Structure

If an input argument or result is not an integer, you need to create a structure for it in the RPCGEN input file. RPCGEN converts the structure to C format and creates XDR code to encode and decode it.

The TCPWARE_ROOT:[TCPWARE.EXAMPLES.RPC]GETSYI.X file provides a sample interface definition containing a structure.

# Step 4: Compile All Files

Compile the RPCGEN output files, server procedures, and main program separately using the appropriate language compiler(s):

XDR: DEC C (VAX, Alpha and I64):

$ CC /STANDARD=RELAXED /WARNING=DISABLE=(IMPLICITFUNC) filename.C

ONC: VAX C:

$ CC filename.C

ONC: DEC C (VAX):

$ CC /STANDARD=VAXC filename.C

ONC: DEC C (Alpha and I64):

$ CC /STANDARD=VAXC /NOMEMBER_ALIGN /ASSUME=NOALIGN filename.C

FORTRAN (VAX):

$ FORTRAN filename.FOR

FORTRAN (Alpha and I64):

$ FORTRAN /NOALIGN /WARNING=(DECLARATIONS,ALIGN) filename.FOR

# Step 5: Link the Object Code

Link the object code files. Make sure you link in the ONC RPC RTL. Use the following command:

XDR: DEC C (VAX, Alpha and I64):

$ LINK filenames, SYS$INPUT /OPTIONS
UCX$RPCXDR_SHR /SHARE
SYS$SHARE:DECC$SHR /SHARE
Ctrl/Z

ONC: VAX:

$ LINK filenames, SYS$INPUT /OPTIONS
SYS$SHARE:VAXCRTL/SHARE
SYS$SHARE:TCPWARE_RPCLIB_SHR/SHARE
Ctrl/Z

ONC: Alpha and I64:

$ LINK filenames, SYS$INPUT /OPTIONS
UCX$RPCXDR_SHR /SHARE
SYS$SHARE:DECC$SHR /SHARE
Ctrl/Z

After entering the command, press Ctrl/Z.

To avoid repetitive data entry, you may create an OpenVMS command procedure to execute these commands.

# Step 6: Start the Port Mapper

The Port Mapper must be running on the server host. If it is not running, use the NETCU ADD SERVICE command to start it. See Chapter 2, NETCU Commands of the NETCU Command Reference manual for details on this command.

# Step 7: Execute the Client and Server Programs

Perform these steps:

1 Run the server program interactively to debug it, or using the /DETACHED qualifier. Refer to HP’s documentation for details.

2 Run the client main program.

## Using Asynchronous Transports

ONC: ONC RPC provides two asynchronous transport protocols: TCPA and UDPA. These protocols allow you to write multi-threaded servers that can process multiple requests in parallel.

Only an asynchronous service can benefit from using an asynchronous transport.

For example, you would use an asynchronous transport for a service that performs a lot of asynchronous file I/O by issuing QIOs. You would not use an asynchronous transport for a service that performs a lot of synchronous file I/O.

Client processes cannot use TCPA and UDPA.

The asynchronous transport protocols are specific to TCPware.

The ONC RPC Fundamentals, Chapter 12, explains the differences between each transport protocol.

## Writing an Asynchronous Server

ONC: This section explains how to write an asynchronous server.

## Before You Begin

1 Decide how many threads the server will support. The number of threads determines the number of requests the server can handle in parallel. The server can parallel process as many requests as it has threads.

2 Choose the TCPA and/or UDPA transport protocol. (A server can support both.)

3 Determine:

• The size of the XID cache. Generally, this is at least the number of UDPA or TCPA threads.

• Which procedures, if any, the XID cache will contain responses for.

## Writing the Code

ONC: Write a program that performs the following steps:

1 To set up the server:

a Call svcudpa_create and/or svctcpa_create for each thread. Save the return values for later use. Use the svc_getchan routine after the first call and specify the returned value in subsequent calls.

b If you are enabling the XID cache, call svcudpa_enablecache and/or svctcpa_enablecache for each thread. Use the result of the first call to svcudpa_enablecache/svctcpa_enablecache as input to successive calls to that routine, so that all threads use the same cache.

c Call the svc_register routine once for each transport to register the service.

2 Put the main code in "hibernation" by calling SYS$HIBER instead of svc_run. SYS$HIBER is an OpenVMS system service that accepts no input arguments.

3 To shut down the server:

a Perform any shutdown steps that are specific to your server.

b Call svctcpa_shutdown once for all TCPA threads.

c Call svcudpa_shutdown once for all UDPA threads.

d Call svc_destroy once for each thread.

## How Asynchronous Transports Affect Memory

ONC: Asynchronous transports use more memory than synchronous transports because each service has more than one thread.

When TCPA receives requests greater than 4Kbytes, it uses significantly more memory than TCP uses for the same size requests. TCP reads in 4Kbytes of data, processes the data, then reads more data as necessary. TCPA reads all of the data before calling the server dispatch routine.

## Asynchronous System Traps

ONC: All UDPA and TCPA servers use asynchronous system traps (ASTs). Refer to the Guide to VMS Programming Resources for complete information on ASTs.

When using ASTs, follow these guidelines:

• Do not permit the main program to disable ASTs for long periods of time. If the program disables ASTs before it calls SYS$HIBER, the server does not respond to requests.

• The AST quota for the server process must allow at least one AST for each thread.

• The dispatch routine is called as a user-mode AST. This means a program cannot do synchronous waiting when an AST is required to wake up the program.

• Only one AST can be active at a time.

# RPCINFO Utility

RPCINFO is an ONC RPC utility that allows you to:

• Request a listing of all programs registered with a Port Mapper.

• Call the NULL routine of any program

RPCINFO supports both the UDP and TCP protocols.

## Requesting a Program Listing

To request a listing of all programs that are registered with the Port Mapper, enter the RPCINFO command in the following format at the DCL prompt:

RPCINFO -p [-u | -t] [host-name]

-p | Calls the Port Mapper.
-u | Uses the UDP transport to send the request. This is the default if you do not specify a transport.
-t | Uses the TCP transport to send the request.
host-name | Specifies the domain name of the host on which the Port Mapper resides. If you omit this parameter, RPCINFO uses the name of the local host.

Example 13-1 shows an example.

Example 13-1 Sample RPCINFO Program Listing

$ rpcinfo -p hermes

Program Version Protocol Port
------- ------- -------- ----
100000 2 udp 111 rpcbind
100000 2 tcp 111 rpcbind
100005 1 udp 2049 mountd

## Calling a NULL Routine

To call the NULL routine of a program, enter the RPCINFO command in the following format at the DCL prompt:

RPCINFO [-u | -t] host-name program [version]

-u | Uses the UDP transport to send the request. If you do not specify a trans port, this is the default.
-t | Uses the TCP transport to send the request.
host-name | Specifies the domain name of the target host.
program | Specifies the program number of the target program.
version | Specifies the version number of the target program. If you omit the version, the default is 1.

For example, suppose you enter the following command:

RPCINFO ETA 100000 2

The following message displays if the call completes successfully:

Version 2 of program 100000 successfully called