Example: TI-RPC top-level client API

This code example illustrates a top-level client API that is used in developing TI-RPC applications.

At the top level, you must create a client handle before you can use it or modify it. Top-level APIs are easy to use, and they allow more manipulation and error handling than the simplified level.

Note: By using the code example, you agree to the terms of the Code license and disclaimer information.
#include <stdio.h>
#include <netconfig.h>
#include <netdir.h>
#include <errno.h>
#include "myapp.h"

#define EXIT 100

int main(void) {

   enum clnt_stat rslt;    /* return value of clnt_call() */
   char hostname[256];    /* buffer for remote service's hostname */
   unsigned long procnum;  /* procedure to call */
   char filename[512];     /* buffer for filename */
   xdrproc_t xdr_argument; /* xdr procedure to encode arguments */
   xdrproc_t xdr_result;   /* xdr procedure to decode results */
   CLIENT *clnt;           /* pointer to client handle */
   struct timeval tout;    /* timeout for clnt_call() */
   char *arg = filename;   /* pointer to filename buffer */

   union {
      u_int   myapp_get_uid_result;
      char *  myapp_get_uid_string_result;
      int     myapp_get_size_result;
      long    myapp_get_mtime_result;
      char *  myapp_get_mtime_string_result;
      u_short myapp_get_codepage_result;
      char *  myapp_get_objtype_result;
      char *  myapp_get_filetype_result;
   } result; /* a union of all the possible results */

   tout.tv_sec  = 30;  /* set default timeout to 30.00 seconds */
   tout.tv_usec =  0;

   /* get the hostname from the user */
   printf("Enter the hostname where the remote service is running: \n");
   scanf("%s", (char *)&hostname);

   myapp_print_menu(); /* print out the menu choices */

   /* get the procedure number to call from the user */
   printf("\nEnter a procedure number to call: \n");
   scanf("%lu", &procnum);

   /* get the filename from the user */
   printf("\nEnter a filename to stat: \n");
   scanf("%s", (char *)&filename);

   /* clnt_create(host, prognum, versnum, nettype);    */
   clnt = clnt_create(hostname, PROGNUM, VERSNUM, NETTYPE);

   /* check to make sure clnt_create() didn't fail */
   if (clnt == (CLIENT *)NULL) {
      /* if we failed, print out all appropriate error messages and exit */
      fprintf(stderr, "Error calling clnt_create()\n");
      fprintf(stderr, "PROG: %lu\tVERS: %lu\tNET: %s\n",
              PROGNUM, VERSNUM, NETTYPE);
      fprintf(stderr, "clnt_stat: %d\n", rpc_createerr.cf_stat);
      fprintf(stderr, "errno: %d\n", errno);
      fprintf(stderr, "re_errno: %d\n", rpc_createerr.cf_error.re_errno);
      return 1;
   }

   /* switch on the input */
   switch (procnum) {

      case NULLPROC:
         /* set the encode procedure */
         xdr_argument = (xdrproc_t)xdr_void;
         /* set the decode procedure */
         xdr_result   = (xdrproc_t)xdr_void;
         break;

      case GET_UID:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring; 
         /* set the decode procedure */
         xdr_result   = xdr_u_int;
         break;

      case GET_UID_STRING:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring; 
         /* set the decode procedure */
         xdr_result   = xdr_wrapstring; 
         break;

      case GET_SIZE:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_int;
         break;

      case GET_MTIME:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_long;
         break;

      case GET_MTIME_STRING:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_wrapstring;
         break;

      case GET_CODEPAGE:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_u_short;
         break;

      case GET_OBJTYPE:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_wrapstring;
         break;

      case GET_FILETYPE:
         /* set the encode procedure */
         xdr_argument = xdr_wrapstring;
         /* set the decode procedure */
         xdr_result   = xdr_wrapstring;
         break;

      case END_SERVER:
         /* set the encode procedure */
         xdr_argument = (xdrproc_t)xdr_void;
         /* set the decode procedure */
         xdr_result   = (xdrproc_t)xdr_void;
         break;

      case EXIT:
         /* we're done.  clean up and exit */
         clnt_destroy(clnt);
         return 1;
         break;

      default:
         /* invalid procedure number entered.  defaulting to NULLPROC */
         printf("Invalid choice.  Issuing NULLRPOC instead.\n");
         procnum = NULLPROC;
         /* set the encode procedure */
         xdr_argument = (xdrproc_t)xdr_void;
         /* set the decode procedure */
         xdr_result   = (xdrproc_t)xdr_void;
         break;

   } /* end of switch(procnum) */

   /* clnt_call(client, procnum, xdr_inproc, in, xdr_outproc, out, timeout) */
   rslt = clnt_call(clnt, procnum, xdr_argument, (char *)&arg, 
                    xdr_result, (char *)&result, tout);

   /* check to make sure clnt_call() succeeded */
   if (rslt != RPC_SUCCESS) {
      /* if clnt_call() failed, print errors and exit */
      printf("An error occurred calling %lu procedure\n", procnum);
      printf("clnt_stat: %d\terrno: %d\n", rslt, errno);
      clnt_destroy(clnt);
      return 1;
   }

   /* clnt_call() succeeded.  switch on procedure and print results */
   switch (procnum) {

      case NULLPROC:
         /* print results and exit */
         printf("NULLRPOC call succeeded\n");
         break;

      case GET_UID:
         /* print results and exit */
         printf("uid of %s: %u\n", 
                filename, result.myapp_get_uid_result);
         break;

      case GET_UID_STRING:
         /* print results and exit */
         printf("owner of %s: %s\n", 
                filename, result.myapp_get_uid_string_result);
         break;

      case GET_SIZE:
         /* print results and exit */
         printf("size of %s: %d\n", 
                filename, result.myapp_get_size_result);
         break;

      case GET_MTIME:
         /* print results and exit */
         printf("last modified time of %s: %ld\n", 
                filename, result.myapp_get_mtime_result);
         break;

      case GET_MTIME_STRING:
         /* print results and exit */
         printf("last modified time of %s: %s\n", 
                filename, result.myapp_get_mtime_string_result);
         break;

      case GET_CODEPAGE:
         /* print results and exit */
         printf("codepage of %s: %d\n", 
                filename, result.myapp_get_codepage_result);
         break;

      case GET_OBJTYPE:
         /* print results and exit */
         printf("object type of %s: %s\n", 
                filename, result.myapp_get_objtype_result);
         break;

      case GET_FILETYPE:
         /* print results and exit */
         printf("file type of %s: %s\n", 
                filename, result.myapp_get_filetype_result);
         break;

      case END_SERVER:
         /* print results and exit */
         printf("Service has been unregistered.\n");
         printf("You must still kill the job in QBATCH\n");
         break;

      default:
         /* we should never get the default case.  */
         /* the previous switch should catch it.   */
         break;

   } /* end of switch(procnum) */


   /* clean up and exit */
   clnt_destroy(clnt);

   return 0;

}

void myapp_print_menu(void) {

   /* print out the procedure choices */
   printf("%.2ld - GET_UID             %.2ld - GET_UID_STRING\n", 
          GET_UID, GET_UID_STRING);
   printf("%.2ld - GET_SIZE            %.2ld - GET_MTIME\n",
          GET_SIZE, GET_MTIME);
   printf("%.2ld - GET_MTIME_STRING    %.2ld - GET_CODEPAGE\n",
          GET_MTIME_STRING, GET_CODEPAGE);
   printf("%.2ld - GET_OBJTYPE         %.2ld - GET_FILETYPE\n",
          GET_OBJTYPE, GET_FILETYPE);
   printf("%.2ld - END_SERVER          %.2d - EXIT\n",
          END_SERVER, EXIT);

}