/* ** File name: GETSYI_PROC_A.C ** ** Copyright (c) 1993, by ** Process Software Corporation ** Framingham, Massachusetts */ /* ** Include files */ #include #include #include "TCPWARE_INCLUDE:RPC.H" #include "GETSYI.H" #include "GETSYI_DEF.H" #define NO_UDPA_XPRTS 4 /* # UDP receives (threads) */ #define NO_TCPA_XPRTS 2 /* # TCP listens (threads) */ #define UDPA_CACHE_SIZE 10 /* # entries in XID cache */ /* ** Declare Functions */ extern thread_info *parse_rpc_args(); extern void encode_rpc_res(), free_rpc_res(); static void getsyi_done_ast(), getsyi_prog_1(), send_rpc_res(); /* **************************************** ** ** Main program ** ** Abstract: ** This is the main program for the asynchronous version of the GETSYI ** server. Unlike the synchronous version, this server enables the XID ** cache. Only the results of GETSYI_PROC_1 are cached. */ main() { int i; byte *cache; /* address of XID cache */ SVCXPRT *udpa_xprts[ NO_UDPA_XPRTS]; /* save all server handles */ SVCXPRT *tcpa_xprts[ NO_TCPA_XPRTS]; /* save all server handles */ word port, chan; reply_id reqlst[] = {{GETSYI_PROG, GETSYI_VERS_1, GETSYI_PROC_1}, {0, 0, 0}}; /* ** The server will use non-privileged ports. */ oncrpc_set_char( RPCCHAR__DEFPORTS, &RPCPORTS__NORMAL); /* ** Remove any previous mapping of this program and version to a port. */ pmap_unset( GETSYI_PROG, GETSYI_VERS_1); /* ** Create the transports and register them with the Port Mapper. The server ** uses a channel and listens on a port assigned by the RPC library. The ** channel is saved so that all of the UDPA transports will use the same ** channel (and port). The port is not saved since svcudpa_create ignores ** the port if a channel is specified. All of a server's UDPA transports ** must use the same channel. If this is not done, the XID and active caches ** are useless. If desired, the size of the active cache may be changed before ** this loop. Once a UDPA transport is created, the size of the active cache ** may not be changed until all UDPA transports are destroyed. */ port = RPC_ANYPORT; chan = RPC_ANYCHAN; cache = 0; for( i = 0; i < NO_UDPA_XPRTS; i++) { udpa_xprts[i] = svcudpa_create( chan, port); if( udpa_xprts[i] == NULL) { fprintf( stderr, "cannot create udpa service.\n"); exit( SS$_OPINCOMPL); } chan = svc_getchan( udpa_xprts[0]); /* all xprts use same chan */ cache = svcudpa_enablecache( udpa_xprts[i], cache, UDPA_CACHE_SIZE, &reqlst); } if( !svc_register( udpa_xprts[0], GETSYI_PROG, GETSYI_VERS_1, getsyi_prog_1, IPPROTO_UDP)) { fprintf( stderr, "unable to register (GETSYI_PROG, GETSYI_VERS_1, UDP).\n"); exit( SS$_OPINCOMPL); } /* ** The call to svctcpa_create specifies a zero channel on first call (chan ** on subsequent calls is obtained from first server handle). The port is ** RPC_ANYPORT on the first call to use a port assigned by the RPC library. On ** subsequent calls, use the port is ignored (since chan is specified). We ** don't enable a XID cache. */ port = RPC_ANYPORT; /* use library assigned port */ chan = RPC_ANYCHAN; for( i = 0; i < NO_TCPA_XPRTS; i++) { tcpa_xprts[i] = svctcpa_create( chan, port, 0, 0); if( tcpa_xprts[i] == NULL) { fprintf( stderr, "cannot create tcp service.\n"); exit( SS$_OPINCOMPL); } chan = svc_getchan( tcpa_xprts[0]); /* all xprts on same chan */ } if( !svc_register( tcpa_xprts[0], GETSYI_PROG, GETSYI_VERS_1, getsyi_prog_1, IPPROTO_TCP)) { fprintf( stderr, "unable to register (GETSYI_PROG, GETSYI_VERS_1, TCP).\n"); exit( SS$_OPINCOMPL); } /* ** For UDPA and TCPA transports, call SYS$HIBER instead of svc_run. */ sys$hiber(); /* ** NOTE: The remainder of the code in this main program is never executed. ** The code is included to show how the asynchronous transports are ** destroyed. To execute this code, a new RPC procedure must be added. ** The arguments and results of this procedure would be void (as with ** the NULL procedure). The procedure would simply call SYS$WAKE to ** cancel the hibernation. ** ** NOTE: svcudpa_shutdown behaves differently than svctcpa_shutdown. */ printf( "The GETSYI server is exiting\n"); svc_unregister( GETSYI_PROG, GETSYI_VERS_1); svcudpa_shutdown( udpa_xprts[0]); /* call this once */ for( i = 0; i < NO_UDPA_XPRTS; i++) { svc_destroy( udpa_xprts[i]); /* call this for each transport */ udpa_xprts[i] = 0; } svcudpa_freecache( cache); svctcpa_shutdown( tcpa_xprts[0]); /* call this once */ for( i = 0; i < NO_TCPA_XPRTS; i++) { svc_destroy( tcpa_xprts[i]); tcpa_xprts[i] = 0; } exit( SS$_NORMAL); } /* end the main program */ /* **************************************** ** ** Function: getsyi_prog_1() ** ** Abstract: ** The dispatch routine for the asynchronous GETSYI server. */ static void getsyi_prog_1( rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp; { getsyi_args *argument; /* RPC arguments in local form */ bool_t (*xdr_argument)(); /* xdr function to convert arguments */ /* xdr_result is not needed */ char *(*local)(); switch( rqstp->rq_proc) { case NULLPROC: svc_sendreply( transp, xdr_void, NULL); return; case GETSYI_PROC_1: /* results will be handled later */ xdr_argument = xdr_getsyi_args; local = (char *(*)()) getsyi_proc_1_1; break; default: svcerr_noproc( transp); return; } /* ** Convert the arguments from the XDR format to the VAX format. */ if( (argument = get_vm( sizeof( *argument))) == 0) svcerr_systemerr(transp); bzero( argument, sizeof( *argument)); if( !svc_getargs( transp, xdr_argument, argument)) { svcerr_decode( transp); return; } (*local)( argument, rqstp); /* call the routine */ /* ** Unlike the synchronous servers, the code to send the reply to the client ** is handled by each procedure, not by this dispatch routine. */ return; } /* end function getsyi_prog_1() */ /* **************************************** ** ** Function: getsyi_proc_1_1() ** ** Abstract: ** This routine converts the VAX format RPC arguments into the form GETSYI ** expects, calls SYS$GETSYI, and returns if this was successful. If not, ** the error code and its message are sent to the client. ** ** Refer to the DEC VMS documentation for information about the SYS$GETSYI ** system service. ** ** Return value: ** Unlike the synchronous version, this routine does not return a value. ** The routine is defined as it is because of the GETSYI.H header file. */ getsyi_res *getsyi_proc_1_1( argsp, rqstp) getsyi_args *argsp; struct svc_req *rqstp; { /* ** This version of the server cannot use a set of static variables to hold ** the results that will be sent to the client. */ DSC *node; thread_info *ti; /* ** Convert the strings that the client sent into the integers that GETSYI ** expects. This function also sets up other information that will be used ** when converting the results into string to send to the client. */ if( (ti = parse_rpc_args( argsp)) == 0) { svcerr_systemerr( rqstp->rq_xprt); if( !svc_freeargs( rqstp->rq_xprt, xdr_getsyi_args, argsp)) fprintf( stderr, "unable to free arguments\n"); return( 0); /* done with this request */ } ti->ti_xprt = rqstp->rq_xprt; /* save the server handle for later */ ti->ti_rqstp = rqstp; /* save the request pointer */ ti->ti_args = argsp; /* save the arguments */ /* ** If the client did not send a node string, pass a NULL pointer to SYS$GETSYI. */ if( ti->ti_node.dsc$w_length == 0) node = 0; else node = &ti->ti_node; /* ** If parse_rpc_args returned a successful status in ti->ti_results.gsr_status, ** then call SYS$GETSYI. If the call to SYS$GETSYI is successful, the AST ** routine (getsyi_done_ast) will send the results to the client. */ _success( ti->ti_results.gsr_status) { ti->ti_results.gsr_status = sys$getsyi( 0, 0, node, ti->ti_getsyi_args, &ti->ti_iosb, getsyi_done_ast, ti); _success( ti->ti_results.gsr_status) return( 0); /* done for now, wait for AST to execute */ } send_rpc_res( ti); /* send the error code */ return( 0); } /* end function getsyi_proc_1_1() */ /* **************************************** ** ** Function: getsyi_done_ast() ** ** Abstract: ** This is the AST routine that is called when SYS$GETSYI completes. It ** saves the status code and sends the results to the client. */ void getsyi_done_ast( ti) thread_info *ti; { /* ** If SYS$GETSYI returned an error, don't send it to the client a second time. */ _error( ti->ti_results.gsr_status) return; ti->ti_results.gsr_status = ti->ti_iosb.val[0]; /* Save the status */ send_rpc_res( ti); } /* end function getsyi_done_ast() */ /* **************************************** ** ** Function: send_rpc_res() ** ** Abstract: ** This routine converts the SYS$GETSYI results into VAX format RPC ** results and sends them to the client. Although this routine is ** usually called as an AST, it may use TCP or UDP since svc_sendreply ** and svcerr_systemerr are asynchronous (they do not use the socket ** library.) */ void send_rpc_res( ti) thread_info *ti; { encode_rpc_res( ti, 0); if( !svc_sendreply( ti->ti_xprt, xdr_getsyi_res, &ti->ti_results)) svcerr_systemerr( ti->ti_xprt); if( !svc_freeargs( ti->ti_xprt, xdr_getsyi_args, ti->ti_args)) fprintf( stderr, "unable to free arguments\n"); free_rpc_res( &ti->ti_results); free_vm( ti->ti_args); free_vm( ti); } /* end function send_rpc_res() */ /* end file GETSYI_PROC_A.C */