home *** CD-ROM | disk | FTP | other *** search
-
- /* */
- /* */
- /* Copyright 1987, 1988, 1989 Netwise, Inc. */
- /* All Rights Reserved */
- /* This software contains information which is proprietary to and a trade */
- /* secret of Netwise, Inc. It is not to be used, reproduced, or disclosed */
- /* except as authorized in your license agreement. */
- /* */
- /* Restricted Rights Legend */
- /* Use, duplication, or disclosure by the Government is subject to */
- /* restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in */
- /* Technical Data and Computer Software clause at 252.227-7013, or the */
- /* equivalent Government clause for other agencies. */
- /* Contractor: Netwise, Inc., Boulder, CO 80301 USA */
- /* */
- /* */
-
- #include <stdio.h>
- #include <stdarg.h>
- #include <rpchdr.h>
- #include <nwnet.h>
- #include <signal.h>
-
- #ifdef __TURBOC__
- #pragma warn -par
- #endif
-
- /*
- * Error severity codes (passed to eprt).
- */
- #define NONFATAL 0
- #define FATAL 1
-
- #ifdef SERV_DEF
- #include "serv_def.h" /* get macro definitions from this file */
- #endif
-
- /*
- * Main routine for servers to handle one-shot or persistent
- * connections for a single client at a time.
- */
-
- /* Macro: Dispatcher (Required)
- *
- * The 'Dispatcher' macro is the name of the dispatcher procedure
- * for your RPC server. The name of the dispatcher procedure depends on
- * the interface name given in the RPC specification file, or on the
- * name of your RPC specification file if no interface name was given.
- */
- /*
- #define Dispatcher dispatcher_proc_name
- */
-
- /* Macro: Server_Name (Required)
- *
- * The 'Server_Name' macro must contain the name of your server as it
- * should be registered in your environment. The name clients use to
- * locate the server will be based on this.
- */
- /*
- #define Server_Name "server_name"
- */
-
- /* Macro: Server_Init (Optional)
- *
- * The macro 'Server_Init' may contain code to be executed when the
- * server is started. This may be useful for opening files, or other
- * operations that only need to be done once before any remote procedure
- * calls are serviced. If 'Server_Init' is not defined, no such
- * initialization is performed.
- *
- * Command line arguments can be accessed by using argc and argv.
- */
- /*
- #define Server_Init server_init_routine();
- */
-
- /* Macro: Server_Term (Optional)
- *
- * The macro 'Server_Term' may contain the name of a termination
- * procedure to be called when the server encounters an error. If
- * present, this routine, will be called with the code of the most
- * recent error, or zero if the server is terminating normally. If
- * not defined, the server just calls exit with an appropriate code.
- */
- /*
- #define Server_Term term_routine_name
- */
-
- /* Macro: Poll_Loop (Optional)
- *
- * The macro 'Poll_Loop' may contain code to be executed from within
- * the server's polling loop. This code is placed at the end of the
- * polling loop and can be used to insert delays or to poll for
- * additional events.
- */
- /*
- #define Poll_Loop poll_loop_routine();
- */
-
- /* Macro: Server_Loop (Optional)
- *
- * The macro 'Server_Loop' may contain code to be executed from
- * within the server's primary loop. This code is executed prior to
- * accepting the next client connection. It can be used to allocate
- * resources in preparation for this client's connection.
- */
- /*
- #define Server_Loop server_loop_routine();
- */
-
- /* Macro: Dispatcher_Loop (Optional)
- *
- * The macro 'Dispatcher_Loop' may contain code to be executed from
- * within the server's primary loop. This code is executed prior to
- * servicing the next remote procedure and can be used to allocate
- * resources in preparation for this remote procedure.
- */
- /*
- #define Dispatcher_Loop dispatcher_loop_routine();
- */
-
- /* Macro: DEBUG (Optional)
- *
- * The following define controls the inclusion of optional debugging code
- * within the server. If defined, various debugging messages will be
- * printed to 'stderr' as the server executes.
- */
- /*
- #define DEBUG
- */
-
- /* Macro: DPRT (Optional)
- *
- * The DPRT macro may be defined if you want to use your own "dprt" routine.
- * The default routine in this file prints a debug message to stderr. In
- * certain environments it may be desirable to generate this output through
- * some other means. If the default "dprt" is used, it is only enabled if
- * DEBUG is defined.
- */
- /*
- #define DPRT
- */
-
- /* Macro: EPRT (Optional)
- *
- * The EPRT macro may be defined to replace the default error handler with
- * your own. The default routine prints a message to stderr.
- */
- /*
- #define EPRT
- */
-
- /* Variable: shut_down (Optional)
- *
- * Set this variable from within a remote procedure to tell the main
- * routine to shutdown gracefully after the current RPC call is serviced.
- */
- int shut_down = 0;
-
- /* Variable: _scp_v2r1_ (Required)
- *
- * This variable is used to insure that compatible pieces are linked
- * together. It is not referenced during execution.
- */
- int _scp_v2r1_ = 0;
-
- /*
- * Exit codes used by servers
- */
- #define EXIT_OK 0 /* normal termination */
- #define EXIT_ERR 1 /* an error occurred */
-
- /*ARGSUSED*/
- main(argc, argv)
- int argc;
- char *argv[];
- {
- void finish(), dprt();
- int eprt();
- struct nl_info info;
- connection_id lid, aid;
- network_addr adx;
- struct dscp_t dscp;
- int erc;
- int ch;
-
- if ( (erc = nl_init(&info)) != 0 ) {
- if (eprt("nl_init", FATAL, erc, &dscp, __LINE__))
- finish(erc);
- }
-
- if ( (erc = nl_open(&lid)) != 0 ) {
- if (eprt("nl_open", FATAL, erc, &dscp, __LINE__))
- finish(erc);
- }
-
- adx.len = info.addr_len;
- if ( (adx.value = _allo_(adx.len)) == NULL ) {
- eprt("malloc", FATAL, -1, &dscp, __LINE__);
- finish(-1);
- }
-
- if ( (erc = nl_getaddr(adx.value, &adx.len)) != 0 ) {
- if (eprt("nl_getaddr", FATAL, erc, &dscp, __LINE__))
- finish(erc);
- }
-
- #ifndef Server_Interrupt_Control
- /*
- * The default server interrupt code for DOS sets up the program
- * to ignore the control-C interrupt. This prevents uncontrolled
- * program termination. The server can then be directed to perform an
- * orderly shutdown by pressing the ESC key.
- * If this default server interrupt code is not desired,
- * Server_Interrupt_Control should be defined.
- */
- printf("Press ESC key to shut down the server:\n");
- signal(SIGINT, SIG_IGN);
- #endif
-
- #ifdef Server_Init
- Server_Init /* server-specific initialization code */
- #endif
-
- dprt("Registering");
- erc = nl_register(Server_Name, adx.value, &adx.len, lid);
- if ( erc != 0 ) {
- if (eprt("nl_register", FATAL, erc, &dscp, __LINE__))
- finish(erc);
- }
-
- while ( shut_down == 0 ) {
-
- #ifdef Server_Loop
- Server_Loop
- #endif
- dprt("Waiting for a connection");
-
- for (;;) {
- struct nl_stats stat;
-
- if ( (erc = nl_status(lid, &stat)) != 0 ) {
- if (eprt("nl_status",FATAL,erc,&dscp,__LINE__)){
- nl_close(lid);
- finish(erc);
- }
- }
- if (stat.read_ready == 1)
- break;
-
- #ifndef Server_Interrupt_Control
- /*
- * The server can be directed to perform an orderly
- * shutdown by pressing the ESC key.
- * If this default server interrupt code is not desired,
- * Server_Interrupt_Control should be defined.
- */
- #define ESCKEY '\033'
- if (kbhit() && (ch=getch()) == ESCKEY) {
- dprt("Server shutting down\n");
- nl_close(lid);
- finish(erc);
- }
- #endif
-
- #ifdef Poll_Loop
- Poll_Loop
- #endif
- }
-
- if ( (erc = nl_open(&aid)) != 0 ) {
- if (eprt("nl_open", FATAL, erc, &dscp, __LINE__)) {
- nl_close(lid);
- finish(erc);
- }
- }
-
- if ( (erc = nl_accept(lid, aid, NULL, NULL)) != 0 ) {
- if (eprt("nl_accept", FATAL, erc, &dscp, __LINE__)) {
- nl_close(lid);
- nl_close(aid);
- finish(erc);
- }
- }
- dprt("Connection accepted");
-
- /*
- * Accept RPC calls on this connection until DSCP_CLOSE
- * or DSCP_ABORT is set or an error occurs.
- */
- do {
-
- #ifdef Dispatcher_Loop
- Dispatcher_Loop
- #endif
- dscp.iflags = dscp.cflags = 0L;
-
- if ( (erc = Dispatcher( lid, &dscp )) != 0 ) {
- if (eprt("dispatcher", NONFATAL, erc, &dscp, __LINE__)) {
- nl_close(lid);
- nl_close(aid);
- finish(erc);
- }
- }
- } while ((dscp.cflags & (DSCP_CLOSE|DSCP_ABORT)) == 0 &&
- !shut_down);
-
- if ( dscp.cflags & DSCP_ABORT ) {
- if ( (erc = nl_abort( lid )) != 0 ) {
- if (eprt("nl_abort", FATAL, erc, &dscp, __LINE__)) {
- nl_close(aid);
- finish(erc);
- }
- }
- } else if ( dscp.cflags & DSCP_CLOSE ) {
- if ( (erc = nl_close( lid )) != 0 ) {
- if (eprt("nl_close", FATAL, erc, &dscp, __LINE__)) {
- nl_close(aid);
- finish(erc);
- }
- }
- }
- lid = aid;
- dprt("Connection terminated");
- }
-
- dprt("Server shutting down");
- if ( (erc = nl_close( aid )) != 0 ) {
- if (eprt("nl_close", FATAL, erc, &dscp, __LINE__))
- finish(erc);
- }
-
- finish(0);
- }
-
- void
- finish(error)
- int error;
- {
- #ifdef Server_Term
- Server_Term(error);
- #endif
-
- /*
- * Exit here with a reasonable code in case the user didn't
- * didn't define Server_Term or didn't call exit there.
- */
- exit( error ? EXIT_ERR : EXIT_OK );
- }
-
- #ifndef EPRT
- /*ARGSUSED*/
- int
- eprt(func, severity, error, dscp, line)
- char *func;
- int severity;
- int error;
- struct dscp_t *dscp;
- int line;
- {
- /*
- * Errors can be downgraded from FATAL to NONFATAL if the error
- * occurred in a Network Library routine, and the error code we
- * got indicates an "informational" error.
- */
- if (severity == FATAL) {
- if ((strncmp(func, "nl_", 3) == 0) && ((error & 1) == 0))
- severity = NONFATAL;
- }
-
- (void) fprintf(stderr, "%s failed (%d) on line %d -- %s\n",
- func, error, line,
- severity == FATAL ? "fatal" : "non-fatal");
-
- return severity;
- }
- #endif
-
- #ifndef DPRT
- /*VARARGS0*/
- void
- dprt(char *format, ...)
- {
- #ifdef DEBUG
- va_list args;
-
- va_start(args,format);
- (void) vfprintf(stderr, format, args);
- (void) fputc('\n', stderr);
- va_end(args);
- #endif
- }
- #endif
-