Lecture Notes for Client-Server Interfaces

8 March 2001 - The Horrible Truth About RPC


The Three Faces of RPC


The High Level

#include <stdio.h>
#include <stdlib.h>
#include <rpcsvc/rstat.h>

int main(int argc, char * argv[]) {

  if (argc != 2) {
    fprintf(stderr, "Command format is \"%s hostname\".\n", argv[0]);
    return EXIT_FAILURE;
    }

  int dsk;
  if ((dsk = havedisk(argv[1])) < 0) {
    fprintf(stderr, "havedisk(%s) failed.\n", argv[1]);
    return EXIT_FAILURE;
    }

  printf("%s %s a disk.\n", argv[1], dsk ? "has" : "doesn't have");

  return EXIT_SUCCESS;
  }


And Then. . .

cl make cc-high-rstat
g++    -c cc-high-rstat.cc -o cc-high-rstat.o
g++ -o cc-high-rstat cc-high-rstat.o -lrpcsvc

cl uname -a
SunOS clayton 5.7 Generic_106541-11 sun4u sparc SUNW,Ultra-5_10

cl cc-high-rstat cslab05
cslab05 has a disk.

cl cc-high-rstat clayton 
clayton has a disk.

cl cc-high-rstat starbase.se.monmouth.edu
starbase.se.monmouth.edu has a disk.

cl cc-high-rstat cslab00                 
havedisk(cslab00) failed.

cl rsh cslab00 ps -Af | grep -i rpc
  root  156    1  0   Jan 29 ?   1:32 /usr/sbin/rpcbind
  root  186    1  0   Jan 29 ?   0:00 /usr/lib/netsvc/yp/rpc.ypupdated
  root  171  169  0   Jan 29 ?   5:57 rpc.nisd_resolv -F -C 8 
  root  667    1  0   Jan 29 ?   0:00 /usr/sbin/rpc.bootparamd
  root  785  213  0   Jan 29 ?   0:00 /usr/dt/bin/rpc.ttdbserverd

cl rsh cslab05 ps -Af | grep -i rpc
  root  105    1  0   Feb 12 ?   0:00 /usr/sbin/rpcbind
  root  338  142  0   Feb 12 ?   0:00 rpc.ttdbserverd
daemon  537  142  0   Feb 13 ?   0:00 rpc.cmsd
  root 2835  142  0 16:14:20 ?   0:00 rpc.rstatd


The Middle Level

#include <stdio.h>
#include <stdlib.h>
#define PORTMAP
#include <rpc/rpc.h>
#include <rpcsvc/rstat.h>
#include <rpc/xdr.h>

int main(int argc, char * argv[]) {

  if (argc != 2) {
    fprintf(stderr, "Command format is \"%s hostname\".\n", argv[0]);
    return EXIT_FAILURE;
    }

  int dsk;
  enum clnt_stat stat = callrpc(
    argv[1], RSTATPROG, RSTATVERS_VAR, RSTATPROC_HAVEDISK, 
    xdr_void, 0, xdr_u_long, &dsk);
  if (stat) {
    clnt_perrno(stat);
    return EXIT_FAILURE;
    }

  printf("%s %s a disk.\n", argv[1], dsk ? "has" : "doesn't have");

  return EXIT_SUCCESS;
  }


Fun with RPC

cl make cc-mid-rstat
g++    -c cc-mid-rstat.cc -o cc-mid-rstat.o
g++ -o cc-mid-rstat cc-mid-rstat.o -lnsl

cl cc-mid-rstat clayton
clayton has a disk.

cl cc-mid-rstat cslab05
cslab05 has a disk.

cl cc-mid-rstat starbase.se.monmouth.edu
RPC: Program/version mismatch

cl 


The Low Level

int main(int argc, char * argv[]) {

  struct hostent *hp;
  if ((hp = gethostbyname(argv[1])) == NULL) {
    fprintf(stderr, "can't get addr for %s\n",argv[1]);
    return EXIT_FAILURE;
    }

  int sock = RPC_ANYSOCK;
  struct timeval pertry_timeout, total_timeout;
  struct sockaddr_in server_addr;

  pertry_timeout.tv_sec = 3;
  pertry_timeout.tv_usec = 0;
  bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port =  0;

  CLIENT *client = clntudp_create(&server_addr, RSTATPROG,
				  RSTATVERS_VAR, pertry_timeout, &sock);
  if (NULL == client) {
    clnt_pcreateerror("clntudp_create");
    return EXIT_FAILURE;
    }

  total_timeout.tv_sec = 20;
  total_timeout.tv_usec = 0;
  unsigned long dsk;
  enum clnt_stat stat = clnt_call(client, RSTATPROC_HAVEDISK,
				  (bool_t (*)(XDR *, void *)) xdr_void, 0,
				  xdr_u_long, (char *) &dsk, 
				  total_timeout);
  if (stat != RPC_SUCCESS) {
    clnt_perror(client, "rpc");
    return EXIT_FAILURE;
    }

  printf("%s %s a disk.\n", argv[1], dsk ? "has" : "doesn't have");

  clnt_destroy(client);
  close(sock);

  return EXIT_SUCCESS;
  }


Just Checking

cl cc-low-rstat cslab05
cslab05 has a disk.

cl cc-low-rstat cslab00
clntudp_create: RPC: Program not registered

cl cc-low-rstat starbase.se.monmouth.edu
rpc: RPC: Program/version mismatch; low version = 1, high version = 3

cl 


Why Three Levels?


The Server Side


This page last modified on 10 April 2001.