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.
#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); }