Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
DCE for the HP e3000: HP e3000 MPE/iX Computer Systems

Chapter 7 Programming with RPC 1.2.1 on MPE/iX

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Index

This chapter explains the RPC application programming with a small example. The example consists of server and client components. The client makes a RPC request to the server and asks the server to sleep for a specified amount of time. The server serves this request from the client by going to sleep for the time given by the client.

/*                                         client.c ************************************************************************************ * This is the sleeper client program.It takes two arguments, a hostname to contact * for the server and a number of seconds to sleep. The client locates the server * using the hostname provided and the endpoint mapper on the server's host -- the  * client does not contact the name service for server location information. The  * client uses the explicit binding method, so it uses th hostname argument to  * construct a binding handle (rpc_binding_handle_t).The client passes this binding * handle to the invocation of the remote procedure.************************************************************************************ *//* * (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co. *//* * @(#)HP DCE/3000 @(#)Module: client.c */#include          <stdlib.h>                    /* Standard POSIX defines */#include          <strings.h>                   /* str*() routines */#include          <stdio.h>                     /* Standard IO library */#include          <dce/dce_error.h>             /* DCE error facility */#include          <pthread.h>                   /* DCE Pthread facility */#include          "common.h"                    /* Common defs for this app */#include          "sleeper.h"                   /* Output from sleeper.idl */#ifdef    TRACINGtr_handle_t       *tr_handle = NULL;            /* Initialize for client */#endif                                          /* TRACING */
void main(int argc, char *argv[]){    rpc_binding_handle_tbh;                     /* "points" to the server */    error_status_t          st, _ignore;        /* returned by DCE calls */    dce_error_string_t      dce_err_string;     /* text describing error code */    ndr_char                *string_binding;    /* used to create binding */    unsigned long           sleep_time;         /* seconds server will sleep */    unsigned_char_t         *netaddr;           /* network address of server */#ifdef    TRACING    /* tr_init() --     *      * The tr_init call initializes the trace facility.  The first parameter     * is the name of an environment variable to consult to determine the     * values for the selector levels, output filename, etc.  These values     * can have defaults assigned in the second and third parameters, but     * this sample application does not choose to do this.  The trace_name     * parameter is a prefix string that will appear on each line of output     * to distinguish tracing from this application from other applications.     */    if (tr_handle == NULL) {        tr_handle = tr_init("TR_SLEEPER",       /* environment variable name */                             NULL,              /* selector level defaults */                             NULL,              /* filename for output */                             trace_name);       /* prefix string in output */   if (tr_handle == NULL) {	    /* 	     * Still NULL -- unable to initialize tracing.  This may cause	     * the following tr_printmsg calls (via PRINT_FUNC) to fail.	     */	    fprintf(stderr, "Unable to initialize tracing interface!\n");   } }#endif /* TRACING */if (argc != 3) {         ifprintf(stderr, "Usage: %s hostname sleep_time\n", argv[0]);         exit(1);    } else {         netaddr = (unsigned_char_t *)argv[1];         sleep_time = atoi(argv[2]);    }    /*    rpc_string_binding_compose() --     *      * Create a string binding using the command line hostname parameter.  A     * string binding must be converted into a binding handle, required by     * the DCE runtime, before it can be used.     *      * The first parameter is an optional object UUID.  This application does     * not use multiple object UUIDs, so none is supplied.  The second     * parameter is the protocol sequence to use to establish a connection;     * the "ip" parameter selects the UDP/IP protocol.  The third parameter is     * the network address of the server; this was specified on the command     * line either as a hostname or as an IP address.     *      * The fourth parameter is an endpoint value (IP port number) to use; you     * should only specify this when creating a string binding if the     * endpoint is well-known.  Most servers use a dynamic endpoint, chosen     * when the server starts up; so specify a value of NULL to cause the     * RPC runtime to determine the value during the RPC setup.  The fifth     * parameter is for network options.     *      * The sixth parameter is the return argument where the string binding     * will be stored.  New memory will be allocated for this return value;     * it must be freed later by this application.  The final parameter is a     * DCE return status which will be checked for errors.     */    rpc_string_binding_compose(NULL,           /* no object UUID */                            (unsigned_char_t *)"ip",  /* protocol to use */                             netaddr,          /* network addr of server */                             NULL,             /* use a dynamic endpoint */                             NULL,             /* misc. network options */                             &string_binding,  /* returned string binding */                             &st);             /* error status for this call */    if (st != rpc_s_ok) {           /*       dce_error_inq_text() --            *             * Inquire about the error status returned by the previous DCE call.            *             * The first parameter to this call is a DCE error_status_t presumed            * to have been returned by a preceeding DCE call.  The second            * parameter is a string long enough to hold the longest possible            * DCE error string -- the data type dce_error_string_t is defined            * to be a character array of this length.  The third parameter is            * another dce error status; this call is unlikely to fail so its            * status is ignored.            */           dce_error_inq_text(st, dce_err_string, (int *)&_ignore);           PRINT_FUNC(PRINT_HANDLE, "Cannot compose string binding: %s\n",                 dce_err_string);           exit(1);    }    /*    rpc_binding_from_string_binding() --     * Create a binding handle structure from the string binding.  The     * client stub function needs a binding handle; it cannot use the string     * binding form created above.     *      * The first parameter to this call is the string binding generated     * earlier.  The second parameter is an RPC binding handle structure;     * a new binding handle will be allocated and stored here -- this     * application must free the storage when it is done with it.  The third     * parameter is the DCE return status.     */    rpc_binding_from_string_binding(string_binding,     /* created above */                                  &bh,                  /* allocated and returned */                                  &st);                 /* error status for this call */    if (st != rpc_s_ok) {    dce_error_inq_text(st, dce_err_string, (int *)&_ignore);    PRINT_FUNC(PRINT_HANDLE, "Cannot get a binding handle: %s\n",           dce_err_string);    exit(1);}/*      * At this point the application is not actually connected to any     * server, but it has all the information needed to establish a     * connection to the remote server.  Connection establishment happens in     * the client stub function called below.     */    PRINT_FUNC(PRINT_HANDLE, "Bound to %s\n", string_binding);    /*    rpc_string_free() --     *      * Free a string allocated by the RPC runtime.  The first parameter is     * the address of a string which was previously allocated (or is NULL).     * It will be free()d, and the space returned to the system for use in     * the future.  The second parameter is the DCE return status.     */    rpc_string_free(&string_binding,                   /* DCE string to free */                    &_ignore);                         /* DCE return status */    PRINT_FUNC(PRINT_HANDLE, "Calling remote_sleep(%d)\n", sleep_time);    /*    TRY --     *      * The macro TRY is used to wrap a call which may result in a DCE     * exception being raised.  Any call to an RPC client stub can result in     * an exception being raised if something goes wrong.  Examples of what     * can go wrong include: there is no server listening on the remote     * host; there is a data error in a client or server stub; the server     * raises an exception while executing the procedure call.  If an     * exception is raised and there is no TRY/CATCH block surrounding the     * call, the exception will cause the process to abort and dump core.     * Since this is typically not very helpful, we prefer to catch the     * exception.  In the string_conv and later sample applications the     * client will do something intelligent with the exception.     */    TRY {        /*          * Call the remote procedure passing in the number of seconds to sleep,         * as defined in the .idl file.  A binding handle parameter is required         * since this client uses the explicit binding method.         */         remote_sleep(bh, sleep_time);    /*   CATCH_ALL --     *      * The CATCH_ALL macro denotes the end of a TRY block.  If an exception     * occurs in any of the calls within the TRY block, control will pass to     * the CATCH_ALL block where the exception is dealt with.  This client     * will simply inform you that something went wrong; in the string_conv     * and later sample applications the client will do something     * intelligent with the exception.     */    } CATCH_ALL {        /*          * We caught an exception in the client stub code.  Inform the user.         */         PRINT_FUNC(PRINT_HANDLE, "Caught an exception!\n");         exit(1);    }    /*   ENDTRY --     *      * The ENDTRY macro is required by the exception implementation to     * terminate a TRY block.     */    ENDTRY;    /*      * No status information was passed back.  If the call failed, the RPC     * runtime will have raised an exception and caused an exit.     */    PRINT_FUNC(PRINT_HANDLE, "Returned from remote_sleep(%d)\n", sleep_time);    exit(0);}
/*                             manager.c *************************************************************************** * This is the server-side RPC manager function; this is the function that * actually implements the remote procedure defined in the .idl file.  The * server stub (called by the RPC runtime) calls this function when an RPC * request comes in for this interface. *  * The manager function takes the arguments defined in the .idl file, * performs its function and returns results as defined in the .idl file. * This particular manager function does not return any results (it does not * have any [out] parameters, nor a return value). *************************************************************************** *//* * (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co. *//* * @(#)HP DCE/3000  * @(#)Module: manager.c  */#include         <stdlib.h>                 /* Standard POSIX defines */#include         <stdio.h>                  /* Standard IO library */#include         "common.h"                 /* Common defs for this app */#include         "sleeper.h"                /* Output from sleeper.idl *//* * This particular manager function simply sleeps for the number of seconds * specified by its argument.  Since the .idl file speficies use of explicit * binding, the manager must take a binding handle as its first argument. *  * Note: the code in this manager function must be (and is) reentrant since it * may be running simultaneously in multiple server threads. */
void remote_sleep    (     /* [in] */   handle_t       h,        /* Use explicit binding */     /* [in] */   ndr_long_int   time      /* Seconds to sleep */     ){    PRINT_FUNC(PRINT_HANDLE, "Enter remote_sleep(%d) manager\n", time);    /*      * This is a mind-numbingly simple manager ...      */    (void) sleep (time);    PRINT_FUNC(PRINT_HANDLE, "Return from remote_sleep(%d) manager\n", time);    return;}/*                             server.c *************************************************************************** * This is the server program for the basic sleeper sample application.  It * will register the interface named "sleeper" with the local RPC runtime * and with the endpoint mapper daemon (rpcd) on the local host.  It then * listens for incoming requests and serves each request in a separate * thread.  The manager function (see manager.c) is invoked to serve the * requests after the inbound arguments are unmarshalled. *************************************************************************** *//* * (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co. *//* * @(#)HP DCE/3000  * @(#)Module: server.c  
*/#include <pthread.h> /* POSIX threads facility */#include <stdlib.h> /* Standard POSIX defines */#include <strings.h> /* str*() routines */#include <stdio.h> /* Standard IO library */#include <dce/dce_error.h> /* DCE error facility */#include "common.h" /* Common defs for this app */#include "sleeper.h" /* Output from sleeper.idl */#ifdef TRACINGtr_handle_t * tr_handle = NULL; /* Initialize for server */#endif /* TRACING */void main(int argc, char *argv[]){ rpc_binding_vector_t *bvec; /* used to register w/runtime */ error_status_t st, _ignore; /* returned by DCE calls */ dce_error_string_t dce_err_string; /* text describing error code */ ndr_char *string_binding; /* printable rep of binding */ int i; /* index into bvec */#ifdef TRACING /* * Initialize tracing. */ if (tr_handle == NULL) { char trace_name_buf[40]; /* * Construct the tracing prefix string from the trace_name constant * and the current process id. This allows multiple servers on the * same host to differentiate themselves from each other. */ sprintf(trace_name_buf, "%s-%d", trace_name, getpid()); tr_handle = tr_init("TR_SLEEPER", /* environment variable name */ NULL, /* selector level defaults */ NULL, /* filename for output */ trace_name_buf); /* prefix string in output */ if (tr_handle == NULL) { /* * Still NULL -- unable to initialize tracing. This may cause * the following tr_printmsg calls (via PRINT_FUNC) to fail. */ fprintf(stderr, "Unable to initialize tracing interface!\n"); } }#endif /* TRACING */ /* rpc_server_use_protseq() -- * * Specify the protocol sequences that the RPC runtime should use when * creating endpoints. The first parameter is a string representation * of a protocol sequence to use. The second parameter is the maximum * number of concurrent remote procedure call requests that the server * will accept. In the first version of DCE, the second parameter is * always replaced by a default value. The third parameter is the DCE * return status. * * This server uses only the UDP/IP protocol sequence for efficiency * reasons: the UDP transport is more efficient for procedures that are * idempotent and expected to return only small amounts of data. The * reason why we don't simply listen on all protocols and let the client * choose is because it consumes more system resources to listen on * multiple protocol sequences. */ rpc_server_use_protseq((unsigned char *)"ip", /* prot seq to listen on */ rpc_c_protseq_max_calls_default, &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE, "Cannot use protocol sequence ip: %s\n", dce_err_string); exit(1); } /* rpc_server_register_if() -- * * Register the interface definition and manager entry point vector with * the RPC runtime. The first parameter is the interface specification * generated by the IDL compiler; it is declared in the "sleeper.h" file * generated by idl. The second parameter is the manager type UUID to * associate with the third parameter. This application does not use * type UUIDs (an advanced feature). The third parameter is the manager * entry point vector, the array of functions used as implementations * for incoming remote procedure calls. A value of NULL indicates that * the runtime should use the default manager EPV generated by the IDL * compiler. The fourth parameter is the DCE error status. */ rpc_server_register_if(sleeper_v1_0_s_ifspec, /* generated interface spec */ NULL, /* No type UUIDs */ NULL, /* Use supplied epv */ &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE,"Cannot register interface with runtime: %s\n", dce_err_string); exit(1); } /* rpc_server_inq_bindings() -- * * Inquire from the RPC runtime about the bindings that were created in * the registration call above. * * The first parameter is the address of a binding vector data type. * Memory for a new binding vector will be allocated and returned. The * application must later free this memory. The second parameter is the * DCE error status. * * The binding information is required for registration with the * endpoint mapper below. We print it out simply for debugging * purposes. */ rpc_server_inq_bindings(&bvec, /* runtime's binding vector */ &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE, "Cannot get bindings: %s\n", dce_err_string); exit(1); } else PRINT_FUNC(PRINT_HANDLE, "Bindings:\n"); /* * Print out the bindings obtained from the RPC runtime. This info is * only for debugging purposes -- it shows what protocol sequence and * ports have been grabbed by the runtime for this server. */ for (i = 0; i < bvec->count; i++) { /* rpc_binding_to_string_binding() -- * * Convert a binding handle to a string binding for printing. The * first parameter is a binding handle. (In a binding vector there * are bvec->count binding handles). The second parameter is a * pointer to a dce string data type; memory will be allocated and * the value returned in it. The application must free this memory. * The third parameter is the DCE error status. */ rpc_binding_to_string_binding(bvec->binding_h[i], /* a binding handle */ &string_binding, /* returned string form */ &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE, "Cannot get string binding: %s\n", dce_err_string); } else PRINT_FUNC(PRINT_HANDLE, " %s\n", string_binding); /* * Free the memory allocated in rpc_binding_to_string_binding(). */ rpc_string_free(&string_binding, &_ignore); } /* rpc_ep_register() -- * * Register the interface with the endpoint mapper. The first parameter * is the interface specification generated by the IDL compiler. The * second parameter is the binding vector returned by the RPC runtime * describing the endpoints (IP ports) on which this server is listening * for RPC requests. The third parameter is a vector of object UUIDs * that the server offers; this server does not implement multiple * objects so it specifies NULL. The fourth parameter is an annotation * used for informational purposes only. The RPC runtime does not use * this string to determine which server instance a client communicates * with, or for enumerating endpoint map elements. The last parameter * is the DCE error status. * * When this call completes the bindings we established with the RPC, * runtime will be associated with this interface. This allows a client * to look up a server by interface without specifying an endpoint * (port): instead, by contacting the endpoint mapper, a client is able * to locate servers registered using dynamic (system-chosen) endpoints. */ rpc_ep_register(sleeper_v1_0_s_ifspec, /* generated interface spec */ bvec, /* runtime's binding vector */ NULL, /* no objects supported */ (unsigned_char_t *) sleeper_description, &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE, "Cannot register with endpoint map: %s\n", dce_err_string); exit(1); } PRINT_FUNC(PRINT_HANDLE, "Listening...\n"); /* rpc_server_listen() -- * * Listen and handle incoming RPC requests. This call typically does * not return; instead incoming RPC requests will be dispatched to the * manager function(s), each in its own thread. * * The first parameter is the maximum number of concurrently executing * remote procedure calls to allow. The second parameter is the DCE * error status. */ rpc_server_listen(rpc_c_listen_max_calls_default, &st); /* error status for this call */ if (st != rpc_s_ok) { dce_error_inq_text(st, dce_err_string, (int *)&_ignore); PRINT_FUNC(PRINT_HANDLE, "Listen returned with error: %s\n", dce_err_string); } else PRINT_FUNC(PRINT_HANDLE, "Stopped listening...\n"); /************************************************************************ * IMPORTANT NOTE: We will probably never reach here. If you interrupt * the server with an asynchronous signal, such as a ^C (or SIGINT) from * the keyboard or a "kill <PID>" (a SIGTERM signal), it will cause the * process to exit; it will not reach here. See the lookup sample * application for code that is able to properly clean up after the * listen call. ************************************************************************/ PRINT_FUNC(PRINT_HANDLE, "Unregistering endpoints and interface...\n"); /* rpc_ep_unregister() -- * * Unregister the interface and endpoints with the RPC runtime. The * first parameter is the interface specification from the IDL compiler. * The second parameter is the binding vector registered with this * interface. The third parameter is the object UUID vector (NULL since * this application does not support multiple objects). The final * parameter is the DCE error status. */ rpc_ep_unregister(sleeper_v1_0_s_ifspec, /* IDL-generated ifspec */ bvec, /* this server's bindings */ NULL, /* no object UUIDs supported */ &_ignore); /* ignore any errors */ /* rpc_binding_vector_free() -- * Free a binding vector that is no longer needed. Since it was * allocated by the runtime, the application should remember to free it. * The first parameter is the binding vector to free; the second * parameter is the DCE error status, which is ignored. */ rpc_binding_vector_free(&bvec, &_ignore); /* rpc_server_unregister_if() -- * * Unregister this server from the RPC runtime. This is unnecessary * since this process is about to exit, but is here to demonstrate good * programming style. The first parameter is the interface * specification; the second is the manager type UUID (which is NULL * since this application does not support multiple types). The last * parameter is the DCE error status, which is ignored. */ rpc_server_unregister_if(sleeper_v1_0_s_ifspec, /* IDL-generated ifspec */ NULL, /* No object UUID */ &_ignore); /* ignore any errors */ exit(0);}
/*                             common.h *************************************************************************** * This file contains definitions common between the client and server. *************************************************************************** * (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co. *//* * @(#)HP DCE/3000 1.5  * @(#)Module: common.h  
*//* * This string will be registered with the RPC runtime as an annotation * describing the endpoint entry. */# define sleeper_description "sleeper"#ifdef TRACING/* * If you want to use the building blocks tracing facility then define the TRACING
* flag in your compile (put -DTRACING in the Makefile). For this to compile and
* link, you will need the building blocks library installed on your system. */#include <dce/trace_log.h> /* Building blocks tracing */extern tr_handle_t * tr_handle; /* used by client, server *//* * These print functions use the trace/log facility instead of stdio. All print
 * statements in this file use these macros so it's easy to replace use of stdio with 
 * the trace/log facility. The NULL after tr_handle signifies the use of the 500 
 * byte, default buffer for trace output. */# define     RINT_FUNC     tr_printmsg# define     PRINT_HANDLE  tr_handle, NULL/*  * The trace_name string is registered with the trace/log facility as the * name of this application.  It will appear in any tracing output. */# define     trace_name    sleeper_description#else   /* TRACING *//*  * These print functions use stdio instead of the trace/log facility.  They * turn off the tracing macros by replacing them with standard IO routines. */# define     PRINT_FUNC        fprintf# define     PRINT_HANDLE      stdout#endif    /* TRACING */
/*                               sleeper.idl **************************************************************************** * This .idl file declares an interface with a set of remotely-callable * procedures.  This file is compiled by the idl compiler into a C interface * declaration (.h) and a C client stub (_cstub.c) and server stub * (_sstub.c) that interface with the RPC runtime.  You must write a manager * for this procedure (see manager.c) and the client and server main() * functions (see client.c and server.c). ****************************************************************************//* * (c) Copyright 1992, 1993, 1994 Hewlett-Packard Co. *//* * @(#)HP DCE/3000  * @(#)Module: sleeper.idl  *//*  * This definition declares the interface for this application and * associates it with a globally (universally) unique identifier, or UUID. * The RPC runtime uses the UUID to identify this interface.  If you * leverage this code, BE SURE TO CHANGE THE UUID!  Do this by running the * program "uuidgen" and putting the uuidgen output in place of the one * supplied.  Failure to do this may cause bizarre results. */[uuid(D0FCDD70-7DCB-11CB-BDDD-08000920E4CC),      /* NOTE: CHANGE THIS!!! */ version(1.0)]interface sleeper{    void remote_sleep         (         [in] handle_t	    h,          /* Use explicit binding */         [in] long        time        /* Seconds to sleep */         );}
Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© Hewlett-Packard Development Company, L.P.