Introduction to programming with Sun/ONC RPC: step 4

Step 4. Getting the server to do some work

Now that we know the client and sever compile and run, it's time to get the server to do some work. We will hard-code two numbers in the client that we want the server to add.

Initialize parameter in client

Edit add_client.c. Note that the function add_prog_1 defines a variable add_1_arg. This argument is passed as a parameter to the remote procedure call a few lines later with the call:

result_1 = add_1(&add_1_arg, clnt);

Before calling this function, we will initialize add_1_arg to contain the numbers 123 and 22. The variable is defined as type intpair, which we defined in add.x as containing to integers a and b (take a look at add.h to see how this is defined to the program). We can initialize the parameters with:

if (clnt == NULL) { clnt_pcreateerror(host); exit(1); } add_1_arg.a = 123; add_1_arg.b = 22; if (result_1 == NULL) { clnt_perror(clnt, "call failed:"); }

We can run make to make sure there were no syntax errors in transcribing these two lines (or the commands listed in step 3).

Turning to the server, add_server.c, we see that the first parameter of the add_1_svc function is our incoming parameter of type intpair.

We will add another print statement after the "add function called\n" one to print the values of the parameters. For more complex data types, these statements can serve as sanity checks and debugging aids. If the first statement is printed and the server dies after that, we know we made a mistake in dereferencing the parameters.

ONC RPC passes an address to the parameter on the client side and the server receives a local address of the incoming parameter. We now add the statement:

printf("add function called\n"); printf("parameters: %d, %d\n", argp->a, argp->b);

Compile and run this to see if we get what we expect. Compile with

make

and run the server (make sure you killed the old one) and then the client as in step 3. On the server window you should see:

parameters: 123, 22

This confirms that we get the parameters correctly. Let's compute the result and send it back. Before we return the address of result, set it to the sum of the two parameters and add another print statement:

printf("add function called\n"); printf("parameters: %d, %d\n", argp->a, argp->b); result = argp->a + argp->b; printf("returning: %d\n", result); return &result;

Note that the variable result is declared static. This is crucial because local (automatic) variables live on the stack. As soon as the server function returns the pointer to the result back to the server stub, the memory used by local variables can be reclaimed for use by the server stub. Failure to declare the return type static can result in nasty bugs where the code may seem to work a lot of the time but not always.

On the client, we'll need to add code to print the result. The return value from the call to add_1 is a pointer to the result type (int in this case). This allows us to find out whether the remote procedure call succeeded or not. If the return value is a 0 (a null pointer), we know the RPC failed. Otherwise, we can dereference the return type and get the value. Let's modify add_client.c to print the value:

if (result_1 == (int *) NULL) { clnt_perror (clnt, "call failed"); } else { printf("result = %d\n", *result_1); }

Compile (make) and run the code again on the server and client. As soon as you run the client code, you should see the following on the server:

add function called parameters: 123, 22 returning: 145

And the following on the client:

result = 145

We now have a working server.

Continue to step 5

Back to step 3