mirror of
https://git.openafs.org/openafs.git
synced 2025-01-18 15:00:12 +00:00
4fee9a2f9e
Get rid of some remaining references to bcopy, bzero, and bcmp. In a
few places (such as ka-forwarder.c, and linked_list.c), these were
being called without including strings.h, which causes errors on AIX
when using the clang-based xlc 17.1 compiler.
Remove references even inside comments or documentation, to make it
easier to make sure they've all been removed.
Leave some references inside platform-specific or kernel code, since
those are more likely to need bcopy() et al, and tend to only impact
that platform.
Note that most references to bcopy() et al were removed by commit
c5c521af0e
(convert-from-bsd-to-posix-string-and-memory-functions-20010807).
Change-Id: I28d1b139348c2a4b2259a259de0c93997c684c40
Reviewed-on: https://gerrit.openafs.org/15432
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
6420 lines
275 KiB
C
6420 lines
275 KiB
C
/*!
|
||
* \addtogroup rxrpc-spec RX RPC Specification
|
||
* RX RPC Specification
|
||
* @{
|
||
*
|
||
* \mainpage AFS-3 Programmer's Reference: Specification for the Rx Remote
|
||
* Procedure Call Facility
|
||
*
|
||
* AFS-3 Programmer's Reference:
|
||
*
|
||
* Specification for the Rx Remote Procedure Call Facility
|
||
* \author Edward R. Zayas
|
||
* Transarc Corporation
|
||
* \version 1.2
|
||
* \date 28 August 1991 10:11 .cCopyright 1991 Transarc Corporation All Rights
|
||
* Reserved FS-00-D164
|
||
*
|
||
* \page chap1 Chapter 1 -- Overview of the Rx RPC system
|
||
*
|
||
* \section sec1-1 Section 1.1: Introduction to Rx
|
||
*
|
||
* \par
|
||
* The Rx package provides a high-performance, multi-threaded, and secure
|
||
* mechanism by which
|
||
* remote procedure calls (RPCs) may be performed between programs executing
|
||
* anywhere in a
|
||
* network of computers. The Rx protocol is adaptive, conforming itself to
|
||
* widely varying
|
||
* network communication media. It allows user applications to define and
|
||
* insert their own
|
||
* security modules, allowing them to execute the precise end-to-end
|
||
* authentication algorithms
|
||
* required to suit their needs and goals. Although pervasive throughout the
|
||
* AFS distributed
|
||
* file system, all of its agents, and many of its standard application
|
||
* programs, Rx is entirely
|
||
* separable from AFS and does not depend on any of its features. In fact, Rx
|
||
* can be used to build applications engaging in RPC-style communication under
|
||
* a variety of unix-style file systems. There are in-kernel and user-space
|
||
* implementations of the Rx facility, with both sharing the same interface.
|
||
* \par
|
||
* This document provides a comprehensive and detailed treatment of the Rx RPC
|
||
* package.
|
||
*
|
||
* \section sec1-2 Section 1.2: Basic Concepts
|
||
*
|
||
* \par
|
||
* The Rx design operates on the set of basic concepts described in this
|
||
* section.
|
||
*
|
||
* \subsection sec1-2-1 Section 1.2.1: Security
|
||
*
|
||
* \par
|
||
* The Rx architecture provides for tight integration between the RPC mechanism
|
||
* and methods for making this communication medium secure. As elaborated in
|
||
* Section 5.3.1.3 and illustrated by the built-in rxkad security system
|
||
* described in Chapter 3, Rx defines the format for a generic security module,
|
||
* and then allows application programmers to define and activate
|
||
* instantiations of these modules. Rx itself knows nothing about the internal
|
||
* details of any particular security model, or the module-specific state it
|
||
* requires. It does, however, know when to call the generic security
|
||
* operations, and so can easily execute the security algorithm defined. Rx
|
||
* does maintain basic state per connection on behalf of any given security
|
||
* class.
|
||
*
|
||
* \subsection sec1-2-2 Section 1.2.2: Services
|
||
*
|
||
* \par
|
||
* An Rx-based server exports services, or specific RPC interfaces that
|
||
* accomplish certain tasks. Services are identified by (host-address,
|
||
* UDP-port, serviceID) triples. An Rx service is installed and initialized on
|
||
* a given host through the use of the rx NewService() routine (See Section
|
||
* 5.6.3). Incoming calls are stamped with the Rx service type, and must match
|
||
* an installed service to be accepted. Internally, Rx services also carry
|
||
* string names which identify them, which is useful for remote debugging and
|
||
* statistics-gathering programs. The use of a service ID allows a single
|
||
* server process to export multiple, independently-specified Rx RPC services.
|
||
* \par
|
||
* Each Rx service contains one or more security classes, as implemented by
|
||
* individual security objects. These security objects implement end-to-end
|
||
* security protocols. Individual peer-to-peer connections established on
|
||
* behalf of an Rx service will select exactly one of the supported security
|
||
* objects to define the authentication procedures followed by all calls
|
||
* associated with the connection. Applications are not limited to using only
|
||
* the core set of built-in security objects offered by Rx. They are free to
|
||
* define their own security objects in order to execute the specific protocols
|
||
* they require.
|
||
* \par
|
||
* It is possible to specify both the minimum and maximum number of lightweight
|
||
* processes available to handle simultaneous calls directed to an Rx service.
|
||
* In addition, certain procedures may be registered with the service and
|
||
* called at specific times in the course of handling an RPC request.
|
||
*
|
||
* \subsection sec1-2-3 Section 1.2.3: Connections
|
||
*
|
||
* \par
|
||
* An Rx connection represents an authenticated communication path, allowing a
|
||
* sequence of multiple asynchronous conversations (calls). Each connection is
|
||
* identified by a connection ID. The low-order bits of the connection ID are
|
||
* reserved so that they may be stamped with the index of a particular call
|
||
* channel. With up to RX MAXCALLS concurrent calls (set to 4 in this
|
||
* implementation), the bottom two bits are set aside for this purpose. The
|
||
* connection ID is not sufficient to uniquely identify an Rx connection by
|
||
* itself. Should a client crash and restart, it may reuse a connection ID,
|
||
* causing inconsistent results. Included with the connection ID is the epoch,
|
||
* or start time for the client side of the connection. After a crash, the next
|
||
* incarnation of the client will choose a different epoch value. This will
|
||
* differentiate the new incarnation from the orphaned connection record on the
|
||
* server side.
|
||
* \par
|
||
* Each connection is associated with a parent service, which defines a set of
|
||
* supported security models. At creation time, an Rx connection selects the
|
||
* particular security protocol it will implement, referencing the associated
|
||
* service. The connection structure maintains state for each individual call
|
||
* simultaneously handled.
|
||
*
|
||
* \subsection sec1-2-4 Section 1.2.4: Peers
|
||
*
|
||
* \par
|
||
* For each connection, Rx maintains information describing the entity, or
|
||
* peer, on the other side of the wire. A peer is identified by a (host,
|
||
* UDP-port) pair, with an IP address used to identify the host. Included in
|
||
* the information kept on this remote communication endpoint are such network
|
||
* parameters as the maximum packet size supported by the host, current
|
||
* readings on round trip time and retransmission delays, and packet skew (see
|
||
* Section 1.2.7). There are also congestion control fields, including
|
||
* retransmission statistics and descriptions of the maximum number of packets
|
||
* that may be sent to the peer without pausing. Peer structures are shared
|
||
* between connections whenever possible, and, hence, are reference-counted. A
|
||
* peer object may be garbage-collected if it is not actively referenced by any
|
||
* connection structure and a sufficient period of time has lapsed since the
|
||
* reference count dropped to zero.
|
||
*
|
||
* \subsection sec1-2-5 Section 1.2.5: Calls
|
||
*
|
||
* \par
|
||
* An Rx call represents an individual RPC being executed on a given
|
||
* connection. As described above, each connection may have up to RX MAXCALLS
|
||
* calls active at any one instant. The information contained in each call
|
||
* structure is specific to the given call.
|
||
* \par
|
||
* "Permanent" call state, such as the call number, is maintained in the
|
||
* connection structure itself.
|
||
*
|
||
* \subsection sec1-2-6 Section 1.2.6: Quotas
|
||
*
|
||
* \par
|
||
* Each attached server thread must be able to make progress to avoid system
|
||
* deadlock. The Rx facility ensures that it can always handle the arrival of
|
||
* the next unacknowledged data packet for an attached call with its system of
|
||
* packet quotas. A certain number of packets are reserved per server thread
|
||
* for this purpose, allowing the server threads to queue up an entire window
|
||
* full of data for an active call and still have packet buffers left over to
|
||
* be able to read its input without blocking.
|
||
*
|
||
* \subsection sec1-2-7 Section 1.2.7: Packet Skew
|
||
*
|
||
* \par
|
||
* If a packet is received n packets later than expected (based on packet
|
||
* serial numbers), then we define it to have a skew of n. The maximum skew
|
||
* values allow us to decide when a packet hasn't been received yet because it
|
||
* is out of order, as opposed to when it is likely to have been dropped.
|
||
*
|
||
* \subsection sec1-2-8 Section 1.2.8: Multicasting
|
||
*
|
||
* \par
|
||
* The rx multi.c module provides for multicast abilities, sending an RPC to
|
||
* several targets simultaneously. While true multicasting is not achieved, it
|
||
* is simulated by a rapid succession of packet transmissions and a collection
|
||
* algorithm for the replies. A client program, though, may be programmed as if
|
||
* multicasting were truly taking place. Thus, Rx is poised to take full
|
||
* advantage of a system supporting true multicasting with minimal disruption
|
||
* to the existing client code base.
|
||
*
|
||
* \section sec1-3 Section 1.3: Scope
|
||
*
|
||
* \par
|
||
* This paper is a member of a documentation suite providing specifications as
|
||
* to the operation and interfaces offered by the various AFS servers and
|
||
* agents. Rx is an integral part of the AFS environment, as it provides the
|
||
* high-performance, secure pathway by which these system components
|
||
* communicate across the network. Although AFS is dependent on Rx's services,
|
||
* the reverse is not true. Rx is a fully independent RPC package, standing on
|
||
* its own and usable in other environments.
|
||
* \par
|
||
* The intent of this work is to provide readers with a sufficiently detailed
|
||
* description of Rx that they may proceed to write their own applications on
|
||
* top of it. In fact, code for a sample Rx server and client are provided.
|
||
* \par
|
||
* One topic related to Rx will not be covered by this document, namely the
|
||
* Rxgen stub generator. Rather, rxgen is addressed in a separate document.
|
||
*
|
||
* \section sec1-4 Section 1.4: Document Layout
|
||
*
|
||
* \par
|
||
* After this introduction, Chapter 2 will introduce and describe various
|
||
* facilities and tools that support Rx. In particular, the threading and
|
||
* locking packages used by Rx will be examined, along with a set of timer and
|
||
* preemption tools. Chapter 3 proceeds to examine the details of one of the
|
||
* built-in security modules offered by Rx. Based on the Kerberos system
|
||
* developed by MIT's Project Athena, this rxkad module allows secure, ecrypted
|
||
* communication between the server and client ends of the RPC. Chapter 5 then
|
||
* provides the full Rx programming interface, and Chapter 6 illustrates the
|
||
* use of this programming interface by providing a fully-operational
|
||
* programming example employing Rx. This rxdemo suite is examined in detail,
|
||
* ranging all the way from a step-by-step analysis of the human-authored
|
||
* files, and the Rxgen-generated files upon which they are based, to the
|
||
* workings of the associated Makefile. Output from the example rxdemo server
|
||
* and client is also provided.
|
||
*
|
||
* \section sec1-5 Section 1.5: Related Documents
|
||
*
|
||
* \par
|
||
* Titles for the full suite of AFS specification documents are listed below.
|
||
* All of the servers and agents making up the AFS computing environment,
|
||
* whether running in the unix kernel or in user space, utilize an Rx RPC
|
||
* interface through which they export their services.
|
||
* \par
|
||
* \li AFS-3 Programmer's Reference: Architectural Overview: This paper
|
||
* provides an architectual overview of the AFS distributed file system,
|
||
* describing the full set of servers and agents in a coherent way,
|
||
* illustrating their relationships to each other and examining their
|
||
* interactions.
|
||
* \li AFS-3 Programmer's Reference: file Server/Cache Manager Interface: This
|
||
* document describes the workings and interfaces of the two primary AFS
|
||
* agents, the file Server and Cache Manager. The file Server provides a
|
||
* centralized disk repository for sets of files, regulating access to them.
|
||
* End users sitting on client machines rely on the Cache Manager agent,
|
||
* running in their kernel, to act as their agent in accessing the data stored
|
||
* on file Server machines, making those files appear as if they were really
|
||
* housed locally.
|
||
* \li AFS-3 Programmer's Reference:Volume Server/Volume Location Server
|
||
* Interface: This document describes the services through which "containers"
|
||
* of related user data are located and managed.
|
||
* \li AFS-3 Programmer's Reference: Protection Server Interface: This paper
|
||
* describes the server responsible for mapping printable user names to and
|
||
* from their internal AFS identifiers. The Protection Server also allows users
|
||
* to create, destroy, and manipulate "groups" of users, which are suitable for
|
||
* placement on access control lists (ACLs).
|
||
* \li AFS-3 Programmer's Reference: BOS Server Interface: This paper
|
||
* explicates the "nanny" service which assists in the administrability of the
|
||
* AFS environment.
|
||
* \par
|
||
* In addition to these papers, the AFS 3.1 product is delivered with its own
|
||
* user, system administrator, installation, and command reference documents.
|
||
*
|
||
* \page chap2 Chapter 2 -- The LWP Lightweight Process Package
|
||
*
|
||
* \section sec2-1 Section 2.1: Introduction
|
||
* \par
|
||
* This chapter describes a package allowing multiple threads of control to
|
||
* coexist and cooperate within one unix process. Each such thread of control
|
||
* is also referred to as a lightweight process, in contrast to the traditional
|
||
* unix (heavyweight) process. Except for the limitations of a fixed stack size
|
||
* and non-preemptive scheduling, these lightweight processes possess all the
|
||
* properties usually associated with full-fledged processes in typical
|
||
* operating systems. For the purposes of this document, the terms lightweight
|
||
* process, LWP, and thread are completely interchangeable, and they appear
|
||
* intermixed in this chapter. Included in this lightweight process facility
|
||
* are various sub-packages, including services for locking, I/O control,
|
||
* timers, fast time determination, and preemption.
|
||
* \par
|
||
* The Rx facility is not the only client of the LWP package. Other LWP clients
|
||
* within AFS include the file Server, Protection Server, BOS Server, Volume
|
||
* Server, Volume Location Server, and the Authentication Server, along with
|
||
* many of the AFS application programs.
|
||
*
|
||
* \section sec2-2 Section 2.2: Description
|
||
*
|
||
* \subsection Section 2.2.1: sec2-2-1 LWP Overview
|
||
*
|
||
* \par
|
||
* The LWP package implements primitive functions that provide the basic
|
||
* facilities required to enable procedures written in C to execute
|
||
* concurrently and asynchronously. The LWP package is meant to be
|
||
* general-purpose (note the applications mentioned above), with a heavy
|
||
* emphasis on simplicity. Interprocess communication facilities can be built
|
||
* on top of this basic mechanism and in fact, many different IPC mechanisms
|
||
* could be implemented.
|
||
* \par
|
||
* In order to set up the threading support environment, a one-time invocation
|
||
* of the LWP InitializeProcessSupport() function must precede the use of the
|
||
* facilities described here. This initialization function carves an initial
|
||
* process out of the currently executing C procedure and returns its thread
|
||
* ID. For symmetry, an LWP TerminateProcessSupport() function may be used
|
||
* explicitly to release any storage allocated by its counterpart. If this
|
||
* function is used, it must be issued from the thread created by the original
|
||
* LWP InitializeProcessSupport() invocation.
|
||
* \par
|
||
* When any of the lightweight process functions completes, an integer value is
|
||
* returned to indicate whether an error condition was encountered. By
|
||
* convention, a return value of zero indicates that the operation succeeded.
|
||
* \par
|
||
* Macros, typedefs, and manifest constants for error codes needed by the
|
||
* threading mechanism are exported by the lwp.h include file. A lightweight
|
||
* process is identified by an object of type PROCESS, which is defined in the
|
||
* include file.
|
||
* \par
|
||
* The process model supported by the LWP operations is based on a
|
||
* non-preemptive priority dispatching scheme. A priority is an integer in the
|
||
* range [0..LWP MAX PRIORITY], where 0 is the lowest priority. Once a given
|
||
* thread is selected and dispatched, it remains in control until it
|
||
* voluntarily relinquishes its claim on the CPU. Control may be relinquished
|
||
* by either explicit means (LWP_DispatchProcess()) or implicit means (through
|
||
* the use of certain other LWP operations with this side effect). In general,
|
||
* all LWP operations that may cause a higher-priority process to become ready
|
||
* for dispatching preempt the process requesting the service. When this
|
||
* occurs, the dispatcher mechanism takes over and automatically schedules the
|
||
* highest-priority runnable process. Routines in this category, where the
|
||
* scheduler is guaranteed to be invoked in the absence of errors, are:
|
||
* \li LWP_WaitProcess()
|
||
* \li LWP_MwaitProcess()
|
||
* \li LWP_SignalProcess()
|
||
* \li LWP_DispatchProcess()
|
||
* \li LWP_DestroyProcess()
|
||
* \par
|
||
* The following functions are guaranteed not to cause preemption, and so may
|
||
* be issued with no fear of losing control to another thread:
|
||
* \li LWP_InitializeProcessSupport()
|
||
* \li LWP_NoYieldSignal()
|
||
* \li LWP_CurrentProcess()
|
||
* \li LWP_ActiveProcess()
|
||
* \li LWP_StackUsed()
|
||
* \li LWP_NewRock()
|
||
* \li LWP_GetRock()
|
||
* \par
|
||
* The symbol LWP NORMAL PRIORITY, whose value is (LWP MAX PRIORITY-2),
|
||
* provides a reasonable default value to use for process priorities.
|
||
* \par
|
||
* The lwp debug global variable can be set to activate or deactivate debugging
|
||
* messages tracing the flow of control within the LWP routines. To activate
|
||
* debugging messages, set lwp debug to a non-zero value. To deactivate, reset
|
||
* it to zero. All debugging output from the LWP routines is sent to stdout.
|
||
* \par
|
||
* The LWP package checks for stack overflows at each context switch. The
|
||
* variable that controls the action of the package when an overflow occurs is
|
||
* lwp overflowAction. If it is set to LWP SOMESSAGE, then a message will be
|
||
* printed on stderr announcing the overflow. If lwp overflowAction is set to
|
||
* LWP SOABORT, the abort() LWP routine will be called. finally, if lwp
|
||
* overflowAction is set to LWP SOQUIET, the LWP facility will ignore the
|
||
* errors. By default, the LWP SOABORT setting is used.
|
||
* \par
|
||
* Here is a sketch of a simple program (using some psuedocode) demonstrating
|
||
* the high-level use of the LWP facility. The opening #include line brings in
|
||
* the exported LWP definitions. Following this, a routine is defined to wait
|
||
* on a "queue" object until something is deposited in it, calling the
|
||
* scheduler as soon as something arrives. Please note that various LWP
|
||
* routines are introduced here. Their definitions will appear later, in
|
||
* Section 2.3.1.
|
||
*
|
||
* \code
|
||
* #include <afs/lwp.h>
|
||
* static read_process(id)
|
||
* int *id;
|
||
* { /* Just relinquish control for now */
|
||
* LWP_DispatchProcess();
|
||
* for (;;)
|
||
* {
|
||
* /* Wait until there is something in the queue */
|
||
* while (empty(q)) LWP_WaitProcess(q);
|
||
* /* Process the newly-arrived queue entry */
|
||
* LWP_DispatchProcess();
|
||
* }
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The next routine, write process(), sits in a loop, putting messages on the
|
||
* shared queue and signalling the reader, which is waiting for activity on the
|
||
* queue. Signalling a thread is accomplished via the LWP SignalProcess()
|
||
* library routine.
|
||
*
|
||
* \code
|
||
* static write_process()
|
||
* { ...
|
||
* /* Loop, writing data to the shared queue. */
|
||
* for (mesg = messages; *mesg != 0; mesg++)
|
||
* {
|
||
* insert(q, *mesg);
|
||
* LWP_SignalProcess(q);
|
||
* }
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* finally, here is the main routine for this demo pseudocode. It starts by
|
||
* calling the LWP initialization routine. Next, it creates some number of
|
||
* reader threads with calls to LWP CreateProcess() in addition to the single
|
||
* writer thread. When all threads terminate, they will signal the main routine
|
||
* on the done variable. Once signalled, the main routine will reap all the
|
||
* threads with the help of the LWP DestroyProcess() function.
|
||
*
|
||
* \code
|
||
* main(argc, argv)
|
||
* int argc;
|
||
* char **argv;
|
||
* {
|
||
* PROCESS *id; /* Initial thread ID */
|
||
* /* Set up the LWP package, create the initial thread ID. */
|
||
* LWP_InitializeProcessSupport(0, &id);
|
||
* /* Create a set of reader threads. */
|
||
* for (i = 0; i < nreaders; i++)
|
||
* LWP_CreateProcess(read_process, STACK_SIZE, 0, i, "Reader",
|
||
* &readers[i]);
|
||
*
|
||
* /* Create a single writer thread. */
|
||
* LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer);
|
||
* /* Wait for all the above threads to terminate. */
|
||
* for (i = 0; i <= nreaders; i++)
|
||
* LWP_WaitProcess(&done);
|
||
*
|
||
* /* All threads are done. Destroy them all. */
|
||
* for (i = nreaders-1; i >= 0; i--)
|
||
* LWP_DestroyProcess(readers[i]);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec2-2-2 Section 2.2.2: Locking
|
||
* \par
|
||
* The LWP locking facility exports a number of routines and macros that allow
|
||
* a C programmer using LWP threading to place read and write locks on shared
|
||
* data structures. This locking facility was also written with simplicity in
|
||
* mind.
|
||
* \par
|
||
* In order to invoke the locking mechanism, an object of type struct Lock must
|
||
* be associated with the object. After being initialized with a call to
|
||
* LockInit(), the lock object is used in invocations of various macros,
|
||
* including ObtainReadLock(), ObtainWriteLock(), ReleaseReadLock(),
|
||
* ReleaseWriteLock(), ObtainSharedLock(), ReleaseSharedLock(), and
|
||
* BoostSharedLock().
|
||
* \par
|
||
* Lock semantics specify that any number of readers may hold a lock in the
|
||
* absence of a writer. Only a single writer may acquire a lock at any given
|
||
* time. The lock package guarantees fairness, legislating that each reader and
|
||
* writer will eventually obtain a given lock. However, this fairness is only
|
||
* guaranteed if the priorities of the competing processes are identical. Note
|
||
* that ordering is not guaranteed by this package.
|
||
* \par
|
||
* Shared locks are read locks that can be "boosted" into write locks. These
|
||
* shared locks have an unusual locking matrix. Unboosted shared locks are
|
||
* compatible with read locks, yet incompatible with write locks and other
|
||
* shared locks. In essence, a thread holding a shared lock on an object has
|
||
* effectively read-locked it, and has the option to promote it to a write lock
|
||
* without allowing any other writer to enter the critical region during the
|
||
* boost operation itself.
|
||
* \par
|
||
* It is illegal for a process to request a particular lock more than once
|
||
* without first releasing it. Failure to obey this restriction will cause
|
||
* deadlock. This restriction is not enforced by the LWP code.
|
||
* \par
|
||
* Here is a simple pseudocode fragment serving as an example of the available
|
||
* locking operations. It defines a struct Vnode object, which contains a lock
|
||
* object. The get vnode() routine will look up a struct Vnode object by name,
|
||
* and then either read-lock or write-lock it.
|
||
* \par
|
||
* As with the high-level LWP example above, the locking routines introduced
|
||
* here will be fully defined later, in Section 2.3.2.
|
||
*
|
||
* \code
|
||
* #include <afs/lock.h>
|
||
*
|
||
* struct Vnode {
|
||
* ...
|
||
* struct Lock lock; Used to lock this vnode
|
||
* ... };
|
||
*
|
||
* #define READ 0
|
||
* #define WRITE 1
|
||
*
|
||
* struct Vnode *get_vnode(name, how) char *name;
|
||
* int how;
|
||
* {
|
||
* struct Vnode *v;
|
||
* v = lookup(name);
|
||
* if (how == READ)
|
||
* ObtainReadLock(&v->lock);
|
||
* else
|
||
* ObtainWriteLock(&v->lock);
|
||
* }
|
||
* \endcode
|
||
*
|
||
*
|
||
* \subsection sec2-2-3 Section 2.2.3: IOMGR
|
||
*
|
||
* \par
|
||
* The IOMGR facility associated with the LWP service allows threads to wait on
|
||
* various unix events. The exported IOMGR Select() routine allows a thread to
|
||
* wait on the same set of events as the unix select() call. The parameters to
|
||
* these two routines are identical. IOMGR Select() puts the calling LWP to
|
||
* sleep until no threads are active. At this point, the built-in IOMGR thread,
|
||
* which runs at the lowest priority, wakes up and coalesces all of the select
|
||
* requests together. It then performs a single select() and wakes up all
|
||
* threads affected by the result.
|
||
* \par
|
||
* The IOMGR Signal() routine allows an LWP to wait on the delivery of a unix
|
||
* signal. The IOMGR thread installs a signal handler to catch all deliveries
|
||
* of the unix signal. This signal handler posts information about the signal
|
||
* delivery to a global data structure. The next time that the IOMGR thread
|
||
* runs, it delivers the signal to any waiting LWP.
|
||
* \par
|
||
* Here is a pseudocode example of the use of the IOMGR facility, providing the
|
||
* blueprint for an implemention a thread-level socket listener.
|
||
*
|
||
* \code
|
||
* void rpc_SocketListener()
|
||
* {
|
||
* int ReadfdMask, WritefdMask, ExceptfdMask, rc;
|
||
* struct timeval *tvp;
|
||
* while(TRUE)
|
||
* { ...
|
||
* ExceptfdMask = ReadfdMask = (1 << rpc_RequestSocket);
|
||
* WritefdMask = 0;
|
||
*
|
||
* rc = IOMGR_Select(8*sizeof(int), &ReadfdMask, &WritefdMask,
|
||
* &ExceptfdMask, tvp);
|
||
*
|
||
* switch(rc)
|
||
* {
|
||
* case 0: /* Timeout */ continue;
|
||
* /* Main while loop */
|
||
*
|
||
* case -1: /* Error */
|
||
* SystemError("IOMGR_Select");
|
||
* exit(-1);
|
||
*
|
||
* case 1: /* RPC packet arrived! */ ...
|
||
* process packet ...
|
||
* break;
|
||
*
|
||
* default: Should never occur
|
||
* }
|
||
* }
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec2-2-4 Section 2.2.4: Timer
|
||
* \par
|
||
* The timer package exports a number of routines that assist in manipulating
|
||
* lists of objects of type struct TM Elem. These struct TM Elem timers are
|
||
* assigned a timeout value by the user and inserted in a package-maintained
|
||
* list. The time remaining to each timer's timeout is kept up to date by the
|
||
* package under user control. There are routines to remove a timer from its
|
||
* list, to return an expired timer from a list, and to return the next timer
|
||
* to expire.
|
||
* \par
|
||
* A timer is commonly used by inserting a field of type struct TM Elem into a
|
||
* structure. After setting the desired timeout value, the structure is
|
||
* inserted into a list by means of its timer field.
|
||
* \par
|
||
* Here is a simple pseudocode example of how the timer package may be used.
|
||
* After calling the package initialization function, TM Init(), the pseudocode
|
||
* spins in a loop. first, it updates all the timers via TM Rescan() calls.
|
||
* Then, it pulls out the first expired timer object with TM GetExpired() (if
|
||
* any), and processes it.
|
||
*
|
||
* \code
|
||
* static struct TM_Elem *requests;
|
||
* ...
|
||
* TM_Init(&requests); /* Initialize timer list */ ...
|
||
* for (;;) {
|
||
* TM_Rescan(requests); /* Update the timers */
|
||
* expired = TM_GetExpired(requests);
|
||
* if (expired == 0)
|
||
* break;
|
||
* . . . process expired element . . .
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec2-2-5 Section 2.2.5: Fast Time
|
||
*
|
||
* \par
|
||
* The fast time routines allows a caller to determine the current time of day
|
||
* without incurring the expense of a kernel call. It works by mapping the page
|
||
* of the kernel that holds the time-of-day variable and examining it directly.
|
||
* Currently, this package only works on Suns. The routines may be called on
|
||
* other architectures, but they will run more slowly.
|
||
* \par
|
||
* The initialization routine for this package is fairly expensive, since it
|
||
* does a lookup of a kernel symbol via nlist(). If the client application
|
||
* program only runs for only a short time, it may wish to call FT Init() with
|
||
* the notReally parameter set to TRUE in order to prevent the lookup from
|
||
* taking place. This is useful if you are using another package that uses the
|
||
* fast time facility.
|
||
*
|
||
* \section sec2-3 Section 2.3: Interface Specifications
|
||
*
|
||
* \subsection sec2-3-1 Section 2.3.1: LWP
|
||
*
|
||
* \par
|
||
* This section covers the calling interfaces to the LWP package. Please note
|
||
* that LWP macros (e.g., ActiveProcess) are also included here, rather than
|
||
* being relegated to a different section.
|
||
*
|
||
* \subsubsection sec2-3-1-1 Section 2.3.1.1: LWP_InitializeProcessSupport
|
||
* _ Initialize the LWP package
|
||
*
|
||
* \par
|
||
* int LWP_InitializeProcessSupport(IN int priority; OUT PROCESS *pid)
|
||
* \par Description
|
||
* This function initializes the LWP package. In addition, it turns the current
|
||
* thread of control into the initial process with the specified priority. The
|
||
* process ID of this initial thread is returned in the pid parameter. This
|
||
* routine must be called before any other routine in the LWP library. The
|
||
* scheduler will NOT be invoked as a result of calling
|
||
* LWP_InitializeProcessSupport().
|
||
* \par Error Codes
|
||
* LWP EBADPRI The given priority is invalid, either negative or too large.
|
||
*
|
||
* \subsubsection sec2-3-1-2 Section 2.3.1.2: LWP_TerminateProcessSupport
|
||
* _ End process support, perform cleanup
|
||
*
|
||
* \par
|
||
* int LWP_TerminateProcessSupport()
|
||
* \par Description
|
||
* This routine terminates the LWP threading support and cleans up after it by
|
||
* freeing any auxiliary storage used. This routine must be called from within
|
||
* the process that invoked LWP InitializeProcessSupport(). After LWP
|
||
* TerminateProcessSupport() has been called, it is acceptable to call LWP
|
||
* InitializeProcessSupport() again in order to restart LWP process support.
|
||
* \par Error Codes
|
||
* ---Always succeeds, or performs an abort().
|
||
*
|
||
* \subsubsection sec2-3-1-3 Section 2.3.1.3: LWP_CreateProcess _ Create a
|
||
* new thread
|
||
*
|
||
* \par
|
||
* int LWP_CreateProcess(IN int (*ep)(); IN int stacksize; IN int priority; IN
|
||
* char *parm; IN char *name; OUT PROCESS *pid)
|
||
* \par Description
|
||
* This function is used to create a new lightweight process with a given
|
||
* printable name. The ep argument identifies the function to be used as the
|
||
* body of the thread. The argument to be passed to this function is contained
|
||
* in parm. The new thread's stack size in bytes is specified in stacksize, and
|
||
* its execution priority in priority. The pid parameter is used to return the
|
||
* process ID of the new thread.
|
||
* \par
|
||
* If the thread is successfully created, it will be marked as runnable. The
|
||
* scheduler is called before the LWP CreateProcess() call completes, so the
|
||
* new thread may indeed begin its execution before the completion. Note that
|
||
* the new thread is guaranteed NOT to run before the call completes if the
|
||
* specified priority is lower than the caller's. On the other hand, if the new
|
||
* thread's priority is higher than the caller's, then it is guaranteed to run
|
||
* before the creation call completes.
|
||
* \par Error Codes
|
||
* LWP EBADPRI The given priority is invalid, either negative or too large.
|
||
* \n LWP NOMEM Could not allocate memory to satisfy the creation request.
|
||
*
|
||
* \subsubsection sec2-3-1-4 Section: 2.3.1.4: LWP_DestroyProcess _ Create
|
||
* a new thread
|
||
*
|
||
* \par
|
||
* int LWP_DestroyProcess(IN PROCESS pid)
|
||
* \par Description
|
||
* This routine destroys the thread identified by pid. It will be terminated
|
||
* immediately, and its internal storage will be reclaimed. A thread is allowed
|
||
* to destroy itself. In this case, of course, it will only get to see the
|
||
* return code if the operation fails. Note that a thread may also destroy
|
||
* itself by returning from the parent C routine.
|
||
* \par
|
||
* The scheduler is called by this operation, which may cause an arbitrary
|
||
* number of threads to execute before the caller regains the processor.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized.
|
||
*
|
||
* \subsubsection sec2-3-1-5 Section 2.3.1.5: WaitProcess _ Wait on an
|
||
* event
|
||
*
|
||
* \par
|
||
* int LWP WaitProcess(IN char *event)
|
||
* \par Description
|
||
* This routine puts the thread making the call to sleep until another LWP
|
||
* calls the LWP SignalProcess() or LWP NoYieldSignal() routine with the
|
||
* specified event. Note that signalled events are not queued. If a signal
|
||
* occurs and no thread is awakened, the signal is lost. The scheduler is
|
||
* invoked by the LWP WaitProcess() routine.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized.
|
||
* \n LWP EBADEVENT The given event pointer is null.
|
||
*
|
||
* \subsubsection sec2-3-1-6 Section 2.3.1.6: MwaitProcess _ Wait on a set
|
||
* of events
|
||
*
|
||
* \par
|
||
* int LWP MwaitProcess(IN int wcount; IN char *evlist[])
|
||
* \par Description
|
||
* This function allows a thread to wait for wcount signals on any of the items
|
||
* in the given evlist. Any number of signals of a particular event are only
|
||
* counted once. The evlist is a null-terminated list of events to wait for.
|
||
* The scheduler will be invoked.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized.
|
||
* \n LWP EBADCOUNT An illegal number of events has been supplied.
|
||
*
|
||
* \subsubsection sec2-3-1-7 Section 2.3.1.7: SignalProcess _ Signal an
|
||
* event
|
||
*
|
||
* \par
|
||
* int LWP SignalProcess(IN char *event)
|
||
* \par Description
|
||
* This routine causes the given event to be signalled. All threads waiting for
|
||
* this event (exclusively) will be marked as runnable, and the scheduler will
|
||
* be invoked. Note that threads waiting on multiple events via LWP
|
||
* MwaitProcess() may not be marked as runnable. Signals are not queued.
|
||
* Therefore, if no thread is waiting for the signalled event, the signal will
|
||
* be lost.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized. LWP EBADEVENT A null
|
||
* event pointer has been provided. LWP ENOWAIT No thread was waiting on the
|
||
* given event.
|
||
*
|
||
* \subsubsection sec2-3-1-8 Section 2.3.1.8: NoYieldSignal _ Signal an
|
||
* event without invoking scheduler
|
||
*
|
||
* \par
|
||
* int LWP NoYieldSignal(IN char *event)
|
||
* \par Description
|
||
* This function is identical to LWP SignalProcess() except that the scheduler
|
||
* will not be invoked. Thus, control will remain with the signalling process.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized. LWP EBADEVENT A null
|
||
* event pointer has been provided. LWP ENOWAIT No thread was waiting on the
|
||
* given event.
|
||
*
|
||
* \subsubsection sec2-3-1-9 Section 2.3.1.9: DispatchProcess _ Yield
|
||
* control to the scheduler
|
||
*
|
||
* \par
|
||
* int LWP DispatchProcess()
|
||
* \par Description
|
||
* This routine causes the calling thread to yield voluntarily to the LWP
|
||
* scheduler. If no other thread of appropriate priority is marked as runnable,
|
||
* the caller will continue its execution.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized.
|
||
*
|
||
* \subsubsection sec2-3-1-10 Section 2.3.1.10: CurrentProcess _ Get the
|
||
* current thread's ID
|
||
*
|
||
* \par
|
||
* int LWP CurrentProcess(IN PROCESS *pid)
|
||
* \par Description
|
||
* This call places the current lightweight process ID in the pid parameter.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package has not been initialized.
|
||
*
|
||
* \subsubsection sec2-3-1-11 Section 2.3.1.11: ActiveProcess _ Get the
|
||
* current thread's ID (macro)
|
||
*
|
||
* \par
|
||
* int LWP ActiveProcess()
|
||
* \par Description
|
||
* This macro's value is the current lightweight process ID. It generates a
|
||
* value identical to that acquired by calling the LWP CurrentProcess()
|
||
* function described above if the LWP package has been initialized. If no such
|
||
* initialization has been done, it will return a value of zero.
|
||
*
|
||
* \subsubsection sec2-3-1-12 Section: 2.3.1.12: StackUsed _ Calculate
|
||
* stack usage
|
||
*
|
||
* \par
|
||
* int LWP StackUsed(IN PROCESS pid; OUT int *max; OUT int *used)
|
||
* \par Description
|
||
* This function returns the amount of stack space allocated to the thread
|
||
* whose identifier is pid, and the amount actually used so far. This is
|
||
* possible if the global variable lwp stackUseEnabled was TRUE when the thread
|
||
* was created (it is set this way by default). If so, the thread's stack area
|
||
* was initialized with a special pattern. The memory still stamped with this
|
||
* pattern can be determined, and thus the amount of stack used can be
|
||
* calculated. The max parameter is always set to the thread's stack allocation
|
||
* value, and used is set to the computed stack usage if lwp stackUseEnabled
|
||
* was set when the process was created, or else zero.
|
||
* \par Error Codes
|
||
* LWP NO STACK Stack usage was not enabled at thread creation time.
|
||
*
|
||
* \subsubsection sec2-3-1-13 Section 2.3.1.13: NewRock _ Establish
|
||
* thread-specific storage
|
||
*
|
||
* \par
|
||
* int LWP NewRock (IN int tag; IN char **value)
|
||
* \par Description
|
||
* This function establishes a "rock", or thread-specific information,
|
||
* associating it with the calling LWP. The tag is intended to be any unique
|
||
* integer value, and the value is a pointer to a character array containing
|
||
* the given data.
|
||
* \par
|
||
* Users of the LWP package must coordinate their choice of tag values. Note
|
||
* that a tag's value cannot be changed. Thus, to obtain a mutable data
|
||
* structure, another level of indirection is required. Up to MAXROCKS (4)
|
||
* rocks may be associated with any given thread.
|
||
* \par Error Codes
|
||
* ENOROCKS A rock with the given tag field already exists. All of the MAXROCKS
|
||
* are in use.
|
||
*
|
||
*
|
||
* \subsubsection sec2-3-1-14 Section: 2.3.1.14: GetRock _ Retrieve
|
||
* thread-specific storage
|
||
*
|
||
* \par
|
||
* int LWP GetRock(IN int tag; OUT **value)
|
||
* \par Description
|
||
* This routine recovers the thread-specific information associated with the
|
||
* calling process and the given tag, if any. Such a rock had to be established
|
||
* through a LWP NewRock() call. The rock's value is deposited into value.
|
||
* \par Error Codes
|
||
* LWP EBADROCK A rock has not been associated with the given tag for this
|
||
* thread.
|
||
*
|
||
* \subsection sec2-3-2 Section 2.3.2: Locking
|
||
*
|
||
* \par
|
||
* This section covers the calling interfaces to the locking package. Many of
|
||
* the user-callable routines are actually implemented as macros.
|
||
*
|
||
* \subsubsection sec2-3-2-1 Section 2.3.2.1: Lock Init _ Initialize lock
|
||
* structure
|
||
*
|
||
* \par
|
||
* void Lock Init(IN struct Lock *lock)
|
||
* \par Description
|
||
* This function must be called on the given lock object before any other
|
||
* operations can be performed on it.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-2 Section 2.3.2.2: ObtainReadLock _ Acquire a
|
||
* read lock
|
||
*
|
||
* \par
|
||
* void ObtainReadLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro obtains a read lock on the specified lock object. Since this is a
|
||
* macro and not a function call, results are not predictable if the value of
|
||
* the lock parameter is a side-effect producing expression, as it will be
|
||
* evaluated multiple times in the course of the macro interpretation.
|
||
* Read locks are incompatible with write, shared, and boosted shared locks.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-3 Section 2.3.2.3: ObtainWriteLock _ Acquire a
|
||
* write lock
|
||
*
|
||
* \par
|
||
* void ObtainWriteLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro obtains a write lock on the specified lock object. Since this is
|
||
* a macro and not a function call, results are not predictable if the value of
|
||
* the lock parameter is a side-effect producing expression, as it will be
|
||
* evaluated multiple times in the course of the macro interpretation.
|
||
* \par
|
||
* Write locks are incompatible with all other locks.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-4 Section 2.3.2.4: ObtainSharedLock _ Acquire a
|
||
* shared lock
|
||
*
|
||
* \par
|
||
* void ObtainSharedLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro obtains a shared lock on the specified lock object. Since this is
|
||
* a macro and not a function call, results are not predictable if the value of
|
||
* the lock parameter is a side-effect producing expression, as it will be
|
||
* evaluated multiple times in the course of the macro interpretation.
|
||
* \par
|
||
* Shared locks are incompatible with write and boosted shared locks, but are
|
||
* compatible with read locks.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-5 Section 2.3.2.5: ReleaseReadLock _ Release
|
||
* read lock
|
||
*
|
||
* \par
|
||
* void ReleaseReadLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro releases the specified lock. The lock must have been previously
|
||
* read-locked. Since this is a macro and not a function call, results are not
|
||
* predictable if the value of the lock parameter is a side-effect producing
|
||
* expression, as it will be evaluated multiple times in the course of the
|
||
* macro interpretation. The results are also unpredictable if the lock was not
|
||
* previously read-locked by the thread calling ReleaseReadLock().
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-6 Section 2.3.2.6: ReleaseWriteLock _ Release
|
||
* write lock
|
||
*
|
||
* \par
|
||
* void ReleaseWriteLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro releases the specified lock. The lock must have been previously
|
||
* write-locked. Since this is a macro and not a function call, results are not
|
||
* predictable if the value of the lock parameter is a side-effect producing
|
||
* expression, as it will be evaluated multiple times in the course of the
|
||
* macro interpretation. The results are also unpredictable if the lock was not
|
||
* previously write-locked by the thread calling ReleaseWriteLock().
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-7 Section 2.3.2.7: ReleaseSharedLock _ Release
|
||
* shared lock
|
||
*
|
||
* \par
|
||
* void ReleaseSharedLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro releases the specified lock. The lock must have been previously
|
||
* share-locked. Since this is a macro and not a function call, results are not
|
||
* predictalbe if the value of the lock parameter is a side-effect producing
|
||
* expression, as it will be evaluated multiple times in the course of the
|
||
* macro interpretation. The results are also unpredictable if the lock was not
|
||
* previously share-locked by the thread calling ReleaseSharedLock().
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-8 Section 2.3.2.8: CheckLock _ Determine state
|
||
* of a lock
|
||
*
|
||
* \par
|
||
* void CheckLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro produces an integer that specifies the status of the indicated
|
||
* lock. The value will be -1 if the lock is write-locked, 0 if unlocked, or
|
||
* otherwise a positive integer that indicates the number of readers (threads
|
||
* holding read locks). Since this is a macro and not a function call, results
|
||
* are not predictable if the value of the lock parameter is a side-effect
|
||
* producing expression, as it will be evaluated multiple times in the course
|
||
* of the macro interpretation.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-9 Section 2.3.2.9: BoostLock _ Boost a shared
|
||
* lock
|
||
*
|
||
* \par
|
||
* void BoostLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro promotes ("boosts") a shared lock into a write lock. Such a boost
|
||
* operation guarantees that no other writer can get into the critical section
|
||
* in the process. Since this is a macro and not a function call, results are
|
||
* not predictable if the value of the lock parameter is a side-effect
|
||
* producing expression, as it will be evaluated multiple times in the course
|
||
* of the macro interpretation.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsubsection sec2-3-2-10 Section 2.3.2.10: UnboostLock _ Unboost a
|
||
* shared lock
|
||
*
|
||
* \par
|
||
* void UnboostLock(IN struct Lock *lock)
|
||
* \par Description
|
||
* This macro demotes a boosted shared lock back down into a regular shared
|
||
* lock. Such an unboost operation guarantees that no other writer can get into
|
||
* the critical section in the process. Since this is a macro and not a
|
||
* function call, results are not predictable if the value of the lock
|
||
* parameter is a side-effect producing expression, as it will be evaluated
|
||
* multiple times in the course of the macro interpretation.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsection sec2-3-3 Section 2.3.3: IOMGR
|
||
*
|
||
* \par
|
||
* This section covers the calling interfaces to the I/O management package.
|
||
*
|
||
* \subsubsection sec2-3-3-1 Section: 2.3.3.1: IOMGR Initialize _
|
||
* Initialize the package
|
||
*
|
||
* \par
|
||
* int IOMGR Initialize()
|
||
* \par Description
|
||
* This function initializes the IOMGR package. Its main task is to create the
|
||
* IOMGR thread itself, which runs at the lowest possible priority (0). The
|
||
* remainder of the lightweight processes must be running at priority 1 or
|
||
* greater (up to a maximum of LWP MAX PRIORITY (4)) for the IOMGR package to
|
||
* function correctly.
|
||
* \par Error Codes
|
||
* -1 The LWP and/or timer package haven't been initialized.
|
||
* \n <misc> Any errors that may be returned by the LWP CreateProcess()
|
||
* routine.
|
||
*
|
||
* \subsubsection sec2-3-3-2 Section 2.3.3.2: IOMGR finalize _ Clean up
|
||
* the IOMGR facility
|
||
*
|
||
* \par
|
||
* int IOMGR finalize()
|
||
* \par Description
|
||
* This routine cleans up after the IOMGR package when it is no longer needed.
|
||
* It releases all storage and destroys the IOMGR thread itself.
|
||
* \par Error Codes
|
||
* <misc> Any errors that may be returned by the LWP DestroyProcess() routine.
|
||
*
|
||
* \subsubsection sec2-3-3-3 Section 2.3.3.3: IOMGR Select _ Perform a
|
||
* thread-level select()
|
||
*
|
||
* \par
|
||
* int IOMGR Select (IN int numfds; IN int *rfds; IN int *wfds; IN int *xfds;
|
||
* IN truct timeval *timeout)
|
||
* \par Description
|
||
* This routine performs an LWP version of unix select() operation. The
|
||
* parameters have the same meanings as with the unix call. However, the return
|
||
* values will be simplified (see below). If this is a polling select (i.e.,
|
||
* the value of timeout is null), it is done and the IOMGR Select() function
|
||
* returns to the user with the results. Otherwise, the calling thread is put
|
||
* to sleep. If at some point the IOMGR thread is the only runnable process, it
|
||
* will awaken and collect all select requests. The IOMGR will then perform a
|
||
* single select and awaken the appropriate processes. This will force a return
|
||
* from the affected IOMGR Select() calls.
|
||
* \par Error Codes
|
||
* -1 An error occurred.
|
||
* \n 0 A timeout occurred.
|
||
* \n 1 Some number of file descriptors are ready.
|
||
*
|
||
* \subsubsection sec2-3-3-4 Section 2.3.3.4: IOMGR Signal _ Associate
|
||
* unix and LWP signals
|
||
*
|
||
* \par
|
||
* int IOMGR Signal(IN int signo; IN char *event)
|
||
* \par Description
|
||
* This function associates an LWP signal with a unix signal. After this call,
|
||
* when the given unix signal signo is delivered to the (heavyweight unix)
|
||
* process, the IOMGR thread will deliver an LWP signal to the event via LWP
|
||
* NoYieldSignal(). This wakes up any lightweight processes waiting on the
|
||
* event. Multiple deliveries of the signal may be coalesced into one LWP
|
||
* wakeup. The call to LWP NoYieldSignal() will happen synchronously. It is
|
||
* safe for an LWP to check for some condition and then go to sleep waiting for
|
||
* a unix signal without having to worry about delivery of the signal happening
|
||
* between the check and the call to LWP WaitProcess().
|
||
* \par Error Codes
|
||
* LWP EBADSIG The signo value is out of range.
|
||
* \n LWP EBADEVENT The event pointer is null.
|
||
*
|
||
* \subsubsection sec2-3-3-5 Section 2.3.3.5: IOMGR CancelSignal _ Cancel
|
||
* unix and LWP signal association
|
||
*
|
||
* \par
|
||
* int IOMGR CancelSignal(IN int signo)
|
||
* \par Description
|
||
* This routine cancels the association between a unix signal and an LWP event.
|
||
* After calling this function, the unix signal signo will be handled however
|
||
* it was handled before the corresponding call to IOMGR Signal().
|
||
* \par Error Codes
|
||
* LWP EBADSIG The signo value is out of range.
|
||
*
|
||
* \subsubsection sec2-3-3-6 Section 2.3.3.6: IOMGR Sleep _ Sleep for a
|
||
* given period
|
||
*
|
||
* \par
|
||
* void IOMGR Sleep(IN unsigned seconds)
|
||
* \par Description
|
||
* This function calls IOMGR Select() with zero file descriptors and a timeout
|
||
* structure set up to cause the thread to sleep for the given number of
|
||
* seconds.
|
||
* \par Error Codes
|
||
* ---No value is returned.
|
||
*
|
||
* \subsection sec2-3-4 Section 2.3.4: Timer
|
||
*
|
||
* \par
|
||
* This section covers the calling interface to the timer package associated
|
||
* with the LWP facility.
|
||
*
|
||
* \subsubsection sec2-3-4-1 Section 2.3.4.1: TM Init _ Initialize a timer
|
||
* list
|
||
*
|
||
* \par
|
||
* int TM Init(IN struct TM Elem **list)
|
||
* \par Description
|
||
* This function causes the specified timer list to be initialized. TM Init()
|
||
* must be called before any other timer operations are applied to the list.
|
||
* \par Error Codes
|
||
* -1 A null timer list could not be produced.
|
||
*
|
||
* \subsubsection sec2-3-4-2 Section 2.3.4.2: TM final _ Clean up a timer
|
||
* list
|
||
*
|
||
* \par
|
||
* int TM final(IN struct TM Elem **list)
|
||
* \par Description
|
||
* This routine is called when the given empty timer list is no longer needed.
|
||
* All storage associated with the list is released.
|
||
* \par Error Codes
|
||
* -1 The list parameter is invalid.
|
||
*
|
||
* \subsubsection sec2-3-4-3 Section 2.3.4.3: TM Insert _ Insert an object
|
||
* into a timer list
|
||
*
|
||
* \par
|
||
* void TM Insert(IN struct TM Elem **list; IN struct TM Elem *elem)
|
||
* \par Description
|
||
* This routine enters an new element, elem, into the list denoted by list.
|
||
* Before the new element is queued, its TimeLeft field (the amount of time
|
||
* before the object comes due) is set to the value stored in its TotalTime
|
||
* field. In order to keep TimeLeft fields current, the TM Rescan() function
|
||
* may be used.
|
||
* \par Error Codes
|
||
* ---No return value is generated.
|
||
*
|
||
* \subsubsection sec2-3-4-4 Section 2.3.4.4: TM Rescan _ Update all
|
||
* timers in the list
|
||
*
|
||
* \par
|
||
* int TM Rescan(IN struct TM Elem *list)
|
||
* \par Description
|
||
* This function updates the TimeLeft fields of all timers on the given list.
|
||
* This is done by checking the time-of-day clock. Note: this is the only
|
||
* routine other than TM Init() that updates the TimeLeft field in the elements
|
||
* on the list.
|
||
* \par
|
||
* Instead of returning a value indicating success or failure, TM Rescan()
|
||
* returns the number of entries that were discovered to have timed out.
|
||
* \par Error Codes
|
||
* ---Instead of error codes, the number of entries that were discovered to
|
||
* have timed out is returned.
|
||
*
|
||
* \subsubsection sec2-3-4-5 Section 2.3.4.5: TM GetExpired _ Returns an
|
||
* expired timer
|
||
*
|
||
* \par
|
||
* struct TM Elem *TM GetExpired(IN struct TM Elem *list)
|
||
* \par Description
|
||
* This routine searches the specified timer list and returns a pointer to an
|
||
* expired timer element from that list. An expired timer is one whose TimeLeft
|
||
* field is less than or equal to zero. If there are no expired timers, a null
|
||
* element pointer is returned.
|
||
* \par Error Codes
|
||
* ---Instead of error codes, an expired timer pointer is returned, or a null
|
||
* timer pointer if there are no expired timer objects.
|
||
*
|
||
* \subsubsection sec2-3-4-6 Section 2.3.4.6: TM GetEarliest _ Returns
|
||
* earliest unexpired timer
|
||
*
|
||
* \par
|
||
* struct TM Elem *TM GetEarliest(IN struct TM Elem *list)
|
||
* \par Description
|
||
* This function returns a pointer to the timer element that will be next to
|
||
* expire on the given list. This is defined to be the timer element with the
|
||
* smallest (positive) TimeLeft field. If there are no timers on the list, or
|
||
* if they are all expired, this function will return a null pointer.
|
||
* \par Error Codes
|
||
* ---Instead of error codes, a pointer to the next timer element to expireis
|
||
* returned, or a null timer object pointer if they are all expired.
|
||
*
|
||
* \subsubsection sec2-3-4-7 Section 2.3.4.7: TM eql _ Test for equality
|
||
* of two timestamps
|
||
*
|
||
* \par
|
||
* bool TM eql(IN struct timemval *t1; IN struct timemval *t2)
|
||
* \par Description
|
||
* This function compares the given timestamps, t1 and t2, for equality. Note
|
||
* that the function return value, bool, has been set via typedef to be
|
||
* equivalent to unsigned char.
|
||
* \par Error Codes
|
||
* 0 If the two timestamps differ.
|
||
* \n 1 If the two timestamps are identical.
|
||
*
|
||
* \subsection sec2-3-5 Section 2.3.5: Fast Time
|
||
* \par
|
||
* This section covers the calling interface to the fast time package
|
||
* associated with the LWP facility.
|
||
*
|
||
* \subsubsection sec2-3-5-1 Section 2.3.5.1: FT Init _ Initialize the
|
||
* fast time package
|
||
*
|
||
* \par
|
||
* int FT Init(IN int printErrors; IN int notReally)
|
||
* \par Description
|
||
* This routine initializes the fast time package, mapping in the kernel page
|
||
* containing the time-of-day variable. The printErrors argument, if non-zero,
|
||
* will cause any errors in initalization to be printed to stderr. The
|
||
* notReally parameter specifies whether initialization is really to be done.
|
||
* Other calls in this package will do auto-initialization, and hence the
|
||
* option is offered here.
|
||
* \par Error Codes
|
||
* -1 Indicates that future calls to FT GetTimeOfDay() will still work, but
|
||
* will not be able to access the information directly, having to make a
|
||
* kernel call every time.
|
||
*
|
||
* \subsubsection sec2-3-5-2 Section 2.3.5.2: FT GetTimeOfDay _ Initialize
|
||
* the fast time package
|
||
*
|
||
* \par
|
||
* int FT GetTimeOfDay(IN struct timeval *tv; IN struct timezone *tz)
|
||
* \par Description
|
||
* This routine is meant to mimic the parameters and behavior of the unix
|
||
* gettimeofday() function. However, as implemented, it simply calls
|
||
* gettimeofday() and then does some bound-checking to make sure the value is
|
||
* reasonable.
|
||
* \par Error Codes
|
||
* <misc> Whatever value was returned by gettimeofday() internally.
|
||
*
|
||
* \subsection sec2-3-6 Section 2.3.6: Preemption
|
||
* \par
|
||
* This section covers the calling interface to the preemption package
|
||
* associated with the LWP facility.
|
||
*
|
||
* \subsubsection sec2-3-6-1 Section 2.3.6.1: PRE InitPreempt _ Initialize
|
||
* the preemption package
|
||
*
|
||
* \par
|
||
* int PRE InitPreempt(IN struct timeval *slice)
|
||
* \par Description
|
||
* This function must be called to initialize the preemption package. It must
|
||
* appear sometime after the call to LWP InitializeProcessSupport() and
|
||
* sometime before the first call to any other preemption routine. The slice
|
||
* argument specifies the time slice size to use. If the slice pointer is set
|
||
* to null in the call, then the default time slice, DEFAULTSLICE (10
|
||
* milliseconds), will be used. This routine uses the unix interval timer and
|
||
* handling of the unix alarm signal, SIGALRM, to implement this timeslicing.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package hasn't been initialized.
|
||
* \n LWP ESYSTEM Operations on the signal vector or the interval timer have
|
||
* failed.
|
||
*
|
||
* \subsubsection sec2-3-6-2 Section 2.3.6.2: PRE EndPreempt _ finalize
|
||
* the preemption package
|
||
*
|
||
* \par
|
||
* int PRE EndPreempt()
|
||
* \par Description
|
||
* This routine finalizes use of the preemption package. No further preemptions
|
||
* will be made. Note that it is not necessary to make this call before exit.
|
||
* PRE EndPreempt() is provided only for those applications that wish to
|
||
* continue after turning off preemption.
|
||
* \par Error Codes
|
||
* LWP EINIT The LWP package hasn't been initialized.
|
||
* \n LWP ESYSTEM Operations on the signal vector or the interval timer have
|
||
* failed.
|
||
*
|
||
* \subsubsection sec2-3-6-3 Section 2.3.6.3: PRE PreemptMe _ Mark thread
|
||
* as preemptible
|
||
*
|
||
* \par
|
||
* int PRE PreemptMe()
|
||
* \par Description
|
||
* This macro is used to signify the current thread as a candidate for
|
||
* preemption. The LWP InitializeProcessSupport() routine must have been called
|
||
* before PRE PreemptMe().
|
||
* \par Error Codes
|
||
* ---No return code is generated.
|
||
*
|
||
* \subsubsection sec2-3-6-4 Section 2.3.6.4: PRE BeginCritical _ Enter
|
||
* thread critical section
|
||
*
|
||
* \par
|
||
* int PRE BeginCritical()
|
||
* \par Description
|
||
* This macro places the current thread in a critical section. Upon return, and
|
||
* for as long as the thread is in the critical section, involuntary
|
||
* preemptions of this LWP will no longer occur.
|
||
* \par Error Codes
|
||
* ---No return code is generated.
|
||
*
|
||
* \subsubsection sec2-3-6-5 Section 2.3.6.5: PRE EndCritical _ Exit
|
||
* thread critical section
|
||
*
|
||
* \par
|
||
* int PRE EndCritical()
|
||
* \par Description
|
||
* This macro causes the executing thread to leave a critical section
|
||
* previously entered via PRE BeginCritical(). If involuntary preemptions were
|
||
* possible before the matching PRE BeginCritical(), they are once again
|
||
* possible.
|
||
* \par Error Codes
|
||
* ---No return code is generated.
|
||
*
|
||
* \page chap3 Chapter 3 -- Rxkad
|
||
*
|
||
*
|
||
* \section sec3-1 Section 3.1: Introduction
|
||
*
|
||
* \par
|
||
* The rxkad security module is offered as one of the built-in Rx
|
||
* authentication models. It is based on the Kerberos system developed by MIT's
|
||
* Project Athena. Readers wishing detailed information regarding Kerberos
|
||
* design and implementation are directed to [2]. This chapter is devoted to
|
||
* defining how Kerberos authentication services are made available as Rx
|
||
* components, and assumes the reader has some familiarity with Kerberos.
|
||
* Included are descriptions of how client-side and server-side Rx security
|
||
* objects (struct rx securityClass; see Section 5.3.1.1) implementing this
|
||
* protocol may be generated by an Rx application. Also, a description appears
|
||
* of the set of routines available in the associated struct rx securityOps
|
||
* structures, as covered in Section 5.3.1.2. It is strongly recommended that
|
||
* the reader become familiar with this section on struct rx securityOps before
|
||
* reading on.
|
||
*
|
||
* \section sec3-2 Section 3.2: Definitions
|
||
*
|
||
* \par
|
||
* An important set of definitions related to the rxkad security package is
|
||
* provided by the rxkad.h include file. Determined here are various values for
|
||
* ticket lifetimes, along with structures for encryption keys and Kerberos
|
||
* principals. Declarations for the two routines required to generate the
|
||
* different rxkad security objects also appear here. The two functions are
|
||
* named rxkad NewServerSecurityObject() and rxkad NewClientSecurityObject().
|
||
* In addition, type field values, encryption levels, security index
|
||
* operations, and statistics structures may be found in this file.
|
||
* \section sec3-3 Section 3.3: Exported Objects
|
||
* \par
|
||
* To be usable as an Rx security module, the rxkad facility exports routines
|
||
* to create server-side and client-side security objects. The server
|
||
* authentication object is incorporated into the server code when calling rx
|
||
* NewService(). The client authentication object is incorporated into the
|
||
* client code every time a connection is established via rx NewConnection().
|
||
* Also, in order to implement these security objects, the rxkad module must
|
||
* provide definitions for some subset of the generic security operations as
|
||
* defined in the appropriate struct rx securityOps variable.
|
||
*
|
||
* \subsection sec3-3-1 Section 3.3.1: Server-Side Mechanisms
|
||
*
|
||
* \subsubsection sec3-3-1-1 Section 3.3.1.1: Security Operations
|
||
*
|
||
* \par
|
||
* The server side of the rxkad module fills in all but two of the possible
|
||
* routines associated with an Rx security object, as described in Section
|
||
* 5.3.1.2.
|
||
*
|
||
* \code
|
||
* static struct rx_securityOps rxkad_server_ops = {
|
||
* rxkad_Close,
|
||
* rxkad_NewConnection,
|
||
* rxkad_PreparePacket, /* Once per packet creation */
|
||
* 0, /* Send packet (once per retrans) */
|
||
* rxkad_CheckAuthentication,
|
||
* rxkad_CreateChallenge,
|
||
* rxkad_GetChallenge,
|
||
* 0,
|
||
* rxkad_CheckResponse, /* Check data packet */
|
||
* rxkad_DestroyConnection,
|
||
* rxkad_GetStats,
|
||
* };
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The rxkad service does not need to take any special action each time a
|
||
* packet belonging to a call in an rxkad Rx connection is physically
|
||
* transmitted. Thus, a routine is not supplied for the op SendPacket()
|
||
* function slot. Similarly, no preparatory work needs to be done previous to
|
||
* the reception of a response packet from a security challenge, so the op
|
||
* GetResponse() function slot is also empty.
|
||
*
|
||
* \subsubsection sec3-3-1-2 Section 3.3.1.2: Security Object
|
||
*
|
||
* \par
|
||
* The exported routine used to generate an rxkad-specific server-side security
|
||
* class object is named rxdad NewServerSecurityObject(). It is declared with
|
||
* four parameters, as follows:
|
||
*
|
||
* \code
|
||
* struct rx_securityClass *
|
||
* rxkad_NewServerSecurityObject(a_level, a_getKeyRockP, a_getKeyP, a_userOKP)
|
||
* rxkad_level a_level; /* Minimum level */
|
||
* char *a_getKeyRockP; /* Rock for get_key implementor */
|
||
* int (*a_getKeyP)(); /* Passed kvno & addr(key) to fill */
|
||
* int (*a_userOKP)(); /* Passed name, inst, cell => bool */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The first argument specifies the desired level of encryption, and may take
|
||
* on the following values (as defined in rxkad.h):
|
||
* \li rxkad clear: Specifies that packets are to be sent entirely in the
|
||
* clear, without any encryption whatsoever.
|
||
* \li rxkad auth: Specifies that packet sequence numbers are to be encrypted.
|
||
* \li rxkad crypt: Specifies that the entire data packet is to be encrypted.
|
||
*
|
||
* \par
|
||
* The second and third parameters represent, respectively, a pointer to a
|
||
* private data area, sometimes called a "rock", and a procedure reference that
|
||
* is called with the key version number accompanying the Kerberos ticket and
|
||
* returns a pointer to the server's decryption key. The fourth argument, if
|
||
* not null, is a pointer to a function that will be called for every new
|
||
* connection with the client's name, instance, and cell. This routine should
|
||
* return zero if the user is not acceptable to the server.
|
||
*
|
||
* \subsection sec3-3-2 Section 3.3.2: Client-Side Mechanisms
|
||
*
|
||
* \subsubsection sec3-3-2-1 Section 3.3.2.1: Security Operations
|
||
*
|
||
* \par
|
||
* The client side of the rxkad module fills in relatively few of the routines
|
||
* associated with an Rx security object, as demonstrated below. The general Rx
|
||
* security object, of which this is an instance, is described in detail in
|
||
* Section 5.3.1.2.
|
||
*
|
||
* \code
|
||
* static struct rx_securityOps rxkad_client_ops = {
|
||
* rxkad_Close,
|
||
* rxkad_NewConnection, /* Every new connection */
|
||
* rxkad_PreparePacket, /* Once per packet creation */
|
||
* 0, /* Send packet (once per retrans) */
|
||
* 0,
|
||
* 0,
|
||
* 0,
|
||
* rxkad_GetResponse, /* Respond to challenge packet */
|
||
* 0,
|
||
* rxkad_CheckPacket, /* Check data packet */
|
||
* rxkad_DestroyConnection,
|
||
* rxkad_GetStats,
|
||
* 0,
|
||
* 0,
|
||
* 0,
|
||
* };
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* As expected, routines are defined for use when someone destroys a security
|
||
* object (rxkad Close()) and when an Rx connection using the rxkad model
|
||
* creates a new connection (rxkad NewConnection()) or deletes an existing one
|
||
* (rxkad DestroyConnection()). Security-specific operations must also be
|
||
* performed in behalf of rxkad when packets are created (rxkad
|
||
* PreparePacket()) and received (rxkad CheckPacket()). finally, the client
|
||
* side of an rxkad security object must also be capable of constructing
|
||
* responses to security challenges from the server (rxkad GetResponse()) and
|
||
* be willing to reveal statistics on its own operation (rxkad GetStats()).
|
||
*
|
||
* \subsubsection sec3-3-2-2 Section 3.3.2.2: Security Object
|
||
*
|
||
* \par
|
||
* The exported routine used to generate an rxkad-specific client-side security
|
||
* class object is named rxkad NewClientSecurityObject(). It is declared with
|
||
* five parameters, specified below:
|
||
*
|
||
* \code
|
||
* struct rx_securityClass * rxkad_NewClientSecurityObject(
|
||
* a_level,
|
||
* a_sessionKeyP,
|
||
* a_kvno,
|
||
* a_ticketLen,
|
||
* a_ticketP
|
||
* )
|
||
* rxkad_level a_level;
|
||
* struct ktc_encryptionKey *a_sessionKeyP;
|
||
* long a_kvno;
|
||
* int a_ticketLen;
|
||
* char *a_ticketP;
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The first parameter, a level, specifies the level of encryption desired for
|
||
* this security object, with legal choices being identical to those defined
|
||
* for the server-side security object described in Section 3.3.1.2. The second
|
||
* parameter, a sessionKeyP, provides the session key to use. The ktc
|
||
* encryptionKey structure is defined in the rxkad.h include file, and consists
|
||
* of an array of 8 characters. The third parameter, a kvno, provides the key
|
||
* version number associated with a sessionKeyP. The fourth argument, a
|
||
* ticketLen, communicates the length in bytes of the data stored in the fifth
|
||
* parameter, a ticketP, which points to the Kerberos ticket to use for the
|
||
* principal for which the security object will operate.
|
||
*
|
||
* \page chap4 Chapter 4 -- Rx Support Packages
|
||
*
|
||
* \section sec4-1 Section 4.1: Introduction
|
||
* \par
|
||
* This chapter documents three packages defined directly in support of the Rx
|
||
* facility.
|
||
* \li rx queue: Doubly-linked queue package.
|
||
* \li rx clock: Clock package, using the 4.3BSD interval timer.
|
||
* \li rx event: Future events package.
|
||
* \par
|
||
* References to constants, structures, and functions defined by these support
|
||
* packages will appear in the following API chapter.
|
||
*
|
||
* \section sec4-2 Section 4.2: The rx queue Package
|
||
*
|
||
* \par
|
||
* This package provides a doubly-linked queue structure, along with a full
|
||
* suite of related operations. The main concern behind the coding of this
|
||
* facility was efficiency. All functions are implemented as macros, and it is
|
||
* suggested that only simple expressions be used for all parameters.
|
||
* \par
|
||
* The rx queue facility is defined by the rx queue.h include file. Some macros
|
||
* visible in this file are intended for rx queue internal use only. An
|
||
* understanding of these "hidden" macros is important, so they will also be
|
||
* described by this document.
|
||
*
|
||
* \subsection sec4-2-1 Section 4.2.1: struct queue
|
||
*
|
||
* \par
|
||
* The queue structure provides the linkage information required to maintain a
|
||
* queue of objects. The queue structure is prepended to any user-defined data
|
||
* type which is to be organized in this fashion.
|
||
* \n \b fields
|
||
* \li struct queue *prev - Pointer to the previous queue header.
|
||
* \li struct queue *next - Pointer to the next queue header.
|
||
* \par
|
||
* Note that a null Rx queue consists of a single struct queue object whose
|
||
* next and previous pointers refer to itself.
|
||
*
|
||
* \subsection sec4-2-2 Section 4.2.2: Internal Operations
|
||
*
|
||
* \par
|
||
* This section describes the internal operations defined for Rx queues. They
|
||
* will be referenced by the external operations documented in Section 4.2.3.
|
||
*
|
||
* \subsection sec4-2-2-1 Section 4.2.2.1: Q(): Coerce type to a queue
|
||
* element
|
||
*
|
||
* \par
|
||
* \#define _Q(x) ((struct queue *)(x))
|
||
* \par
|
||
* This operation coerces the user structure named by x to a queue element. Any
|
||
* user structure using the rx queue package must have a struct queue as its
|
||
* first field.
|
||
*
|
||
* \subsubsection sec4-2-2-2 Section 4.2.2.2: QA(): Add a queue element
|
||
* before/after another element
|
||
*
|
||
* \par
|
||
* \#define _QA(q,i,a,b) (((i->a=q->a)->b=i)->b=q, q->a=i)
|
||
* \par
|
||
* This operation adds the queue element referenced by i either before or after
|
||
* a queue element represented by q. If the (a, b) argument pair corresponds to
|
||
* an element's (next, prev) fields, the new element at i will be linked after
|
||
* q. If the (a, b) argument pair corresponds to an element's (prev, next)
|
||
* fields, the new element at i will be linked before q.
|
||
*
|
||
* \subsubsection sec4-2-2-3 QR(): Remove a queue element
|
||
*
|
||
* \par
|
||
* \#define _QR(i) ((_Q(i)->prev->next=_Q(i)->next)->prev=_Q(i)->prev)
|
||
* \par
|
||
* This operation removes the queue element referenced by i from its queue. The
|
||
* prev and next fields within queue element i itself is not updated to reflect
|
||
* the fact that it is no longer part of the queue.
|
||
*
|
||
* \subsubsection sec4-2-2-4 QS(): Splice two queues together
|
||
*
|
||
* \par
|
||
* \#define _QS(q1,q2,a,b) if (queue_IsEmpty(q2)); else
|
||
* ((((q2->a->b=q1)->a->b=q2->b)->a=q1->a, q1->a=q2->a), queue_Init(q2))
|
||
* \par
|
||
* This operation takes the queues identified by q1 and q2 and splices them
|
||
* together into a single queue. The order in which the two queues are appended
|
||
* is determined by the a and b arguments. If the (a, b) argument pair
|
||
* corresponds to q1's (next, prev) fields, then q2 is appended to q1. If the
|
||
* (a, b) argument pair corresponds to q1's (prev, next) fields, then q is
|
||
* prepended to q2.
|
||
* \par
|
||
* This internal QS() routine uses two exported queue operations, namely queue
|
||
* Init() and queue IsEmpty(), defined in Sections 4.2.3.1 and 4.2.3.16
|
||
* respectively below.
|
||
*
|
||
* \subsection sec4-2-3 Section 4.2.3: External Operations
|
||
*
|
||
* \subsubsection sec4-2-3-1 Section 4.2.3.1: queue Init(): Initialize a
|
||
* queue header
|
||
*
|
||
* \par
|
||
* \#define queue_Init(q) (_Q(q))->prev = (_Q(q))->next = (_Q(q))
|
||
* \par
|
||
* The queue header referred to by the q argument is initialized so that it
|
||
* describes a null (empty) queue. A queue head is simply a queue element.
|
||
*
|
||
* \subsubsection sec4-2-3-2 Section 4.2.3.2: queue Prepend(): Put element
|
||
* at the head of a queue
|
||
*
|
||
* \par
|
||
* \#define queue_Prepend(q,i) _QA(_Q(q),_Q(i),next,prev)
|
||
* \par
|
||
* Place queue element i at the head of the queue denoted by q. The new queue
|
||
* element, i, should not currently be on any queue.
|
||
*
|
||
* \subsubsection sec4-2-3-3 Section 4.2.3.3: queue Append(): Put an
|
||
* element a the tail of a queue
|
||
*
|
||
* \par
|
||
* \#define queue_Append(q,i) _QA(_Q(q),_Q(i),prev,next)
|
||
* \par
|
||
* Place queue element i at the tail of the queue denoted by q. The new queue
|
||
* element, i, should not currently be on any queue.
|
||
*
|
||
* \subsection sec4-2-3-4 Section 4.2.3.4: queue InsertBefore(): Insert a
|
||
* queue element before another element
|
||
*
|
||
* \par
|
||
* \#define queue_InsertBefore(i1,i2) _QA(_Q(i1),_Q(i2),prev,next)
|
||
* \par
|
||
* Insert queue element i2 before element i1 in i1's queue. The new queue
|
||
* element, i2, should not currently be on any queue.
|
||
*
|
||
* \subsubsection sec4-2-3-5 Section 4.2.3.5: queue InsertAfter(): Insert
|
||
* a queue element after another element
|
||
*
|
||
* \par
|
||
* \#define queue_InsertAfter(i1,i2) _QA(_Q(i1),_Q(i2),next,prev)
|
||
* \par
|
||
* Insert queue element i2 after element i1 in i1's queue. The new queue
|
||
* element, i2, should not currently be on any queue.
|
||
*
|
||
* \subsubsection sec4-2-3-6 Section: 4.2.3.6: queue SplicePrepend():
|
||
* Splice one queue before another
|
||
*
|
||
* \par
|
||
* \#define queue_SplicePrepend(q1,q2) _QS(_Q(q1),_Q(q2),next,prev)
|
||
* \par
|
||
* Splice the members of the queue located at q2 to the beginning of the queue
|
||
* located at q1, reinitializing queue q2.
|
||
*
|
||
* \subsubsection sec4-2-3-7 Section 4.2.3.7: queue SpliceAppend(): Splice
|
||
* one queue after another
|
||
*
|
||
* \par
|
||
* \#define queue_SpliceAppend(q1,q2) _QS(_Q(q1),_Q(q2),prev,next)
|
||
* \par
|
||
* Splice the members of the queue located at q2 to the end of the queue
|
||
* located at q1, reinitializing queue q2. Note that the implementation of
|
||
* queue SpliceAppend() is identical to that of queue SplicePrepend() except
|
||
* for the order of the next and prev arguments to the internal queue splicer,
|
||
* QS().
|
||
*
|
||
* \subsubsection sec4-2-3-8 Section 4.2.3.8: queue Replace(): Replace the
|
||
* contents of a queue with that of another
|
||
*
|
||
* \par
|
||
* \#define queue_Replace(q1,q2) (*_Q(q1) = *_Q(q2),
|
||
* \n _Q(q1)->next->prev = _Q(q1)->prev->next = _Q(q1),
|
||
* \n queue_Init(q2))
|
||
* \par
|
||
* Replace the contents of the queue located at q1 with the contents of the
|
||
* queue located at q2. The prev and next fields from q2 are copied into the
|
||
* queue object referenced by q1, and the appropriate element pointers are
|
||
* reassigned. After the replacement has occurred, the queue header at q2 is
|
||
* reinitialized.
|
||
*
|
||
* \subsubsection sec4-2-3-9 Section 4.2.3.9: queue Remove(): Remove an
|
||
* element from its queue
|
||
*
|
||
* \par
|
||
* \#define queue_Remove(i) (_QR(i), _Q(i)->next = 0)
|
||
* \par
|
||
* This function removes the queue element located at i from its queue. The
|
||
* next field for the removed entry is zeroed. Note that multiple removals of
|
||
* the same queue item are not supported.
|
||
*
|
||
* \subsubsection sec4-2-3-10 Section 4.2.3.10: queue MoveAppend(): Move
|
||
* an element from its queue to the end of another queue
|
||
*
|
||
* \par
|
||
* \#define queue_MoveAppend(q,i) (_QR(i), queue_Append(q,i))
|
||
* \par
|
||
* This macro removes the queue element located at i from its current queue.
|
||
* Once removed, the element at i is appended to the end of the queue located
|
||
* at q.
|
||
*
|
||
* \subsubsection sec4-2-3-11 Section 4.2.3.11: queue MovePrepend(): Move
|
||
* an element from its queue to the head of another queue
|
||
*
|
||
* \par
|
||
* \#define queue_MovePrepend(q,i) (_QR(i), queue_Prepend(q,i))
|
||
* \par
|
||
* This macro removes the queue element located at i from its current queue.
|
||
* Once removed, the element at i is inserted at the head fo the queue located
|
||
* at q.
|
||
*
|
||
* \subsubsection sec4-2-3-12 Section 4.2.3.12: queue first(): Return the
|
||
* first element of a queue, coerced to a particular type
|
||
*
|
||
* \par
|
||
* \#define queue_first(q,s) ((struct s *)_Q(q)->next)
|
||
* \par
|
||
* Return a pointer to the first element of the queue located at q. The
|
||
* returned pointer value is coerced to conform to the given s structure. Note
|
||
* that a properly coerced pointer to the queue head is returned if q is empty.
|
||
*
|
||
* \subsubsection sec4-2-3-13 Section 4.2.3.13: queue Last(): Return the
|
||
* last element of a queue, coerced to a particular type
|
||
*
|
||
* \par
|
||
* \#define queue_Last(q,s) ((struct s *)_Q(q)->prev)
|
||
* \par
|
||
* Return a pointer to the last element of the queue located at q. The returned
|
||
* pointer value is coerced to conform to the given s structure. Note that a
|
||
* properly coerced pointer to the queue head is returned if q is empty.
|
||
*
|
||
* \subsubsection sec4-2-3-14 Section 4.2.3.14: queue Next(): Return the
|
||
* next element of a queue, coerced to a particular type
|
||
*
|
||
* \par
|
||
* \#define queue_Next(i,s) ((struct s *)_Q(i)->next)
|
||
* \par
|
||
* Return a pointer to the queue element occuring after the element located at
|
||
* i. The returned pointer value is coerced to conform to the given s
|
||
* structure. Note that a properly coerced pointer to the queue head is
|
||
* returned if item i is the last in its queue.
|
||
*
|
||
* \subsubsection sec4-2-3-15 Section 4.2.3.15: queue Prev(): Return the
|
||
* next element of a queue, coerced to a particular type
|
||
*
|
||
* \par
|
||
* \#define queue_Prev(i,s) ((struct s *)_Q(i)->prev)
|
||
* \par
|
||
* Return a pointer to the queue element occuring before the element located at
|
||
* i. The returned pointer value is coerced to conform to the given s
|
||
* structure. Note that a properly coerced pointer to the queue head is
|
||
* returned if item i is the first in its queue.
|
||
*
|
||
* \subsubsection sec4-2-3-16 Section 4.2.3.16: queue IsEmpty(): Is the
|
||
* given queue empty?
|
||
*
|
||
* \par
|
||
* \#define queue_IsEmpty(q) (_Q(q)->next == _Q(q))
|
||
* \par
|
||
* Return a non-zero value if the queue located at q does not have any elements
|
||
* in it. In this case, the queue consists solely of the queue header at q
|
||
* whose next and prev fields reference itself.
|
||
*
|
||
* \subsubsection sec4-2-3-17 Section 4.2.3.17: queue IsNotEmpty(): Is the
|
||
* given queue not empty?
|
||
*
|
||
* \par
|
||
* \#define queue_IsNotEmpty(q) (_Q(q)->next != _Q(q))
|
||
* \par
|
||
* Return a non-zero value if the queue located at q has at least one element
|
||
* in it other than the queue header itself.
|
||
*
|
||
* \subsubsection sec4-2-3-18 Section 4.2.3.18: queue IsOnQueue(): Is an
|
||
* element currently queued?
|
||
*
|
||
* \par
|
||
* \#define queue_IsOnQueue(i) (_Q(i)->next != 0)
|
||
* \par
|
||
* This macro returns a non-zero value if the queue item located at i is
|
||
* currently a member of a queue. This is determined by examining its next
|
||
* field. If it is non-null, the element is considered to be queued. Note that
|
||
* any element operated on by queue Remove() (Section 4.2.3.9) will have had
|
||
* its next field zeroed. Hence, it would cause a non-zero return from this
|
||
* call.
|
||
*
|
||
* \subsubsection sec4-2-3-19 Section 4.2.3.19: queue Isfirst(): Is an
|
||
* element the first on a queue?
|
||
*
|
||
* \par
|
||
* \#define queue_Isfirst(q,i) (_Q(q)->first == _Q(i))
|
||
* \par
|
||
* This macro returns a non-zero value if the queue item located at i is the
|
||
* first element in the queue denoted by q.
|
||
*
|
||
* \subsubsection sec4-2-3-20 Section 4.2.3.20: queue IsLast(): Is an
|
||
* element the last on a queue?
|
||
*
|
||
* \par
|
||
* \#define queue_IsLast(q,i) (_Q(q)->prev == _Q(i))
|
||
* \par
|
||
* This macro returns a non-zero value if the queue item located at i is the
|
||
* last element in the queue denoted by q.
|
||
*
|
||
* \subsubsection sec4-2-3-21 Section 4.2.3.21: queue IsEnd(): Is an
|
||
* element the end of a queue?
|
||
*
|
||
* \par
|
||
* \#define queue_IsEnd(q,i) (_Q(q) == _Q(i))
|
||
* \par
|
||
* This macro returns a non-zero value if the queue item located at i is the
|
||
* end of the queue located at q. Basically, it determines whether a queue
|
||
* element in question is also the queue header structure itself, and thus does
|
||
* not represent an actual queue element. This function is useful for
|
||
* terminating an iterative sweep through a queue, identifying when the search
|
||
* has wrapped to the queue header.
|
||
*
|
||
* \subsubsection sec4-2-3-22 Section 4.2.3.22: queue Scan(): for loop
|
||
* test for scanning a queue in a forward direction
|
||
*
|
||
* \par
|
||
* \#define queue_Scan(q, qe, next, s)
|
||
* \n (qe) = queue_first(q, s), next = queue_Next(qe, s);
|
||
* \n !queue_IsEnd(q, qe);
|
||
* \n (qe) = (next), next = queue_Next(qe, s)
|
||
* \par
|
||
* This macro may be used as the body of a for loop test intended to scan
|
||
* through each element in the queue located at q. The qe argument is used as
|
||
* the for loop variable. The next argument is used to store the next value for
|
||
* qe in the upcoming loop iteration. The s argument provides the name of the
|
||
* structure to which each queue element is to be coerced. Thus, the values
|
||
* provided for the qe and next arguments must be of type (struct s *).
|
||
* \par
|
||
* An example of how queue Scan() may be used appears in the code fragment
|
||
* below. It declares a structure named mystruct, which is suitable for
|
||
* queueing. This queueable structure is composed of the queue pointers
|
||
* themselves followed by an integer value. The actual queue header is kept in
|
||
* demoQueue, and the currItemP and nextItemP variables are used to step
|
||
* through the demoQueue. The queue Scan() macro is used in the for loop to
|
||
* generate references in currItemP to each queue element in turn for each
|
||
* iteration. The loop is used to increment every queued structure's myval
|
||
* field by one.
|
||
*
|
||
* \code
|
||
* struct mystruct {
|
||
* struct queue q;
|
||
* int myval;
|
||
* };
|
||
* struct queue demoQueue;
|
||
* struct mystruct *currItemP, *nextItemP;
|
||
* ...
|
||
* for (queue_Scan(&demoQueue, currItemP, nextItemP, mystruct)) {
|
||
* currItemP->myval++;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Note that extra initializers can be added before the body of the queue
|
||
* Scan() invocation above, and extra expressions can be added afterwards.
|
||
*
|
||
* \subsubsection sec4-2-3-23 Section 4.2.3.23: queue ScanBackwards(): for
|
||
* loop test for scanning a queue in a reverse direction
|
||
*
|
||
* \par
|
||
* #define queue_ScanBackwards(q, qe, prev, s)
|
||
* \n (qe) = queue_Last(q, s), prev = queue_Prev(qe, s);
|
||
* \n !queue_IsEnd(q, qe);
|
||
* \n (qe) = prev, prev = queue_Prev(qe, s)
|
||
* \par
|
||
* This macro is identical to the queue Scan() macro described above in Section
|
||
* 4.2.3.22 except for the fact that the given queue is scanned backwards,
|
||
* starting at the last item in the queue.
|
||
*
|
||
* \section sec4-3 Section 4.3: The rx clock Package
|
||
*
|
||
* \par
|
||
* This package maintains a clock which is independent of the time of day. It
|
||
* uses the unix 4.3BSD interval timer (e.g., getitimer(), setitimer()) in
|
||
* TIMER REAL mode. Its definition and interface may be found in the rx clock.h
|
||
* include file.
|
||
*
|
||
* \subsection sec4-3-1 Section 4.3.1: struct clock
|
||
*
|
||
* \par
|
||
* This structure is used to represent a clock value as understood by this
|
||
* package. It consists of two fields, storing the number of seconds and
|
||
* microseconds that have elapsed since the associated clock Init() routine has
|
||
* been called.
|
||
* \par
|
||
* \b fields
|
||
* \n long sec -Seconds since call to clock Init().
|
||
* \n long usec -Microseconds since call to clock Init().
|
||
*
|
||
* \subsection sec4-3-2 Section 4.3.12: clock nUpdates
|
||
*
|
||
* \par
|
||
* The integer-valued clock nUpdates is a variable exported by the rx clock
|
||
* facility. It records the number of times the clock value is actually
|
||
* updated. It is bumped each time the clock UpdateTime() routine is called, as
|
||
* described in Section 4.3.3.2.
|
||
*
|
||
* \subsection sec4-3-3 Section 4.3.3: Operations
|
||
*
|
||
* \subsubsection sec4-3-3-1 Section 4.3.3.1: clock Init(): Initialize the
|
||
* clock package
|
||
*
|
||
* \par
|
||
* This routine uses the unix setitimer() call to initialize the unix interval
|
||
* timer. If the setitimer() call fails, an error message will appear on
|
||
* stderr, and an exit(1) will be executed.
|
||
*
|
||
* \subsubsection sec4-3-3-2 Section 4.3.3.2: clock UpdateTime(): Compute
|
||
* the current time
|
||
*
|
||
* \par
|
||
* The clock UpdateTime() function calls the unix getitimer() routine in order
|
||
* to update the current time. The exported clock nUpdates variable is
|
||
* incremented each time the clock UpdateTime() routine is called.
|
||
*
|
||
* \subsubsection sec4-3-3-3 Section 4.3.3.3: clock GetTime(): Return the
|
||
* current clock time
|
||
*
|
||
* \par
|
||
* This macro updates the current time if necessary, and returns the current
|
||
* time into the cv argument, which is declared to be of type (struct clock *).
|
||
* 4.3.3.4 clock Sec(): Get the current clock time, truncated to seconds
|
||
* This macro returns the long value of the sec field of the current time. The
|
||
* recorded time is updated if necessary before the above value is returned.
|
||
*
|
||
* \subsubsection sec4-3-3-5 Section 4.3.3.5: clock ElapsedTime(): Measure
|
||
* milliseconds between two given clock values
|
||
*
|
||
* \par
|
||
* This macro returns the elapsed time in milliseconds between the two clock
|
||
* structure pointers provided as arguments, cv1 and cv2.
|
||
*
|
||
* \subsubsection sec4-3-3-6 Section 4.3.3.6: clock Advance(): Advance the
|
||
* recorded clock time by a specified clock value
|
||
*
|
||
* \par
|
||
* This macro takes a single (struct clock *) pointer argument, cv, and adds
|
||
* this clock value to the internal clock value maintined by the package.
|
||
*
|
||
* \subsubsection sec4-3-3-7 Section 4.3.3.7: clock Gt(): Is a clock value
|
||
* greater than another?
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), a and b. It
|
||
* returns a nonzero value if the a parameter points to a clock value which is
|
||
* later than the one pointed to by b.
|
||
*
|
||
* \subsubsection sec4-3-3-8 Section 4.3.3.8: clock Ge(): Is a clock value
|
||
* greater than or equal to another?
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), a and b. It
|
||
* returns a nonzero value if the a parameter points to a clock value which is
|
||
* greater than or equal to the one pointed to by b.
|
||
*
|
||
* \subsubsection sec4-3-3-9 Section 4.3.3.9: clock Gt(): Are two clock
|
||
* values equal?
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), a and b. It
|
||
* returns a non-zero value if the clock values pointed to by a and b are
|
||
* equal.
|
||
*
|
||
* \subsubsection sec4.3.3.10 Section 4.3.3.10: clock Le(): Is a clock
|
||
* value less than or equal to another?
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), a and b. It
|
||
* returns a nonzero value if the a parameter points to a clock value which is
|
||
* less than or equal to the one pointed to by b.
|
||
*
|
||
* \subsubsection sec4-3-3-11 Section 4.3.3.11: clock Lt(): Is a clock
|
||
* value less than another?
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), a and b. It
|
||
* returns a nonzero value if the a parameter points to a clock value which is
|
||
* less than the one pointed to by b.
|
||
*
|
||
* \subsubsection sec4-3-3-12 Section 4.3.3.12: clock IsZero(): Is a clock
|
||
* value zero?
|
||
*
|
||
* \par
|
||
* This macro takes a single parameter of type (struct clock *), c. It returns
|
||
* a non-zero value if the c parameter points to a clock value which is equal
|
||
* to zero.
|
||
*
|
||
* \subsubsection sec4-3-3-13 Section 4.3.3.13: clock Zero(): Set a clock
|
||
* value to zero
|
||
*
|
||
* \par
|
||
* This macro takes a single parameter of type (struct clock *), c. It sets the
|
||
* given clock value to zero.
|
||
* \subsubsection sec4-3-3-14 Section 4.3.3.14: clock Add(): Add two clock
|
||
* values together
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), c1 and c2. It adds
|
||
* the value of the time in c2 to c1. Both clock values must be positive.
|
||
*
|
||
* \subsubsection sec4-3-3-15 Section 4.3.3.15: clock Sub(): Subtract two
|
||
* clock values
|
||
*
|
||
* \par
|
||
* This macro takes two parameters of type (struct clock *), c1 and c2. It
|
||
* subtracts the value of the time in c2 from c1. The time pointed to by c2
|
||
* should be less than the time pointed to by c1.
|
||
*
|
||
* \subsubsection sec4-3-3-16 Section 4.3.3.16: clock Float(): Convert a
|
||
* clock time into floating point
|
||
*
|
||
* \par
|
||
* This macro takes a single parameter of type (struct clock *), c. It
|
||
* expresses the given clock value as a floating point number.
|
||
*
|
||
* \section sec4-4 Section 4.4: The rx event Package
|
||
*
|
||
* \par
|
||
* This package maintains an event facility. An event is defined to be
|
||
* something that happens at or after a specified clock time, unless cancelled
|
||
* prematurely. The clock times used are those provided by the rx clock
|
||
* facility described in Section 4.3 above. A user routine associated with an
|
||
* event is called with the appropriate arguments when that event occurs. There
|
||
* are some restrictions on user routines associated with such events. first,
|
||
* this user-supplied routine should not cause process preemption. Also, the
|
||
* event passed to the user routine is still resident on the event queue at the
|
||
* time of invocation. The user must not remove this event explicitly (via an
|
||
* event Cancel(), see below). Rather, the user routine may remove or schedule
|
||
* any other event at this time.
|
||
* \par
|
||
* The events recorded by this package are kept queued in order of expiration
|
||
* time, so that the first entry in the queue corresponds to the event which is
|
||
* the first to expire. This interface is defined by the rx event.h include
|
||
* file.
|
||
*
|
||
* \subsection sec4-4-1 Section 4.4.1: struct rxevent
|
||
*
|
||
* \par
|
||
* This structure defines the format of an Rx event record.
|
||
* \par
|
||
* \b fields
|
||
* \n struct queue junk -The queue to which this event belongs.
|
||
* \n struct clock eventTime -The clock time recording when this event comes
|
||
* due.
|
||
* \n int (*func)() -The user-supplied function to call upon expiration.
|
||
* \n char *arg -The first argument to the (*func)() function above.
|
||
* \n char *arg1 -The second argument to the (*func)() function above.
|
||
*
|
||
* \subsection sec4-4-2 Section 4.4.2: Operations
|
||
*
|
||
* \par
|
||
* This section covers the interface routines provided for the Rx event
|
||
* package.
|
||
*
|
||
* \subsubsection sec4-4-2-1 Section 4.4.2.1: rxevent Init(): Initialize
|
||
* the event package
|
||
*
|
||
* \par
|
||
* The rxevent Init() routine takes two arguments. The first, nEvents, is an
|
||
* integer-valued parameter which specifies the number of event structures to
|
||
* allocate at one time. This specifies the appropriate granularity of memory
|
||
* allocation by the event package. The second parameter, scheduler, is a
|
||
* pointer to an integer-valued function. This function is to be called when an
|
||
* event is posted (added to the set of events managed by the package) that is
|
||
* scheduled to expire before any other existing event.
|
||
* \par
|
||
* This routine sets up future event allocation block sizes, initializes the
|
||
* queues used to manage active and free event structures, and recalls that an
|
||
* initialization has occurred. Thus, this function may be safely called
|
||
* multiple times.
|
||
*
|
||
* \subsubsection sec4-4-2-2 Section 4.4.2.2: rxevent Post(): Schedule an
|
||
* event
|
||
*
|
||
* \par
|
||
* This function constructs a new event based on the information included in
|
||
* its parameters and then schedules it. The rxevent Post() routine takes four
|
||
* parameters. The first is named when, and is of type (struct clock *). It
|
||
* specifies the clock time at which the event is to occur. The second
|
||
* parameter is named func and is a pointer to the integer-valued function to
|
||
* associate with the event that will be created. When the event comes due,
|
||
* this function will be executed by the event package. The next two arguments
|
||
* to rxevent Post() are named arg and arg1, and are both of type (char *).
|
||
* They serve as the two arguments thath will be supplied to the func routine
|
||
* when the event comes due.
|
||
* \par
|
||
* If the given event is set to take place before any other event currently
|
||
* posted, the scheduler routine established when the rxevent Init() routine
|
||
* was called will be executed. This gives the application a chance to react to
|
||
* this new event in a reasonable way. One might expect that this scheduler
|
||
* routine will alter sleep times used by the application to make sure that it
|
||
* executes in time to handle the new event.
|
||
*
|
||
* \subsubsection sec4-4-2-3 Section 4.4.2.3: rxevent Cancel 1(): Cancel
|
||
* an event (internal use)
|
||
*
|
||
* \par
|
||
* This routine removes an event from the set managed by this package. It takes
|
||
* a single parameter named ev of type (struct rxevent *). The ev argument
|
||
* identifies the pending event to be cancelled.
|
||
* \par
|
||
* The rxevent Cancel 1() routine should never be called directly. Rather, it
|
||
* should be accessed through the rxevent Cancel() macro, described in Section
|
||
* 4.4.2.4 below.
|
||
*
|
||
* \subsubsection sec4-4-2-4 Section 4.4.2.4: rxevent Cancel(): Cancel an
|
||
* event (external use)
|
||
*
|
||
* \par
|
||
* This macro is the proper way to call the rxevent Cancel 1() routine
|
||
* described in Section 4.4.2.3 above. Like rxevent Cancel 1(), it takes a
|
||
* single argument. This event ptr argument is of type (struct rxevent *), and
|
||
* identi#es the pending event to be cancelled. This macro #rst checks to see
|
||
* if event ptr is null. If not, it calls rxevent Cancel 1() to perform the
|
||
* real work. The event ptr argument is zeroed after the cancellation operation
|
||
* completes.
|
||
*
|
||
* \subsubsection sec4-4-2-5 Section 4.4.2.4: rxevent RaiseEvents():
|
||
* Initialize the event package
|
||
*
|
||
* \par
|
||
* This function processes all events that have expired relative to the current
|
||
* clock time maintained by the event package. Each qualifying event is removed
|
||
* from the queue in order, and its user-supplied routine (func()) is executed
|
||
* with the associated arguments.
|
||
* \par
|
||
* The rxevent RaiseEvents() routine takes a single output parameter named
|
||
* next, defined to be of type (struct clock *). Upon completion of rxevent
|
||
* RaiseEvents(), the relative time to the next event due to expire is placed
|
||
* in next. This knowledge may be used to calculate the amount of sleep time
|
||
* before more event processing is needed. If there is no recorded event which
|
||
* is still pending at this point, rxevent RaiseEvents() returns a zeroed clock
|
||
* value into next.
|
||
*
|
||
* \subsubsection sec4-4-2-6 Section 4.4.2.6: rxevent TimeToNextEvent():
|
||
* Get amount of time until the next event expires
|
||
*
|
||
* \par
|
||
* This function returns the time between the current clock value as maintained
|
||
* by the event package and the the next event's expiration time. This
|
||
* information is placed in the single output argument,interval, defined to be
|
||
* of type (struct clock *). The rxevent TimeToNextEvent() function returns
|
||
* integer-valued quantities. If there are no scheduled events, a zero is
|
||
* returned. If there are one or more scheduled events, a 1 is returned. If
|
||
* zero is returned, the interval argument is not updated.
|
||
*
|
||
* \page chap5 Chapter 5 -- Programming Interface
|
||
*
|
||
* \section sec5-1 Section 5.1: Introduction
|
||
*
|
||
* \par
|
||
* This chapter documents the API for the Rx facility. Included are
|
||
* descriptions of all the constants, structures, exported variables, macros,
|
||
* and interface functions available to the application programmer. This
|
||
* interface is identical regardless of whether the application lives within
|
||
* the unix kernel or above it.
|
||
* \par
|
||
* This chapter actually provides more information than what may be strictly
|
||
* considered the Rx API. Many objects that were intended to be opaque and for
|
||
* Rx internal use only are also described here. The reason driving the
|
||
* inclusion of this "extra" information is that such exported Rx interface
|
||
* files as rx.h make these objects visible to application programmers. It is
|
||
* prefereable to describe these objects here than to ignore them and leave
|
||
* application programmers wondering as to their meaning.
|
||
* \par
|
||
* An example application illustrating the use of this interface, showcasing
|
||
* code from both server and client sides, appears in the following chapter.
|
||
*
|
||
* \section sec5-2 Section 5.2: Constants
|
||
*
|
||
* \par
|
||
* This section covers the basic constant definitions of interest to the Rx
|
||
* application programmer. Each subsection is devoted to describing the
|
||
* constants falling into the following categories:
|
||
* \li Configuration quantities
|
||
* \li Waiting options
|
||
* \li Connection ID operations
|
||
* \li Connection flags
|
||
* \li Connection types
|
||
* \li Call states
|
||
* \li Call flags
|
||
* \li Call modes
|
||
* \li Packet header flags
|
||
* \li Packet sizes
|
||
* \li Packet types
|
||
* \li Packet classes
|
||
* \li Conditions prompting ack packets
|
||
* \li Ack types
|
||
* \li Error codes
|
||
* \li Debugging values
|
||
* \par
|
||
* An attempt has been made to relate these constant definitions to the objects
|
||
* or routines that utilize them.
|
||
*
|
||
* \subsection sec5-2-1 Section 5.2.1: Configuration Quantities
|
||
*
|
||
* \par
|
||
* These definitions provide some basic Rx configuration parameters, including
|
||
* the number of simultaneous calls that may be handled on a single connection,
|
||
* lightweight thread parameters, and timeouts for various operations.
|
||
*
|
||
* \par Name
|
||
* RX IDLE DEAD TIME
|
||
* \par Value
|
||
* 60
|
||
* \par Description
|
||
* Default idle dead time for connections, in seconds.
|
||
*
|
||
* \par Name
|
||
* RX MAX SERVICES
|
||
* \par Value
|
||
* 20
|
||
* \par Description
|
||
* The maximum number of Rx services that may be installed within one
|
||
* application.
|
||
*
|
||
* \par Name
|
||
* RX PROCESS MAXCALLS
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* The maximum number of asynchronous calls active simultaneously on any given
|
||
* Rx connection. This value must be set to a power of two.
|
||
*
|
||
* \par Name
|
||
* RX DEFAULT STACK SIZE
|
||
* \par Value
|
||
* 16,000
|
||
* \par Description
|
||
* Default lightweight thread stack size, measured in bytes. This value may be
|
||
* overridden by calling the rx_SetStackSize() macro.
|
||
*
|
||
* \par Name
|
||
* RX PROCESS PRIORITY
|
||
* \par Value
|
||
* LWP NORMAL PRIORITY
|
||
* \par Description
|
||
* This is the priority under which an Rx thread should run. There should not
|
||
* generally be any reason to change this setting.
|
||
*
|
||
* \par Name
|
||
* RX CHALLENGE TIMEOUT
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* The number of seconds before another authentication request packet is
|
||
* generated.
|
||
*
|
||
* \par Name
|
||
* RX MAXACKS
|
||
* \par Value
|
||
* 255
|
||
* \par Description
|
||
* Maximum number of individual acknowledgements that may be carried in an Rx
|
||
* acknowledgement packet.
|
||
*
|
||
* \subsection sec5-2-2 Section 5.2.2: Waiting Options
|
||
*
|
||
* \par
|
||
* These definitions provide readable values indicating whether an operation
|
||
* should block when packet buffer resources are not available.
|
||
*
|
||
* \par Name
|
||
* RX DONTWAIT
|
||
* \par Value
|
||
* 0
|
||
* \par Description
|
||
* Wait until the associated operation completes.
|
||
*
|
||
* \par Name
|
||
* RX WAIT
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Don't wait if the associated operation would block.
|
||
*
|
||
* \subsection sec5-2-3 Section 5.2.3: Connection ID Operations
|
||
*
|
||
* \par
|
||
* These values assist in extracting the call channel number from a connection
|
||
* identifier. A call channel is the index of a particular asynchronous call
|
||
* structure within a single Rx connection.
|
||
*
|
||
* \par Name
|
||
* RX CIDSHIFT
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Number of bits to right-shift to isolate a connection ID. Must be set to
|
||
* the log (base two) of RX MAXCALLS.
|
||
*
|
||
* \par Name
|
||
* RX CHANNELMASK
|
||
* \par Value
|
||
* (RX MAXCALLS-1)
|
||
* \par Description
|
||
* Mask used to isolate a call channel from a connection ID field.
|
||
*
|
||
* \par Name
|
||
* RX CIDMASK
|
||
* \par Value
|
||
* (~RX CHANNELMASK)
|
||
* \par Description
|
||
* Mask used to isolate the connection ID from its field, masking out the call
|
||
* channel information.
|
||
*
|
||
* \subsection sec5-2-4 Section 5.2.4: Connection Flags
|
||
*
|
||
* \par
|
||
* The values defined here appear in the flags field of Rx connections, as
|
||
* defined by the rx connection structure described in Section 5.3.2.2.
|
||
*
|
||
* \par Name
|
||
* RX CONN MAKECALL WAITING
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* rx MakeCall() is waiting for a channel.
|
||
*
|
||
* \par Name
|
||
* RX CONN DESTROY ME
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Destroy this (client) connection after its last call completes.
|
||
*
|
||
* \par Name
|
||
* RX CONN USING PACKET CKSUM
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* This packet is using security-related check-summing (a non-zero header,
|
||
* spare field has been seen.)
|
||
*
|
||
* \subsection sec5-2-5 Section 5.2.5: Connection Types
|
||
*
|
||
* \par
|
||
* Rx stores different information in its connection structures, depending on
|
||
* whether the given connection represents the server side (the one providing
|
||
* the service) or the client side (the one requesting the service) of the
|
||
* protocol. The type field within the connection structure (described in
|
||
* Section 5.3.2.2) takes on the following values to differentiate the two
|
||
* types of connections, and identifies the fields that are active within the
|
||
* connection structure.
|
||
*
|
||
* \par Name
|
||
* RX CLIENT CONNECTION
|
||
* \par Value
|
||
* 0
|
||
* \par Description
|
||
* This is a client-side connection.
|
||
*
|
||
* \par Name
|
||
* CONNECTION
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* This is a server-side connection.
|
||
*
|
||
* \subsection sec5-2-6 Section 5.2.6: Call States
|
||
*
|
||
* \par
|
||
* An Rx call on a particular connection may be in one of several states at any
|
||
* instant in time. The following definitions identify the range of states that
|
||
* a call may assume.
|
||
*
|
||
* \par Name
|
||
* RX STATE NOTINIT
|
||
* \par Value
|
||
* 0
|
||
* \par Description
|
||
* The call structure has never been used, and is thus still completely
|
||
* uninitialized.
|
||
*
|
||
* \par Name
|
||
* RX STATE PRECALL
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* A call is not yet in progress, but packets have arrived for it anyway. This
|
||
* only applies to calls within server-side connections.
|
||
*
|
||
* \par Name
|
||
* RX STATE ACTIVE
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* This call is fully active, having an attached lightweight thread operating
|
||
* on its behalf.
|
||
*
|
||
* \par Name
|
||
* RX STATE DAILY
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* The call structure is "dallying" after its lightweight thread has completed
|
||
* its most recent call. This is a "hot-standby" condition, where the call
|
||
* structure preserves state from the previous call and thus optimizes the
|
||
* arrival of further, related calls.
|
||
*
|
||
* \subsection sec5-2-7 Section 5.2.7: Call Flags:
|
||
*
|
||
* \par
|
||
* These values are used within the flags field of a variable declared to be of
|
||
* type struct rx call, as described in Section 5.3.2.4. They provide
|
||
* additional information as to the state of the given Rx call, such as the
|
||
* type of event for which it is waiting (if any) and whether or not all
|
||
* incoming packets have been received in support of the call.
|
||
*
|
||
* \par Name
|
||
* RX CALL READER WAIT
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Reader is waiting for next packet.
|
||
*
|
||
* \par Name
|
||
* RX CALL WAIT WINDOW ALLOC
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Sender is waiting for a window so that it can allocate buffers.
|
||
*
|
||
* \par Name
|
||
* RX CALL WAIT WINDOW SEND
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* Sender is waiting for a window so that it can send buffers.
|
||
*
|
||
* \par Name
|
||
* RX CALL WAIT PACKETS
|
||
* \par Value
|
||
* 8
|
||
* \par Description
|
||
* Sender is waiting for packet buffers.
|
||
*
|
||
* \par Name
|
||
* RX CALL RECEIVE DONE
|
||
* \par Value
|
||
* 16
|
||
* \par Description
|
||
* The call is waiting for a lightweight thread to be assigned to the operation
|
||
* it has just received.
|
||
*
|
||
* \par Name
|
||
* RX CALL RECEIVE DONE
|
||
* \par Value
|
||
* 32
|
||
* \par Description
|
||
* All packets have been received on this call.
|
||
*
|
||
* \par Name
|
||
* RX CALL CLEARED
|
||
* \par Value
|
||
* 64
|
||
* \par Description
|
||
* The receive queue has been cleared when in precall state.
|
||
*
|
||
* \subsection sec5-2-8 Section 5.2.8: Call Modes
|
||
*
|
||
* \par
|
||
* These values define the modes of an Rx call when it is in the RX STATE
|
||
* ACTIVE state, having a lightweight thread assigned to it.
|
||
*
|
||
* \par Name
|
||
* RX MODE SENDING
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* We are sending or ready to send.
|
||
*
|
||
* \par Name
|
||
* RX MODE RECEIVING
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* We are receiving or ready to receive.
|
||
*
|
||
* \par Name
|
||
* RX MODE ERROR
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* Something went wrong in the current conversation.
|
||
*
|
||
* \par Name
|
||
* RX MODE EOF
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* The server side has flushed (or the client side has read) the last reply
|
||
* packet.
|
||
*
|
||
* \subsection sec5-2-9 Section 5.2.9: Packet Header Flags
|
||
*
|
||
* \par
|
||
* Rx packets carry a flag field in their headers, providing additional
|
||
* information regarding the packet's contents. The Rx packet header's flag
|
||
* field's bits may take the following values:
|
||
*
|
||
* \par Name
|
||
* RX CLIENT INITIATED
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Signifies that a packet has been sent/received from the client side of the
|
||
* call.
|
||
*
|
||
* \par Name
|
||
* RX REQUEST ACK
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* The Rx calls' peer entity requests an acknowledgement.
|
||
*
|
||
* \par Name
|
||
* RX LAST PACKET
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* This is the final packet from this side of the call.
|
||
*
|
||
* \par Name
|
||
* RX MORE PACKETS
|
||
* \par Value
|
||
* 8
|
||
* \par Description
|
||
* There are more packets following this, i.e., the next sequence number seen
|
||
* by the receiver should be greater than this one, rather than a
|
||
* retransmission of an earlier sequence number.
|
||
*
|
||
* \par Name
|
||
* RX PRESET FLAGS
|
||
* \par Value
|
||
* (RX CLIENT INITIATED | RX LAST PACKET)
|
||
* \par Description
|
||
* This flag is preset once per Rx packet. It doesn't change on retransmission
|
||
* of the packet.
|
||
*
|
||
* \subsection sec5-3-10 Section 5.2.10: Packet Sizes
|
||
*
|
||
* \par
|
||
* These values provide sizing information on the various regions within Rx
|
||
* packets. These packet sections include the IP/UDP headers and bodies as well
|
||
* Rx header and bodies. Also covered are such values as different maximum
|
||
* packet sizes depending on whether they are targeted to peers on the same
|
||
* local network or a more far-flung network. Note that the MTU term appearing
|
||
* below is an abbreviation for Maximum Transmission Unit.
|
||
*
|
||
* \par Name
|
||
* RX IPUDP SIZE
|
||
* \par Value
|
||
* 28
|
||
* \par Description
|
||
* The number of bytes taken up by IP/UDP headers.
|
||
*
|
||
* \par Name
|
||
* RX MAX PACKET SIZE
|
||
* \par Value
|
||
* (1500 - RX IPUDP SIZE)
|
||
* \par Description
|
||
* This is the Ethernet MTU minus IP and UDP header sizes.
|
||
*
|
||
* \par Name
|
||
* RX HEADER SIZE
|
||
* \par Value
|
||
* sizeof (struct rx header)
|
||
* \par Description
|
||
* The number of bytes in an Rx packet header.
|
||
*
|
||
* \par Name
|
||
* RX MAX PACKET DATA SIZE
|
||
* \par Value
|
||
* (RX MAX PACKET SIZE RX - HEADER SIZE)
|
||
* \par Description
|
||
* Maximum size in bytes of the user data in a packet.
|
||
*
|
||
* \par Name
|
||
* RX LOCAL PACKET SIZE
|
||
* \par Value
|
||
* RX MAX PACKET SIZE
|
||
* \par Description
|
||
* Packet size in bytes to use when being sent to a host on the same net.
|
||
*
|
||
* \par Name
|
||
* RX REMOTE PACKET SIZE
|
||
* \par Value
|
||
* (576 - RX IPUDP SIZE)
|
||
* \par Description
|
||
* Packet size in bytes to use when being sent to a host on a different net.
|
||
*
|
||
* \subsection sec5-2-11 Section 5.2.11: Packet Types
|
||
*
|
||
* \par
|
||
* The following values are used in the packetType field within a struct rx
|
||
* packet, and define the different roles assumed by Rx packets. These roles
|
||
* include user data packets, different flavors of acknowledgements, busies,
|
||
* aborts, authentication challenges and responses, and debugging vehicles.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE DATA
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* A user data packet.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE ACK
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Acknowledgement packet.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE BUSY
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* Busy packet. The server-side entity cannot accept the call at the moment,
|
||
* but the requestor is encouraged to try again later.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE ABORT
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* Abort packet. No response is needed for this packet type.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE ACKALL
|
||
* \par Value
|
||
* 5
|
||
* \par Description
|
||
* Acknowledges receipt of all packets on a call.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE CHALLENGE
|
||
* \par Value
|
||
* 6
|
||
* \par Description
|
||
* Challenge the client's identity, requesting credentials.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE RESPONSE
|
||
* \par Value
|
||
* 7
|
||
* \par Description
|
||
* Response to a RX PACKET TYPE CHALLENGE authentication challenge packet.
|
||
*
|
||
* \par Name
|
||
* RX PACKET TYPE DEBUG
|
||
* \par Value
|
||
* 8
|
||
* \par Description
|
||
* Request for debugging information.
|
||
*
|
||
* \par Name
|
||
* RX N PACKET TYPES
|
||
* \par Value
|
||
* 9
|
||
* \par Description
|
||
* The number of Rx packet types defined above. Note that it also includes
|
||
* packet type 0 (which is unused) in the count.
|
||
*
|
||
* \par
|
||
* The RX PACKET TYPES definition provides a mapping of the above values to
|
||
* human-readable string names, and is exported by the rx packetTypes variable
|
||
* catalogued in Section 5.4.9.
|
||
*
|
||
* \code
|
||
* {
|
||
* "data",
|
||
* "ack",
|
||
* "busy",
|
||
* "abort",
|
||
* "ackall",
|
||
* "challenge",
|
||
* "response",
|
||
* "debug"
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec5-2-12 Section 5.2.12: Packet Classes
|
||
*
|
||
* \par
|
||
* These definitions are used internally to manage alloction of Rx packet
|
||
* buffers according to quota classifications. Each packet belongs to one of
|
||
* the following classes, and its buffer is derived from the corresponding
|
||
* pool.
|
||
*
|
||
* \par Name
|
||
* RX PACKET CLASS RECEIVE
|
||
* \par Value
|
||
* 0
|
||
* \par Description
|
||
* Receive packet for user data.
|
||
*
|
||
* \par Name
|
||
* RX PACKET CLASS SEND
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Send packet for user data.
|
||
*
|
||
* \par Name
|
||
* RX PACKET CLASS SPECIAL
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* A special packet that does not hold user data, such as an acknowledgement or
|
||
* authentication challenge.
|
||
*
|
||
* \par Name
|
||
* RX N PACKET CLASSES
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* The number of Rx packet classes defined above.
|
||
*
|
||
* \subsection sec5-2-13 Section 5.2.13: Conditions Prompting Ack Packets
|
||
*
|
||
* \par
|
||
* Rx acknowledgement packets are constructed and sent by the protocol
|
||
* according to the following reasons. These values appear in the Rx packet
|
||
* header of the ack packet itself.
|
||
*
|
||
* \par Name
|
||
* RX ACK REQUESTED
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* The peer has explicitly requested an ack on this packet.
|
||
*
|
||
* \par Name
|
||
* RX ACK DUPLICATE
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* A duplicate packet has been received.
|
||
*
|
||
* \par Name
|
||
* RX ACK OUT OF SEQUENCE
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* A packet has arrived out of sequence.
|
||
*
|
||
* \par Name
|
||
* RX ACK EXCEEDS WINDOW
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* A packet sequence number higher than maximum value allowed by the call's
|
||
* window has been received.
|
||
*
|
||
* \par Name
|
||
* RX ACK NOSPACE
|
||
* \par Value
|
||
* 5
|
||
* \par Description
|
||
* No packet buffer space is available.
|
||
*
|
||
* \par Name
|
||
* RX ACK PING
|
||
* \par Value
|
||
* 6
|
||
* \par Description
|
||
* Acknowledgement for keep-alive purposes.
|
||
*
|
||
* \par Name
|
||
* RX ACK PING RESPONSE
|
||
* \par Value
|
||
* 7
|
||
* \par Description
|
||
* Response to a RX ACK PING packet.
|
||
*
|
||
* \par Name
|
||
* RX ACK DELAY
|
||
* \par Value
|
||
* 8
|
||
* \par Description
|
||
* An ack generated due to a period of inactivity after normal packet
|
||
* receptions.
|
||
*
|
||
* \subsection 5-2-14 Section 5.2.14: Acknowledgement Types
|
||
*
|
||
* \par
|
||
* These are the set of values placed into the acks array in an Rx
|
||
* acknowledgement packet, whose data format is defined by struct rx ackPacket.
|
||
* These definitions are used to convey positive or negative acknowledgements
|
||
* for a given range of packets.
|
||
*
|
||
* \par Name
|
||
* RX ACK TYPE NACK
|
||
* \par Value
|
||
* 0
|
||
* \par Description
|
||
* Receiver doesn't currently have the associated packet; it may never hae been
|
||
* received, or received and then later dropped before processing.
|
||
*
|
||
* \par Name
|
||
* RX ACK TYPE ACK
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Receiver has the associated packet queued, although it may later decide to
|
||
* discard it.
|
||
*
|
||
* \subsection sec5-2-15 Section 5.2.15: Error Codes
|
||
*
|
||
* \par
|
||
* Rx employs error codes ranging from -1 to -64. The Rxgen stub generator may
|
||
* use other error codes less than -64. User programs calling on Rx, on the
|
||
* other hand, are expected to return positive error codes. A return value of
|
||
* zero is interpreted as an indication that the given operation completed
|
||
* successfully.
|
||
*
|
||
* \par Name
|
||
* RX CALL DEAD
|
||
* \par Value
|
||
* -1
|
||
* \par Description
|
||
* A connection has been inactive past Rx's tolerance levels and has been shut
|
||
* down.
|
||
*
|
||
* \par Name
|
||
* RX INVALID OPERATION
|
||
* \par Value
|
||
* -2
|
||
* \par Description
|
||
* An invalid operation has been attempted, including such protocol errors as
|
||
* having a client-side call send data after having received the beginning of a
|
||
* reply from its server-side peer.
|
||
*
|
||
* \par Name
|
||
* RX CALL TIMEOUT
|
||
* \par Value
|
||
* -3
|
||
* \par Description
|
||
* The (optional) timeout value placed on this call has been exceeded (see
|
||
* Sections 5.5.3.4 and 5.6.5).
|
||
*
|
||
* \par Name
|
||
* RX EOF
|
||
* \par Value
|
||
* -4
|
||
* \par Description
|
||
* Unexpected end of data on a read operation.
|
||
*
|
||
* \par Name
|
||
* RX PROTOCOL ERROR
|
||
* \par Value
|
||
* -5
|
||
* \par Description
|
||
* An unspecified low-level Rx protocol error has occurred.
|
||
*
|
||
* \par Name
|
||
* RX USER ABORT
|
||
* \par Value
|
||
* -6
|
||
* \par Description
|
||
* A generic user abort code, used when no more specific error code needs to be
|
||
* communicated. For example, Rx clients employing the multicast feature (see
|
||
* Section 1.2.8) take advantage of this error code.
|
||
*
|
||
* \subsection sec5-2-16 Section 5.2.16: Debugging Values
|
||
*
|
||
* \par
|
||
* Rx provides a set of data collections that convey information about its
|
||
* internal status and performance. The following values have been defined in
|
||
* support of this debugging and statistics-collection feature.
|
||
*
|
||
* \subsubsection sec5-3-16-1 Section 5.2.16.1: Version Information
|
||
*
|
||
* \par
|
||
* Various versions of the Rx debugging/statistics interface are in existance,
|
||
* each defining different data collections and handling certain bugs. Each Rx
|
||
* facility is stamped with a version number of its debugging/statistics
|
||
* interface, allowing its clients to tailor their requests to the precise data
|
||
* collections that are supported by a particular Rx entity, and to properly
|
||
* interpret the data formats received through this interface. All existing Rx
|
||
* implementations should be at revision M.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION MINIMUM
|
||
* \par Value
|
||
* 'L'
|
||
* \par Description
|
||
* The earliest version of Rx statistics available.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION
|
||
* \par Value
|
||
* 'M'
|
||
* \par Description
|
||
* The latest version of Rx statistics available.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION W SECSTATS
|
||
* \par Value
|
||
* 'L'
|
||
* \par Description
|
||
* Identifies the earliest version in which statistics concerning Rx security
|
||
* objects is available.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION W GETALLCONN
|
||
* \par Value
|
||
* 'M'
|
||
* \par Description
|
||
* The first version that supports getting information about all current Rx
|
||
* connections, as specified y the RX DEBUGI GETALLCONN debugging request
|
||
* packet opcode described below.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION W RXSTATS
|
||
* \par Value
|
||
* 'M'
|
||
* \par Description
|
||
* The first version that supports getting all the Rx statistics in one
|
||
* operation, as specified by the RX DEBUGI RXSTATS debugging request packet
|
||
* opcode described below.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI VERSION W UNALIGNED CONN
|
||
* \par Value
|
||
* 'L'
|
||
* \par Description
|
||
* There was an alignment problem discovered when returning Rx connection
|
||
* information in older versions of this debugging/statistics interface. This
|
||
* identifies the last version that exhibited this alignment problem.
|
||
*
|
||
* \subsubsection sec5-2-16-2 Section 5.2.16.2: Opcodes
|
||
*
|
||
* \par
|
||
* When requesting debugging/statistics information, the caller specifies one
|
||
* of the following supported data collections:
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI GETSTATS
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Get basic Rx statistics.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI GETCONN
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Get information on all Rx connections considered "interesting" (as defined
|
||
* below), and no others.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI GETALLCONN
|
||
* \par Value
|
||
* 3
|
||
* \par Description
|
||
* Get information on all existing Rx connection structures, even
|
||
* "uninteresting" ones.
|
||
*
|
||
* \par Name
|
||
* RX DEBUGI RXSTATS
|
||
* \par Value
|
||
* 4
|
||
* \par Description
|
||
* Get all available Rx stats.
|
||
*
|
||
* \par
|
||
* An Rx connection is considered "interesting" if it is waiting for a call
|
||
* channel to free up or if it has been marked for destruction. If neither is
|
||
* true, a connection is still considered interesting if any of its call
|
||
* channels is actively handling a call or in its preparatory pre-call state.
|
||
* Failing all the above conditions, a connection is still tagged as
|
||
* interesting if any of its call channels is in either of the RX MODE SENDING
|
||
* or RX MODE RECEIVING modes, which are not allowed when the call is not
|
||
* active.
|
||
*
|
||
* \subsubsection sec5-2-16-3 Section 5.2.16.3: Queuing
|
||
*
|
||
* \par
|
||
* These two queueing-related values indicate whether packets are present on
|
||
* the incoming and outgoing packet queues for a given Rx call. These values
|
||
* are only used in support of debugging and statistics-gathering operations.
|
||
*
|
||
* \par Name
|
||
* RX OTHER IN
|
||
* \par Value
|
||
* 1
|
||
* \par Description
|
||
* Packets available in in queue.
|
||
*
|
||
* \par Name
|
||
* RX OTHER OUT
|
||
* \par Value
|
||
* 2
|
||
* \par Description
|
||
* Packets available in out queue.
|
||
*
|
||
* \section sec5-3 Section 5.3: Structures
|
||
*
|
||
* \par
|
||
* This section describes the major exported Rx data structures of interest to
|
||
* application programmers. The following categories are utilized for the
|
||
* purpose of organizing the structure descriptions:
|
||
* \li Security objects
|
||
* \li Protocol objects
|
||
* \li Packet formats
|
||
* \li Debugging and statistics
|
||
* \li Miscellaneous
|
||
* \par
|
||
* Please note that many fields described in this section are declared to be
|
||
* VOID. This is defined to be char, and is used to get around some compiler
|
||
* limitations.
|
||
* \subsection sec5-3-1 Section 5.3.1: Security Objects
|
||
*
|
||
* \par
|
||
* As explained in Section 1.2.1, Rx provides a modular, extensible security
|
||
* model. This allows Rx applications to either use one of the built-in
|
||
* security/authentication protocol packages or write and plug in one of their
|
||
* own. This section examines the various structural components used by Rx to
|
||
* support generic security and authentication modules.
|
||
*
|
||
* \subsubsection sec5-3-1-1 Section 5.3.1.1: struct rx securityOps
|
||
*
|
||
* \par
|
||
* As previously described, each Rx security object must export a fixed set of
|
||
* interface functions, providing the full set of operations defined on the
|
||
* object. The rx securityOps structure defines the array of functions
|
||
* comprising this interface. The Rx facility calls these routines at the
|
||
* appropriate times, without knowing the specifics of how any particular
|
||
* security object implements the operation.
|
||
* \par
|
||
* A complete description of these interface functions, including information
|
||
* regarding their exact purpose, parameters, and calling conventions, may be
|
||
* found in Section 5.5.7.
|
||
* \par
|
||
* \b fields
|
||
* \li int (*op Close)() - React to the disposal of a security object.
|
||
* \li int (*op NewConnection)() - Invoked each time a new Rx connection
|
||
* utilizing the associated security object is created.
|
||
* \li int (*op PreparePacket)() - Invoked each time an outgoing Rx packet is
|
||
* created and sent on a connection using the given security object.
|
||
* \li int (*op SendPacket)() - Called each time a packet belonging to a call
|
||
* in a connection using the security object is physically transmitted.
|
||
* \li int (*op CheckAuthentication)() - This function is executed each time it
|
||
* is necessary to check whether authenticated calls are being perfomed on a
|
||
* connection using the associated security object.
|
||
* \li int (*op CreateChallenge)() - Invoked each time a server-side challenge
|
||
* event is created by Rx, namely when the identity of the principal associated
|
||
* with the peer process must be determined.
|
||
* \li int (*op GetChallenge)() - Called each time a client-side packet is
|
||
* constructed in response to an authentication challenge.
|
||
* \li int (*op GetResponse)() - Executed each time a response to a challenge
|
||
* event must be received on the server side of a connection.
|
||
* \li int (*op CheckResponse)() - Invoked each time a response to an
|
||
* authentication has been received, validating the response and pulling out
|
||
* the required authentication information.
|
||
* \li int (*op CheckPacket) () - Invoked each time an Rx packet has been
|
||
* received, making sure that the packet is properly formatted and that it
|
||
* hasn't been altered.
|
||
* \li int (*op DestroyConnection)() - Called each time an Rx connection
|
||
* employing the given security object is destroyed.
|
||
* \li int (*op GetStats)() - Executed each time a request for statistics on
|
||
* the given security object has been received.
|
||
* \li int (*op Spare1)()-int (*op Spare3)() - Three spare function slots,
|
||
* reserved for future use.
|
||
*
|
||
* \subsubsection sec5-3-1-2 Section 5.2.1.2: struct rx securityClass
|
||
*
|
||
* \par
|
||
* Variables of type struct rx securityClass are used to represent
|
||
* instantiations of a particular security model employed by Rx. It consists of
|
||
* a pointer to the set of interface operations implementing the given security
|
||
* object, along with a pointer to private storage as necessary to support its
|
||
* operations. These security objects are also reference-counted, tracking the
|
||
* number of Rx connections in existance that use the given security object. If
|
||
* the reference count drops to zero, the security module may garbage-collect
|
||
* the space taken by the unused security object.
|
||
* \par
|
||
* \b fields
|
||
* \li struct rx securityOps *ops - Pointer to the array of interface functions
|
||
* for the security object.
|
||
* \li VOID *privateData - Pointer to a region of storage used by the security
|
||
* object to support its operations.
|
||
* \li int refCount - A reference count on the security object, tracking the
|
||
* number of Rx connections employing this model.
|
||
*
|
||
* \subsubsection sec5-3-1-3 Section 5.3.1.3: struct rx
|
||
* securityObjectStats
|
||
*
|
||
* \par
|
||
* This structure is used to report characteristics for an instantiation of a
|
||
* security object on a particular Rx connection, as well as performance
|
||
* figures for that object. It is used by the debugging portions of the Rx
|
||
* package. Every security object defines and manages fields such as level and
|
||
* flags differently.
|
||
* \par
|
||
* \b fields
|
||
* \li char type - The type of security object being implemented. Existing
|
||
* values are:
|
||
* \li 0: The null security package.
|
||
* \li 1: An obsolete Kerberos-like security object.
|
||
* \li 2: The rxkad discipline (see Chapter 3).
|
||
* \li char level - The level at which encryption is utilized.
|
||
* \li char sparec[10] - Used solely for alignment purposes.
|
||
* \li long flags - Status flags regarding aspects of the connection relating
|
||
* to the security object.
|
||
* \li u long expires - Absolute time when the authentication information
|
||
* cached by the given connection expires. A value of zero indicates that the
|
||
* associated authentication information is valid for all time.
|
||
* \li u long packetsReceived - Number of packets received on this particular
|
||
* connection, and thus the number of incoming packets handled by the
|
||
* associated security object.
|
||
* \li u long packetsSent - Number of packets sent on this particular
|
||
* connection, and thus the number of outgoing packets handled by the
|
||
* associated security object.
|
||
* \li u long bytesReceived - Overall number of "payload" bytes received (i.e.,
|
||
* packet bytes not associated with IP headers, UDP headers, and the security
|
||
* module's own header and trailer regions) on this connection.
|
||
* \li u long bytesSent - Overall number of "payload" bytes sent (i.e., packet
|
||
* bytes not associated with IP headers, UDP headers, and the security module's
|
||
* own header and trailer regions) on this connection.
|
||
* \li short spares[4] - Several shortword spares, reserved for future use.
|
||
* \li long sparel[8] - Several longword spares, reserved for future use.
|
||
*
|
||
* \subsection sec5-3-2 Section 5.3.2: Protocol Objects
|
||
*
|
||
* \par
|
||
* The structures describing the main abstractions and entities provided by Rx,
|
||
* namely services, peers, connections and calls are covered in this section.
|
||
*
|
||
* \subsubsection sec5-3-2-1 Section 5.3.2.1: struct rx service
|
||
*
|
||
* \par
|
||
* An Rx-based server exports services, or specific RPC interfaces that
|
||
* accomplish certain tasks. Services are identified by (host-address,
|
||
* UDP-port, serviceID) triples. An Rx service is installed and initialized on
|
||
* a given host through the use of the rx NewService() routine (See Section
|
||
* 5.6.3). Incoming calls are stamped with the Rx service type, and must match
|
||
* an installed service to be accepted. Internally, Rx services also carry
|
||
* string names for purposes of identification. These strings are useful to
|
||
* remote debugging and statistics-gathering programs. The use of a service ID
|
||
* allows a single server process to export multiple, independently-specified
|
||
* Rx RPC services.
|
||
* \par
|
||
* Each Rx service contains one or more security classes, as implemented by
|
||
* individual security objects. These security objects implement end-to-end
|
||
* security protocols. Individual peer-to-peer connections established on
|
||
* behalf of an Rx service will select exactly one of the supported security
|
||
* objects to define the authentication procedures followed by all calls
|
||
* associated with the connection. Applications are not limited to using only
|
||
* the core set of built-in security objects offered by Rx. They are free to
|
||
* define their own security objects in order to execute the specific protocols
|
||
* they require.
|
||
* \par
|
||
* It is possible to specify both the minimum and maximum number of lightweight
|
||
* processes available to handle simultaneous calls directed to an Rx service.
|
||
* In addition, certain procedures may be registered with the service and
|
||
* called at set times in the course of handling an RPC request.
|
||
* \par
|
||
* \b fields
|
||
* \li u short serviceId - The associated service number.
|
||
* \li u short servicePort - The chosen UDP port for this service.
|
||
* \li char *serviceName - The human-readable service name, expressed as a
|
||
* character
|
||
* \li string. osi socket socket - The socket structure or file descriptor used
|
||
* by this service.
|
||
* \li u short nSecurityObjects - The number of entries in the array of
|
||
* supported security objects.
|
||
* \li struct rx securityClass **securityObjects - The array of pointers to the
|
||
* ser
|
||
* vice's security class objects.
|
||
* \li long (*executeRequestProc)() - A pointer to the routine to call when an
|
||
* RPC request is received for this service.
|
||
* \li VOID (*destroyConnProc)() - A pointer to the routine to call when one of
|
||
* the server-side connections associated with this service is destroyed.
|
||
* \li VOID (*newConnProc)() - A pointer to the routine to call when a
|
||
* server-side connection associated with this service is created.
|
||
* \li VOID (*beforeProc)() - A pointer to the routine to call before an
|
||
* individual RPC call on one of this service's connections is executed.
|
||
* \li VOID (*afterProc)() - A pointer to the routine to call after an
|
||
* individual RPC call on one of this service's connections is executed.
|
||
* \li short nRequestsRunning - The number of simultaneous RPC calls currently
|
||
* in progress for this service.
|
||
* \li short maxProcs - This field has two meanings. first, maxProcs limits the
|
||
* total number of requests that may execute in parallel for any one service.
|
||
* It also guarantees that this many requests may be handled in parallel if
|
||
* there are no active calls for any other service.
|
||
* \li short minProcs - The minimum number of lightweight threads (hence
|
||
* requests) guaranteed to be simultaneously executable.
|
||
* \li short connDeadTime - The number of seconds until a client of this
|
||
* service will be declared to be dead, if it is not responding to the RPC
|
||
* protocol.
|
||
* \li short idleDeadTime - The number of seconds a server-side connection for
|
||
* this service will wait for packet I/O to resume after a quiescent period
|
||
* before the connection is marked as dead.
|
||
*
|
||
* \subsubsection sec5-3-2-2 Section 5.3.2.2: struct rx connection
|
||
*
|
||
* \par
|
||
* An Rx connection represents an authenticated communication path, allowing
|
||
* multiple asynchronous conversations (calls). Each connection is identified
|
||
* by a connection ID. The low-order bits of the connection ID are reserved so
|
||
* they may be stamped with the index of a particular call channel. With up to
|
||
* RX MAXCALLS concurrent calls (set to 4 in this implementation), the bottom
|
||
* two bits are set aside for this purpose. The connection ID is not sufficient
|
||
* by itself to uniquely identify an Rx connection. Should a client crash and
|
||
* restart, it may reuse a connection ID, causing inconsistent results. In
|
||
* addition to the connection ID, the epoch, or start time for the client side
|
||
* of the connection, is used to identify a connection. Should the above
|
||
* scenario occur, a different epoch value will be chosen by the client,
|
||
* differentiating this incarnation from the orphaned connection record on the
|
||
* server side.
|
||
* \par
|
||
* Each connection is associated with a parent service, which defines a set of
|
||
* supported security models. At creation time, an Rx connection selects the
|
||
* particular security protocol it will implement, referencing the associated
|
||
* service. The connection structure maintains state about the individual calls
|
||
* being simultaneously handled.
|
||
* \par
|
||
* \b fields
|
||
* \li struct rx connection *next - Used for internal queueing.
|
||
* \li struct rx peer *peer - Pointer to the connection's peer information (see
|
||
* below).
|
||
* \li u long epoch - Process start time of the client side of the connection.
|
||
* \li u long cid - Connection identifier. The call channel (i.e., the index
|
||
* into the connection's array of call structures) may appear in the bottom
|
||
* bits.
|
||
* \li VOID *rock - Pointer to an arbitrary region of memory in support of the
|
||
* connection's operation. The contents of this area are opaque to the Rx
|
||
* facility in general, but are understood by any special routines used by this
|
||
* connection.
|
||
* \li struct rx call *call[RX MAXCALLS] - Pointer to the call channel
|
||
* structures, describing up to RX MAXCALLS concurrent calls on this
|
||
* connection.
|
||
* \li u long callNumber[RX MAXCALLS] - The set of current call numbers on each
|
||
* of the call channels.
|
||
* \li int timeout - Obsolete; no longer used.
|
||
* \li u char flags - Various states of the connection; see Section 5.2.4 for
|
||
* individual bit definitions.
|
||
* \li u char type - Whether the connection is a server-side or client-side
|
||
* one. See Section 5.2.5 for individual bit definitions.
|
||
* \li u short serviceId - The service ID that should be stamped on requests.
|
||
* This field is only used by client-side instances of connection structures.
|
||
* \li struct rx service *service - A pointer to the service structure
|
||
* associated with this connection. This field is only used by server-side
|
||
* instances of connection structures.
|
||
* \li u long serial - Serial number of the next outgoing packet associated
|
||
* with this connection.
|
||
* \li u long lastSerial - Serial number of the last packet received in
|
||
* association with this connection. This field is used in computing packet
|
||
* skew.
|
||
* \li u short secondsUntilDead - Maximum numer of seconds of silence that
|
||
* should be tolerated from the connection's peer before calls will be
|
||
* terminated with an RX CALL DEAD error.
|
||
* \li u char secondsUntilPing - The number of seconds between "pings"
|
||
* (keep-alive probes) when at least one call is active on this connection.
|
||
* \li u char securityIndex - The index of the security object being used by
|
||
* this connection. This number selects a slot in the security class array
|
||
* maintained by the service associated with the connection.
|
||
* \li long error - Records the latest error code for calls occurring on this
|
||
* connection.
|
||
* \li struct rx securityClass *securityObject - A pointer to the security
|
||
* object used by this connection. This should coincide with the slot value
|
||
* chosen by the securityIndex field described above.
|
||
* \li VOID *securityData - A pointer to a region dedicated to hosting any
|
||
* storage required by the security object being used by this connection.
|
||
* \li u short securityHeaderSize - The length in bytes of the portion of the
|
||
* packet header before the user's data that contains the security module's
|
||
* information.
|
||
* \li u short securityMaxTrailerSize - The length in bytes of the packet
|
||
* trailer, appearing after the user's data, as mandated by the connection's
|
||
* security module.
|
||
* \li struct rxevent *challengeEvent -Pointer to an event that is scheduled
|
||
* when the server side of the connection is challenging the client to
|
||
* authenticate itself.
|
||
* \li int lastSendTime - The last time a packet was sent on this connection.
|
||
* \li long maxSerial - The largest serial number seen on incoming packets.
|
||
* \li u short hardDeadTime - The maximum number of seconds that any call on
|
||
* this connection may execute. This serves to throttle runaway calls.
|
||
*
|
||
* \subsubsection sec5-3-2-3 Section 5.3.2.3: struct rx peer
|
||
*
|
||
* \par
|
||
* For each connection, Rx maintains information describing the entity, or
|
||
* peer, on the other side of the wire. A peer is identified by a (host,
|
||
* UDP-port) pair. Included in the information kept on this remote
|
||
* communication endpoint are such network parameters as the maximum packet
|
||
* size supported by the host, current readings on round trip time to
|
||
* retransmission delays, and packet skew (see Section 1.2.7). There are also
|
||
* congestion control fields, ranging from descriptions of the maximum number
|
||
* of packets that may be sent to the peer without pausing and retransmission
|
||
* statistics. Peer structures are shared between connections whenever
|
||
* possible, and hence are reference-counted. A peer object may be
|
||
* garbage-collected if it is not actively referenced by any connection
|
||
* structure and a sufficient period of time has lapsed since the reference
|
||
* count dropped to zero.
|
||
* \par
|
||
* \b fields
|
||
* \li struct rx peer *next - Use to access internal lists.
|
||
* \li u long host - Remote IP address, in network byte order
|
||
* \li u short port - Remote UDP port, in network byte order
|
||
* \li short packetSize - Maximum packet size for this host, if known.
|
||
* \li u long idleWhen - When the refCount reference count field (see below)
|
||
* went to zero.
|
||
* \li short refCount - Reference count for this structure
|
||
* \li u char burstSize - Reinitialization size for the burst field (below).
|
||
* \li u char burst - Number of packets that can be transmitted immediately
|
||
* without pausing.
|
||
* \li struct clock burstWait - Time delay until new burst aimed at this peer
|
||
* is allowed.
|
||
* \li struct queue congestionQueue - Queue of RPC call descriptors that are
|
||
* waiting for a non-zero burst value.
|
||
* \li int rtt - Round trip time to the peer, measured in milliseconds.
|
||
* \li struct clock timeout - Current retransmission delay to the peer.
|
||
* \li int nSent - Total number of distinct data packets sent, not including
|
||
* retransmissions.
|
||
* \li int reSends - Total number of retransmissions for this peer since the
|
||
* peer structure instance was created.
|
||
* \li u long inPacketSkew - Maximum skew on incoming packets (see Section
|
||
* 1.2.7)
|
||
* \li u long outPacketSkew - Peer-reported maximum skew on outgoing packets
|
||
* (see Section 1.2.7).
|
||
*
|
||
* \subsubsection sec5-3-2-4 Section 5.3.2.4: struct rx call
|
||
*
|
||
* \par
|
||
* This structure records the state of an active call proceeding on a given Rx
|
||
* connection. As described above, each connection may have up to RX MAXCALLS
|
||
* calls active at any one instant, and thus each connection maintains an array
|
||
* of RX MAXCALLS rx call structures. The information contained here is
|
||
* specific to the given call; "permanent" call state, such as the call number,
|
||
* is maintained in the connection structure itself.
|
||
* \par
|
||
* \b fields
|
||
* \li struct queue queue item header - Queueing information for this
|
||
* structure.
|
||
* \li struct queue tq - Queue of outgoing ("transmit") packets.
|
||
* \li struct queue rq - Queue of incoming ("receive") packets.
|
||
* \li char *bufPtr - Pointer to the next byte to fill or read in the call's
|
||
* current packet, depending on whether it is being transmitted or received.
|
||
* \li u short nLeft - Number of bytes left to read in the first packet in the
|
||
* reception queue (see field rq).
|
||
* \li u short nFree - Number of bytes still free in the last packet in the
|
||
* transmission queue (see field tq).
|
||
* \li struct rx packet *currentPacket - Pointer to the current packet being
|
||
* assembled or read.
|
||
* \li struct rx connection *conn - Pointer to the parent connection for this
|
||
* call.
|
||
* \li u long *callNumber - Pointer to call number field within the call's
|
||
* current packet.
|
||
* \li u char channel - Index within the parent connection's call array that
|
||
* describes this call.
|
||
* \li u char dummy1, dummy2 - These are spare fields, reserved for future use.
|
||
* \li u char state - Current call state. The associated bit definitions appear
|
||
* in Section 5.2.7.
|
||
* \li u char mode - Current mode of a call that is in RX STATE ACTIVE state.
|
||
* The associated bit definitions appear in Section 5.2.8.
|
||
* \li u char flags - Flags pertaining to the state of the given call. The
|
||
* associated bit definitions appear in Section 5.2.7.
|
||
* \li u char localStatus - Local user status information, sent out of band.
|
||
* This field is currently not in use, set to zero.
|
||
* \li u char remoteStatus - Remote user status information, received out of
|
||
* band. This field is currently not in use, set to zero.
|
||
* \li long error - Error condition for this call.
|
||
* \li u long timeout - High level timeout for this call
|
||
* \li u long rnext - Next packet sequence number expected to be received.
|
||
* \li u long rprev - Sequence number of the previous packet received. This
|
||
* number is used to decide the proper sequence number for the next packet to
|
||
* arrive, and may be used to generate a negative acknowledgement.
|
||
* \li u long rwind - Width of the packet receive window for this call. The
|
||
* peer must not send packets with sequence numbers greater than or equal to
|
||
* rnext + rwind.
|
||
* \li u long tfirst - Sequence number of the first unacknowledged transmit
|
||
* packet for this call.
|
||
* \li u long tnext - Next sequence number to use for an outgoing packet.
|
||
* \li u long twind - Width of the packet transmit window for this call. Rx
|
||
* cannot assign a sequence number to an outgoing packet greater than or equal
|
||
* to tfirst + twind.
|
||
* \li struct rxevent *resendEvent - Pointer to a pending retransmission event,
|
||
* if any.
|
||
* \li struct rxevent *timeoutEvent - Pointer to a pending timeout event, if
|
||
* any.
|
||
* \li struct rxevent *keepAliveEvent - Pointer to a pending keep-alive event,
|
||
* if this is an active call.
|
||
* \li struct rxevent *delayedAckEvent - Pointer to a pending delayed
|
||
* acknowledgement packet event, if any. Transmission of a delayed
|
||
* acknowledgement packet is scheduled after all outgoing packets for a call
|
||
* have been sent. If neither a reply nor a new call are received by the time
|
||
* the delayedAckEvent activates, the ack packet will be sent.
|
||
* \li int lastSendTime - Last time a packet was sent for this call.
|
||
* \li int lastReceiveTime - Last time a packet was received for this call.
|
||
* \li VOID (*arrivalProc)() - Pointer to the procedure to call when reply is
|
||
* received.
|
||
* \li VOID *arrivalProcHandle - Pointer to the handle to pass to the
|
||
* arrivalProc as its first argument.
|
||
* \li VOID *arrivalProcArg - Pointer to an additional argument to pass to the
|
||
* given arrivalProc.
|
||
* \li u long lastAcked - Sequence number of the last packet "hard-acked" by
|
||
* the receiver. A packet is considered to be hard-acked if an acknowledgement
|
||
* is generated after the reader has processed it. The Rx facility may
|
||
* sometimes "soft-ack" a windowfull of packets before they have been picked up
|
||
* by the receiver.
|
||
* \li u long startTime - The time this call started running.
|
||
* \li u long startWait - The time that a server began waiting for input data
|
||
* or send quota.
|
||
*
|
||
* \subsection sec5-3-3 Section 5.3.3: Packet Formats
|
||
*
|
||
* \par
|
||
* The following sections cover the different data formats employed by the
|
||
* suite of Rx packet types, as enumerated in Section 5.2.11. A description of
|
||
* the most commonly-employed Rx packet header appears first, immediately
|
||
* followed by a description of the generic packet container and descriptor.
|
||
* The formats for Rx acknowledgement packets and debugging/statistics packets
|
||
* are also examined.
|
||
*
|
||
* \subsubsection sec5-3-3-1 Section 5.3.3.1: struct rx header
|
||
*
|
||
* \par
|
||
* Every Rx packet has its own header region, physically located after the
|
||
* leading IP/UDP headers. This header contains connection, call, security, and
|
||
* sequencing information. Along with a type identifier, these fields allow the
|
||
* receiver to properly interpret the packet. In addition, every client relates
|
||
* its "epoch", or Rx incarnation date, in each packet. This assists in
|
||
* identifying protocol problems arising from reuse of connection identifiers
|
||
* due to a client restart. Also included in the header is a byte of
|
||
* user-defined status information, allowing out-of-band channel of
|
||
* communication for the higher-level application using Rx as a transport
|
||
* mechanism.
|
||
* \par
|
||
* \b fields
|
||
* \li u long epoch - Birth time of the client Rx facility.
|
||
* \li u long cid - Connection identifier, as defined by the client. The last
|
||
* RX CIDSHIFT bits in the cid field identify which of the server-side RX
|
||
* MAXCALLS call channels is to receive the packet.
|
||
* \li u long callNumber - The current call number on the chosen call channel.
|
||
* \li u long seq - Sequence number of this packet. Sequence numbers start with
|
||
* 0 for each new Rx call.
|
||
* \li u long serial - This packet's serial number. A new serial number is
|
||
* stamped on each packet transmitted (or retransmitted).
|
||
* \li u char type - What type of Rx packet this is; see Section 5.2.11 for the
|
||
* list of legal definitions.
|
||
* \li u char flags - Flags describing this packet; see Section 5.2.9 for the
|
||
* list of legal settings.
|
||
* \li u char userStatus - User-defined status information, uninterpreted by
|
||
* the Rx facility itself. This field may be easily set or retrieved from Rx
|
||
* packets via calls to the rx GetLocalStatus(), rx SetLocalStatus(), rx
|
||
* GetRemoteStatus(), and rx SetRemoteStatus() macros.
|
||
* \li u char securityIndex - Index in the associated server-side service class
|
||
* of the security object used by this call.
|
||
* \li u short serviceId - The server-provided service ID to which this packet
|
||
* is directed.
|
||
* \li u short spare - This field was originally a true spare, but is now used
|
||
* by the built-in rxkad security module for packet header checksums. See the
|
||
* descriptions of the related rx IsUsingPktChecksum(), rx GetPacketCksum(),
|
||
* and rx SetPacketCksum() macros.
|
||
*
|
||
* \subsubsection sec5-3-3-2 Section 5.3.3.2: struct rx packet
|
||
*
|
||
* \par
|
||
* This structure is used to describe an Rx packet, and includes the wire
|
||
* version of the packet contents, where all fields exist in network byte
|
||
* order. It also includes acknowledgement, length, type, and queueing
|
||
* information.
|
||
* \par
|
||
* \b fields
|
||
* \li struct queue queueItemHeader - field used for internal queueing.
|
||
* \li u char acked - If non-zero, this field indicates that this packet has
|
||
* been tentatively (soft-) acknowledged. Thus, the packet has been accepted by
|
||
* the rx peer entity on the other side of the connection, but has not yet
|
||
* necessarily been passed to the true reader. The sender is not free to throw
|
||
* the packet away, as it might still get dropped by the peer before it is
|
||
* delivered to its destination process.
|
||
* \li short length - Length in bytes of the user data section.
|
||
* \li u char packetType - The type of Rx packet described by this record. The
|
||
* set of legal choices is available in Section 5.2.11.
|
||
* \li struct clock retryTime - The time when this packet should be
|
||
* retransmitted next.
|
||
* \li struct clock timeSent - The last time this packet was transmitted.
|
||
* \li struct rx header header - A copy of the internal Rx packet header.
|
||
* \li wire - The text of the packet as it appears on the wire. This structure
|
||
* has the following sub-fields:
|
||
* \li u long head[RX HEADER SIZE/sizeof(long)] The wire-level contents of
|
||
* IP, UDP, and Rx headers.
|
||
* \li u long data[RX MAX PACKET DATA SIZE/sizeof(long)] The wire form of
|
||
* the packet's "payload", namely the user data it carries.
|
||
*
|
||
* \subsubsection sec5-3-3-3 Section 5.3.3.3: struct rx ackPacket
|
||
*
|
||
* \par
|
||
* This is the format for the data portion of an Rx acknowledgement packet,
|
||
* used to inform a peer entity performing packet transmissions that a subset
|
||
* of its packets has been properly received.
|
||
* \par
|
||
* \b fields
|
||
* \li u short bufferSpace - Number of packet buffers available. Specifically,
|
||
* the number of packet buffers that the ack packet's sender is willing to
|
||
* provide for data on this or subsequent calls. This number does not have to
|
||
* fully accurate; it is acceptable for the sender to provide an estimate.
|
||
* \li u short maxSkew - The maximum difference seen between the serial number
|
||
* of the packet being acknowledged and highest packet yet received. This is an
|
||
* indication of the degree to which packets are arriving out of order at the
|
||
* receiver.
|
||
* \li u long firstPacket - The serial number of the first packet in the list
|
||
* of acknowledged packets, as represented by the acks field below.
|
||
* \li u long previousPacket - The previous packet serial number received.
|
||
* \li u long serial - The serial number of the packet prompted the
|
||
* acknowledgement.
|
||
* \li u char reason - The reason given for the acknowledgement; legal values
|
||
* for this field are described in Section 5.2.13.
|
||
* \li u char nAcks - Number of acknowledgements active in the acks array
|
||
* immediately following.
|
||
* \li u char acks[RX MAXACKS] - Up to RX MAXACKS packet acknowledgements. The
|
||
* legal values for each slot in the acks array are described in Section
|
||
* 5.2.14. Basically, these fields indicate either positive or negative
|
||
* acknowledgements.
|
||
*
|
||
* \par
|
||
* All packets with serial numbers prior to firstPacket are implicitly
|
||
* acknowledged by this packet, indicating that they have been fully processed
|
||
* by the receiver. Thus, the sender need no longer be concerned about them,
|
||
* and may release all of the resources that they occupy. Packets with serial
|
||
* numbers firstPacket + nAcks and higher are not acknowledged by this ack
|
||
* packet. Packets with serial numbers in the range [firstPacket, firstPacket +
|
||
* nAcks) are explicitly acknowledged, yet their sender-side resources must not
|
||
* yet be released, as there is yet no guarantee that the receiver will not
|
||
* throw them away before they can be processed there.
|
||
* \par
|
||
* There are some details of importance to be noted. For one, receiving a
|
||
* positive acknowlegement via the acks array does not imply that the
|
||
* associated packet is immune from being dropped before it is read and
|
||
* processed by the receiving entity. It does, however, imply that the sender
|
||
* should stop retransmitting the packet until further notice. Also, arrival of
|
||
* an ack packet should prompt the transmitter to immediately retransmit all
|
||
* packets it holds that have not been explicitly acknowledged and that were
|
||
* last transmitted with a serial number less than the highest serial number
|
||
* acknowledged by the acks array.
|
||
* Note: The fields in this structure are always kept in wire format, namely in
|
||
* network byte order.
|
||
*
|
||
* \subsection sec5-3-4 Section 5.3.4: Debugging and Statistics
|
||
*
|
||
* \par
|
||
* The following structures are defined in support of the debugging and
|
||
* statistics-gathering interfaces provided by Rx.
|
||
*
|
||
* \subsubsection sec5-3-4-1 Section 5.3.4.1: struct rx stats
|
||
*
|
||
* \par
|
||
* This structure maintains Rx statistics, and is gathered by such tools as the
|
||
* rxdebug program. It must be possible for all of the fields placed in this
|
||
* structure to be successfully converted from their on-wire network byte
|
||
* orderings to the host-specific ordering.
|
||
* \par
|
||
* \b fields
|
||
* \li int packetRequests - Number of packet allocation requests processed.
|
||
* \li int noPackets[RX N PACKET CLASSES] - Number of failed packet requests,
|
||
* organized per allocation class.
|
||
* \li int socketGreedy - Whether the SO GREEDY setting succeeded for the Rx
|
||
* socket.
|
||
* \li int bogusPacketOnRead - Number of inappropriately short packets
|
||
* received.
|
||
* \li int bogusHost - Contains the host address from the last bogus packet
|
||
* received.
|
||
* \li int noPacketOnRead - Number of attempts to read a packet off the wire
|
||
* when there was actually no packet there.
|
||
* \li int noPacketBuffersOnRead - Number of dropped data packets due to lack
|
||
* of packet buffers.
|
||
* \li int selects - Number of selects waiting for a packet arrival or a
|
||
* timeout.
|
||
* \li int sendSelects - Number of selects forced when sending packets.
|
||
* \li int packetsRead[RX N PACKET TYPES] - Total number of packets read,
|
||
* classified by type.
|
||
* \li int dataPacketsRead - Number of unique data packets read off the wire.
|
||
* \li int ackPacketsRead - Number of ack packets read.
|
||
* \li int dupPacketsRead - Number of duplicate data packets read.
|
||
* \li int spuriousPacketsRead - Number of inappropriate data packets.
|
||
* \li int packetsSent[RX N PACKET TYPES] - Number of packet transmissions,
|
||
* broken down by packet type.
|
||
* \li int ackPacketsSent - Number of ack packets sent.
|
||
* \li int pingPacketsSent - Number of ping packets sent.
|
||
* \li int abortPacketsSent - Number of abort packets sent.
|
||
* \li int busyPacketsSent - Number of busy packets sent.
|
||
* \li int dataPacketsSent - Number of unique data packets sent.
|
||
* \li int dataPacketsReSent - Number of retransmissions.
|
||
* \li int dataPacketsPushed - Number of retransmissions pushed early by a
|
||
* negative acknowledgement.
|
||
* \li int ignoreAckedPacket - Number of packets not retransmitted because they
|
||
* have already been acked.
|
||
* \li int struct clock totalRtt - Total round trip time measured for packets,
|
||
* used to compute average time figure.
|
||
* \li struct clock minRtt - Minimum round trip time measured for packets.
|
||
* struct clock maxRtt - Maximum round trip time measured for packets.
|
||
* \li int nRttSamples - Number of round trip samples.
|
||
* \li int nServerConns - Number of server connections.
|
||
* \li int nClientConns - Number of client connections.
|
||
* \li int nPeerStructs - Number of peer structures.
|
||
* \li int nCallStructs - Number of call structures physically allocated (using
|
||
* the internal storage allocator routine).
|
||
* \li int nFreeCallStructs - Number of call structures which were pulled from
|
||
* the free queue, thus avoiding a call to the internal storage allocator
|
||
* routine.
|
||
* \li int spares[10] - Ten integer spare fields, reserved for future use.
|
||
*
|
||
* \subsubsection sec5-3-4-2 Section 5.3.4.2: struct rx debugIn
|
||
*
|
||
* \par
|
||
* This structure defines the data format for a packet requesting one of the
|
||
* statistics collections maintained by Rx.
|
||
* \par
|
||
* \b fields
|
||
* \li long type - The specific data collection that the caller desires. Legal
|
||
* settings for this field are described in Section 5.2.16.2.
|
||
* \li long index - This field is only used when gathering information on Rx
|
||
* connections. Choose the index of the server-side connection record of which
|
||
* we are inquiring. This field may be used as an iterator, stepping through
|
||
* all the connection records, one per debugging request, until they have all
|
||
* been examined.
|
||
*
|
||
* \subsubsection sec5-3-4-3 Section 5.3.4.3: struct rx debugStats
|
||
*
|
||
* \par
|
||
* This structure describes the data format for a reply to an RX DEBUGI
|
||
* GETSTATS debugging request packet. These fields are given values indicating
|
||
* the current state of the Rx facility.
|
||
* \par
|
||
* \b fields
|
||
* \li long nFreePackets - Number of packet buffers currently assigned to the
|
||
* free pool.
|
||
* \li long packetReclaims - Currently unused.
|
||
* \li long callsExecuted - Number of calls executed since the Rx facility was
|
||
* initialized.
|
||
* \li char waitingForPackets - Is Rx currently blocked waiting for a packet
|
||
* buffer to come free?
|
||
* \li char usedFDs - If the Rx facility is executing in the kernel, return the
|
||
* number of unix file descriptors in use. This number is not directly related
|
||
* to the Rx package, but rather describes the state of the machine on which Rx
|
||
* is running.
|
||
* \li char version - Version number of the debugging package.
|
||
* \li char spare1[1] - Byte spare, reserved for future use.
|
||
* \li long spare2[10] - Set of 10 longword spares, reserved for future use.
|
||
*
|
||
* \subsubsection sec5-3-4-4 Section 5.3.4.4: struct rx debugConn
|
||
*
|
||
* \par
|
||
* This structure defines the data format returned when a caller requests
|
||
* information concerning an Rx connection. Thus, rx debugConn defines the
|
||
* external packaging of interest to external parties. Most of these fields are
|
||
* set from the rx connection structure, as defined in Section 5.3.2.2, and
|
||
* others are obtained by indirecting through such objects as the connection's
|
||
* peer and call structures.
|
||
* \par
|
||
* \b fields
|
||
* \li long host - Address of the host identified by the connection's peer
|
||
* structure.
|
||
* \li long cid - The connection ID.
|
||
* \li long serial - The serial number of the next outgoing packet associated
|
||
* with this connection.
|
||
* \li long callNumber[RX MAXCALLS] - The current call numbers for the
|
||
* individual call channels on this connection.
|
||
* \li long error - Records the latest error code for calls occurring on this
|
||
* connection.
|
||
* \li short port - UDP port associated with the connection's peer.
|
||
* \li char flags - State of the connection; see Section 5.2.4 for individual
|
||
* bit definitions.
|
||
* \li char type - Whether the connection is a server-side or client-side one.
|
||
* See Section 5.2.5 for individual bit definitions.
|
||
* \li char securityIndex - Index in the associated server-side service class
|
||
* of the security object being used by this call.
|
||
* \li char sparec[3] - Used to force alignment for later fields.
|
||
* \li char callState[RX MAXCALLS] - Current call state on each call channel.
|
||
* The associated bit definitions appear in Section 5.2.7.
|
||
* \li char callMode[RX MAXCALLS] - Current mode of all call channels that are
|
||
* in RX STATE ACTIVE state. The associated bit definitions appear in Section
|
||
* 5.2.8.
|
||
* \li char callFlags[RX MAXCALLS] - Flags pertaining to the state of each of
|
||
* the connection's call channels. The associated bit definitions appear in
|
||
* Section 5.2.7.
|
||
* \li char callOther[RX MAXCALLS] - Flag field for each call channel, where
|
||
* the presence of the RX OTHER IN flag indicates that there are packets
|
||
* present on the given call's reception queue, and the RX OTHER OUT flag
|
||
* indicates the presence of packets on the transmission queue.
|
||
* \li struct rx securityObjectStats secStats - The contents of the statistics
|
||
* related to the security object selected by the securityIndex field, if any.
|
||
* \li long epoch - The connection's client-side incarnation time.
|
||
* \li long sparel[10] - A set of 10 longword fields, reserved for future use.
|
||
*
|
||
* \subsubsection sec5-3-4-5 Section 5.3.4.5: struct rx debugConn vL
|
||
*
|
||
* \par
|
||
* This structure is identical to rx debugConn defined above, except for the
|
||
* fact that it is missing the sparec field. This sparec field is used in rx
|
||
* debugConn to fix an alignment problem that was discovered in version L of
|
||
* the debugging/statistics interface (hence the trailing "tt vL tag in the
|
||
* structure name). This alignment problem is fixed in version M, which
|
||
* utilizes and exports the rx debugConn structure exclusively. Information
|
||
* regarding the range of version-numbering values for the Rx
|
||
* debugging/statistics interface may be found in Section 5.2.16.1.
|
||
* \section sec5-4 Section 5.4: Exported Variables
|
||
*
|
||
* \par
|
||
* This section describes the set of variables that the Rx facility exports to
|
||
* its applications. Some of these variables have macros defined for the sole
|
||
* purpose of providing the caller with a convenient way to manipulate them.
|
||
* Note that some of these exported variables are never meant to be altered by
|
||
* application code (e.g., rx nPackets).
|
||
*
|
||
* \subsection sec5-4-1 Section 5.4.1: rx connDeadTime
|
||
*
|
||
* \par
|
||
* This integer-valued variable determines the maximum number of seconds that a
|
||
* connection may remain completely inactive, without receiving packets of any
|
||
* kind, before it is eligible for garbage collection. Its initial value is 12
|
||
* seconds. The rx SetRxDeadTime macro sets the value of this variable.
|
||
*
|
||
* \subsection sec5-4-2 Section 5.4.2: rx idleConnectionTime
|
||
*
|
||
* \par
|
||
* This integer-valued variable determines the maximum number of seconds that a
|
||
* server connection may "idle" (i.e., not have any active calls and otherwise
|
||
* not have sent a packet) before becoming eligible for garbage collection. Its
|
||
* initial value is 60 seconds.
|
||
*
|
||
* \subsection sec5-4-3 Section 5.4.3: rx idlePeerTime
|
||
*
|
||
* \par
|
||
* This integer-valued variable determines the maximum number of seconds that
|
||
* an Rx peer structure is allowed to exist without any connection structures
|
||
* referencing it before becoming eligible for garbage collection. Its initial
|
||
* value is 60 seconds.
|
||
*
|
||
* \subsection sec5-4-4 Section 5.4.4: rx extraQuota
|
||
*
|
||
* \par
|
||
* This integer-valued variable is part of the Rx packet quota system (see
|
||
* Section 1.2.6), which is used to avoid system deadlock. This ensures that
|
||
* each server-side thread has a minimum number of packets at its disposal,
|
||
* allowing it to continue making progress on active calls. This particular
|
||
* variable records how many extra data packets a user has requested be
|
||
* allocated. Its initial value is 0.
|
||
*
|
||
* \subsection sec5-4-5 Section 5.4.5: rx extraPackets
|
||
*
|
||
* \par
|
||
* This integer-valued variable records how many additional packet buffers are
|
||
* to be created for each Rx server thread. The caller, upon setting this
|
||
* variable, is applying some application-specific knowledge of the level of
|
||
* network activity expected. The rx extraPackets variable is used to compute
|
||
* the overall number of packet buffers to reserve per server thread, namely rx
|
||
* nPackets, described below. The initial value is 32 packets.
|
||
*
|
||
* \subsection sec5-4-6 Section 5.4.6: rx nPackets
|
||
*
|
||
* \par
|
||
* This integer-valued variable records the total number of packet buffers to
|
||
* be allocated per Rx server thread. It takes into account the quota packet
|
||
* buffers and the extra buffers requested by the caller, if any.
|
||
* \note This variable should never be set directly; the Rx facility itself
|
||
* computes its value. Setting it incorrectly may result in the service
|
||
* becoming deadlocked due to insufficient resources. Callers wishing to
|
||
* allocate more packet buffers to their server threads should indicate that
|
||
* desire by setting the rx extraPackets variable described above.
|
||
*
|
||
* \subsection sec5-4-7 Section 5.4.7: rx nFreePackets
|
||
*
|
||
* \par
|
||
* This integer-valued variable records the number of Rx packet buffers not
|
||
* currently used by any call. These unused buffers are collected into a free
|
||
* pool.
|
||
*
|
||
* \subsection sec5-4-8 Section 5.4.8: rx stackSize
|
||
*
|
||
* \par
|
||
* This integer-valued variable records the size in bytes for the lightweight
|
||
* process stack. The variable is initially set to RX DEFAULT STACK SIZE, and
|
||
* is typically manipulated via the rx SetStackSize() macro.
|
||
*
|
||
* \subsection sec5-4-9 Section 5.4.9: rx packetTypes
|
||
*
|
||
* \par
|
||
* This variable holds an array of string names used to describe the different
|
||
* roles for Rx packets. Its value is derived from the RX PACKET TYPES
|
||
* definition found in Section 5.2.11.
|
||
*
|
||
* \subsection sec5-4-10 Section 5.4.10: rx stats
|
||
*
|
||
* \par
|
||
* This variable contains the statistics structure that keeps track of Rx
|
||
* statistics. The struct rx stats structure it provides is defined in Section
|
||
* 5.3.4.1.
|
||
*
|
||
* \section sec5-5 Section 5.5: Macros
|
||
*
|
||
* \par
|
||
* Rx uses many macro definitions in preference to calling C functions
|
||
* directly. There are two main reasons for doing this:
|
||
* \li field selection: Many Rx operations are easily realized by returning the
|
||
* value of a particular structure's field. It is wasteful to invoke a C
|
||
* routine to simply fetch a structure's field, incurring unnecessary function
|
||
* call overhead. Yet, a convenient, procedure-oriented operation is still
|
||
* provided to Rx clients for such operations by the use of macros. For
|
||
* example, the rx ConnectionOf() macro, described in Section 5.5.1.1, simply
|
||
* indirects through the Rx call structure pointer parameter to deliver the
|
||
* conn field.
|
||
* \li Performance optimization: In some cases, a simple test or operation can
|
||
* be performed to accomplish a particular task. When this simple,
|
||
* straightforward operation fails, then a true C routine may be called to
|
||
* handle to more complex (and rarer) situation. The Rx macro rx Write(),
|
||
* described in Section 5.5.6.2, is a perfect example of this type of
|
||
* optimization. Invoking rx Write() first checks to determine whether or not
|
||
* the outgoing call's internal buffer has enough room to accept the specified
|
||
* data bytes. If so, it copies them into the call's buffer, updating counts
|
||
* and pointers as appropriate. Otherwise, rx Write() calls the rx WriteProc()
|
||
* to do the work, which in this more complicated case involves packet
|
||
* manipulations, dispatches, and allocations. The result is that the common,
|
||
* simple cases are often handled in-line, with more complex (and rarer) cases
|
||
* handled through true function invocations.
|
||
* \par
|
||
* The set of Rx macros is described according to the following categories.
|
||
* \li field selections/assignments
|
||
* \li Boolean operations
|
||
* \li Service attributes
|
||
* \li Security-related operations
|
||
* \li Sizing operations
|
||
* \li Complex operation
|
||
* \li Security operation invocations
|
||
*
|
||
* \subsection sec5-5-1 Section 5.5.1: field Selections/Assignments
|
||
*
|
||
* \par
|
||
* These macros facilitate the fetching and setting of fields from the
|
||
* structures described Chapter 5.3.
|
||
*
|
||
* \subsubsection sec5-5-1-1 Section 5.5.1.1: rx ConnectionOf()
|
||
*
|
||
* \par
|
||
* \#define rx_ConnectionOf(call) ((call)->conn)
|
||
* \par
|
||
* Generate a reference to the connection field within the given Rx call
|
||
* structure. The value supplied as the call argument must resolve into an
|
||
* object of type (struct rx call *). An application of the rx ConnectionOf()
|
||
* macro itself yields an object of type rx peer.
|
||
*
|
||
* \subsubsection sec5-5-1-2 Section 5.5.1.2: rx PeerOf()
|
||
*
|
||
* \par
|
||
* \#define rx_PeerOf(conn) ((conn)->peer)
|
||
* \par
|
||
* Generate a reference to the peer field within the given Rx call structure.
|
||
* The value supplied as the conn argument must resolve into an object of type
|
||
* (struct rx connection *). An instance of the rx PeerOf() macro itself
|
||
* resolves into an object of type rx peer.
|
||
*
|
||
* \subsubsection sec5-5-1-3 Section 5.5.1.3: rx HostOf()
|
||
*
|
||
* \par
|
||
* \#define rx_HostOf(peer) ((peer)->host)
|
||
* \par
|
||
* Generate a reference to the host field within the given Rx peer structure.
|
||
* The value supplied as the peer argument must resolve into an object of type
|
||
* (struct rx peer *). An instance of the rx HostOf() macro itself resolves
|
||
* into an object of type u long.
|
||
*
|
||
* \subsubsection sec5-5-1-4 Section 5.5.1.4: rx PortOf()
|
||
*
|
||
* \par
|
||
* \#define rx_PortOf(peer) ((peer)->port)
|
||
* \par
|
||
* Generate a reference to the port field within the given Rx peer structure.
|
||
* The value supplied as the peer argument must resolve into an object of type
|
||
* (struct rx peer *). An instance of the rx PortOf() macro itself resolves
|
||
* into an object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-1-5 Section 5.5.1.5: rx GetLocalStatus()
|
||
*
|
||
* \par
|
||
* \#define rx_GetLocalStatus(call, status) ((call)->localStatus)
|
||
* \par
|
||
* Generate a reference to the localStatus field, which specifies the local
|
||
* user status sent out of band, within the given Rx call structure. The value
|
||
* supplied as the call argument must resolve into an object of type (struct rx
|
||
* call *). The second argument, status, is not used. An instance of the rx
|
||
* GetLocalStatus() macro itself resolves into an object of type u char.
|
||
*
|
||
* \subsubsection sec5-5-1-6 Section 5.5.1.6: rx SetLocalStatus()
|
||
*
|
||
* \par
|
||
* \#define rx_SetLocalStatus(call, status) ((call)->localStatus = (status))
|
||
* \par
|
||
* Assign the contents of the localStatus field, which specifies the local user
|
||
* status sent out of band, within the given Rx call structure. The value
|
||
* supplied as the call argument must resolve into an object of type (struct rx
|
||
* call *). The second argument, status, provides the new value of the
|
||
* localStatus field, and must resolve into an object of type u char. An
|
||
* instance of the rx GetLocalStatus() macro itself resolves into an object
|
||
* resulting from the assignment, namely the u char status parameter.
|
||
*
|
||
* \subsubsection sec5-5-1-7 Section 5.5.1.7: rx GetRemoteStatus()
|
||
*
|
||
* \par
|
||
* \#define rx_GetRemoteStatus(call) ((call)->remoteStatus)
|
||
* \par
|
||
* Generate a reference to the remoteStatus field, which specifies the remote
|
||
* user status received out of band, within the given Rx call structure. The
|
||
* value supplied as the call argument must resolve into an object of type
|
||
* (struct rx call *). An instance of the rx GetRemoteStatus() macro itself
|
||
* resolves into an object of type u char.
|
||
*
|
||
* \subsubsection sec5-5-1-8 Section 5.5.1.8: rx Error()
|
||
*
|
||
* \par
|
||
* \#define rx_Error(call) ((call)->error)
|
||
* \par
|
||
* Generate a reference to the error field, which specifies the current error
|
||
* condition, within the given Rx call structure. The value supplied as the
|
||
* call argument must resolve into an object of type (struct rx call *). An
|
||
* instance of the rx Error() macro itself resolves into an object of type
|
||
* long.
|
||
*
|
||
* \subsubsection sec5-5-1-9 Section 5.5.1.9: rx DataOf()
|
||
*
|
||
* \par
|
||
* \#define rx_DataOf(packet) ((char *) (packet)->wire.data)
|
||
* \par
|
||
* Generate a reference to the beginning of the data portion within the given
|
||
* Rx packet as it appears on the wire. Any encryption headers will be resident
|
||
* at this address. For Rx packets of type RX PACKET TYPE DATA, the actual user
|
||
* data will appear at the address returned by the rx DataOf macro plus the
|
||
* connection's security header size. The value supplied as the packet argument
|
||
* must resolve into an object of type (struct rx packet *). An instance of the
|
||
* rx DataOf() macro itself resolves into an object of type (u long *).
|
||
*
|
||
* \subsubsection sec5-5-1-10 Section 5.5.1.10: rx GetDataSize()
|
||
*
|
||
* \par
|
||
* \#define rx_GetDataSize(packet) ((packet)->length)
|
||
* \par
|
||
* Generate a reference to the length field, which specifies the number of
|
||
* bytes of user data contained within the wire form of the packet, within the
|
||
* given Rx packet description structure. The value supplied as the packet
|
||
* argument must resolve into an object of type (struct rx packet *). An
|
||
* instance of the rx GetDataSize() macro itself resolves into an object of
|
||
* type short.
|
||
*
|
||
* \subsubsection sec5-5-1-11 Section 5.5.1.11: rx SetDataSize()
|
||
*
|
||
* \par
|
||
* \#define rx_SetDataSize(packet, size) ((packet)->length = (size))
|
||
* \par
|
||
* Assign the contents of the length field, which specifies the number of bytes
|
||
* of user data contained within the wire form of the packet, within the given
|
||
* Rx packet description structure. The value supplied as the packet argument
|
||
* must resolve into an object of type (struct rx packet *). The second
|
||
* argument, size, provides the new value of the length field, and must resolve
|
||
* into an object of type short. An instance of the rx SetDataSize() macro
|
||
* itself resolves into an object resulting from the assignment, namely the
|
||
* short length parameter.
|
||
*
|
||
* \subsubsection sec5-5-1-12 Section 5.5.1.12: rx GetPacketCksum()
|
||
*
|
||
* \par
|
||
* \#define rx_GetPacketCksum(packet) ((packet)->header.spare)
|
||
* \par
|
||
* Generate a reference to the header checksum field, as used by the built-in
|
||
* rxkad security module (See Chapter 3), within the given Rx packet
|
||
* description structure. The value supplied as the packet argument must
|
||
* resolve into an object of type (struct rx packet *). An instance of the rx
|
||
* GetPacketCksum() macro itself resolves into an object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-1-13 Section 5.5.1.13: rx SetPacketCksum()
|
||
*
|
||
* \par
|
||
* \#define rx_SetPacketCksum(packet, cksum) ((packet)->header.spare = (cksum))
|
||
* \par
|
||
* Assign the contents of the header checksum field, as used by the built-in
|
||
* rxkad security module (See Chapter 3), within the given Rx packet
|
||
* description structure. The value supplied as the packet argument must
|
||
* resolve into an object of type (struct rx packet *). The second argument,
|
||
* cksum, provides the new value of the checksum, and must resolve into an
|
||
* object of type u short. An instance of the rx SetPacketCksum() macro itself
|
||
* resolves into an object resulting from the assignment, namely the u short
|
||
* checksum parameter.
|
||
*
|
||
* \subsubsection sec5-5-1-14 Section 5.5.1.14: rx GetRock()
|
||
*
|
||
* \par
|
||
* \#define rx_GetRock(obj, type) ((type)(obj)->rock)
|
||
* \par
|
||
* Generate a reference to the field named rock within the object identified by
|
||
* the obj pointer. One common Rx structure to which this macro may be applied
|
||
* is struct rx connection. The specified rock field is casted to the value of
|
||
* the type parameter, which is the overall value of the rx GetRock() macro.
|
||
*
|
||
* \subsubsection sec5-5-1-15 Section 5.5.1.15: rx SetRock()
|
||
*
|
||
* \par
|
||
* \#define rx_SetRock(obj, newrock) ((obj)->rock = (VOID *)(newrock))
|
||
* \par
|
||
* Assign the contents of the newrock parameter into the rock field of the
|
||
* object pointed to by obj. The given object's rock field must be of type
|
||
* (VOID *). An instance of the rx SetRock() macro itself resolves into an
|
||
* object resulting from the assignment and is of type (VOID *).
|
||
*
|
||
* \subsubsection sec5-5-1-16 Section 5.5.1.16: rx SecurityClassOf()
|
||
*
|
||
* \par
|
||
* \#define rx_SecurityClassOf(conn) ((conn)->securityIndex)
|
||
* \par
|
||
* Generate a reference to the security index field of the given Rx connection
|
||
* description structure. This identifies the security class used by the
|
||
* connection. The value supplied as the conn argument must resolve into an
|
||
* object of type (struct rx connection *). An instance of the rx
|
||
* SecurityClassOf() macro itself resolves into an object of type u char.
|
||
*
|
||
* \subsubsection sec5-5-1-17 Section 5.5.1.17: rx SecurityObjectOf()
|
||
*
|
||
* \par
|
||
* \#define rx_SecurityObjectOf(conn) ((conn)->securityObject)
|
||
* \par
|
||
* Generate a reference to the security object in use by the given Rx
|
||
* connection description structure. The choice of security object determines
|
||
* the authentication protocol enforced by the connection. The value supplied
|
||
* as the conn argument must resolve into an object of type (struct rx
|
||
* connection *). An instance of the rx SecurityObjectOf() macro itself
|
||
* resolves into an object of type (struct rx securityClass *).
|
||
*
|
||
* \subsection sec5-5-2 Section 5.5.2: Boolean Operations
|
||
*
|
||
* \par
|
||
* The macros described in this section all return Boolean values. They are
|
||
* used to query such things as the whether a connection is a server-side or
|
||
* client-side one and if extra levels of checksumming are being used in Rx
|
||
* packet headers.
|
||
*
|
||
* \subsubsection sec5-5-2-1 Section 5.5.2.1: rx IsServerConn()
|
||
*
|
||
* \par
|
||
* \#define rx_IsServerConn(conn) ((conn)->type == RX_SERVER_CONNECTION)
|
||
* \par
|
||
* Determine whether or not the Rx connection specified by the conn argument is
|
||
* a server-side connection. The value supplied for conn must resolve to an
|
||
* object of type struct rx connection. The result is determined by testing
|
||
* whether or not the connection's type field is set to RX SERVER CONNECTION.
|
||
* \note Another macro, rx ServerConn(), performs the identical operation.
|
||
*
|
||
* \subsubsection sec5-5-2-2 Section 5.5.2.2: rx IsClientConn()
|
||
*
|
||
* \par
|
||
* \#define rx_IsClientConn(conn) ((conn)->type == RX_CLIENT_CONNECTION)
|
||
* \par
|
||
* Determine whether or not the Rx connection specified by the conn argument is
|
||
* a client-side connection. The value supplied for conn must resolve to an
|
||
* object of type struct rx connection. The result is determined by testing
|
||
* whether or not the connection's type field is set to RX CLIENT CONNECTION.
|
||
* \note Another macro, rx ClientConn(), performs the identical operation.
|
||
*
|
||
* \subsubsection sec5-5-2-3 Section 5.5.2.2: rx IsUsingPktCksum()
|
||
*
|
||
* \par
|
||
* \#define rx_IsUsingPktCksum(conn) ((conn)->flags &
|
||
* RX_CONN_USING_PACKET_CKSUM)
|
||
* \par
|
||
* Determine whether or not the Rx connection specified by the conn argument is
|
||
* checksum-ming the headers of all packets on its calls. The value supplied
|
||
* for conn must resolve to an object of type struct rx connection. The result
|
||
* is determined by testing whether or not the connection's flags field has the
|
||
* RX CONN USING PACKET CKSUM bit enabled.
|
||
*
|
||
* \subsection sec5-5-3 Section 5.5.3: Service Attributes
|
||
*
|
||
* \par
|
||
* This section describes user-callable macros that manipulate the attributes
|
||
* of an Rx service. Note that these macros must be called (and hence their
|
||
* operations performed) before the given service is installed via the
|
||
* appropriate invocation of the associated rx StartServer() function.
|
||
*
|
||
* \subsubsection sec5-5-3-1 Section 5.5.3.1: rx SetStackSize()
|
||
*
|
||
* \par
|
||
* rx_stackSize = (((stackSize) stackSize) > rx_stackSize) ? stackSize :
|
||
* rx_stackSize)
|
||
* \par
|
||
* Inform the Rx facility of the stack size in bytes for a class of threads to
|
||
* be created in support of Rx services. The exported rx stackSize variable
|
||
* tracks the high-water mark for all stack size requests before the call to rx
|
||
* StartServer(). If no calls to rx SetStackSize() are made, then rx stackSize
|
||
* will retain its default setting of RX DEFAULT STACK SIZE.
|
||
* \par
|
||
* In this macro, the first argument is not used. It was originally intended
|
||
* that thread stack sizes would be settable on a per-service basis. However,
|
||
* calls to rx SetStackSize() will ignore the service parameter and set the
|
||
* high-water mark for all Rx threads created after the use of rx
|
||
* SetStackSize(). The second argument, stackSize, specifies determines the new
|
||
* stack size, and should resolve to an object of type int. The value placed in
|
||
* the stackSize parameter will not be recorded in the global rx stackSize
|
||
* variable unless it is greater than the variable's current setting.
|
||
* \par
|
||
* An instance of the rx SetStackSize() macro itself resolves into the result
|
||
* of the assignment, which is an object of type int.
|
||
*
|
||
* \subsubsection sec5-5-3-2 Section 5.5.3.2: rx SetMinProcs()
|
||
*
|
||
* \par
|
||
* \#define rx_SetMinProcs(service, min) ((service)->minProcs = (min))
|
||
* \par
|
||
* Choose min as the minimum number of threads guaranteed to be available for
|
||
* parallel execution of the given Rx service. The service parameter should
|
||
* resolve to an object of type struct rx service. The min parameter should
|
||
* resolve to an object of type short. An instance of the rx SetMinProcs()
|
||
* macro itself resolves into the result of the assignment, which is an object
|
||
* of type short.
|
||
*
|
||
* \subsubsection sec5-5-3-3 Section 5.5.3.3: rx SetMaxProcs()
|
||
*
|
||
* \par
|
||
* \#define rx_SetMaxProcs(service, max) ((service)->maxProcs = (max))
|
||
* \par
|
||
* Limit the maximum number of threads that may be made available to the given
|
||
* Rx service for parallel execution to be max. The service parameter should
|
||
* resolve to an object of type struct rx service. The max parameter should
|
||
* resolve to an object of type short. An instance of the rx SetMaxProcs()
|
||
* macro itself resolves into the result of the assignment, which is an object
|
||
* of type short.
|
||
*
|
||
* \subsubsection sec5-5-3-4 Section 5.5.3.4: rx SetIdleDeadTime()
|
||
*
|
||
* \par
|
||
* \#define rx_SetIdleDeadTime(service, time) ((service)->idleDeadTime =
|
||
* (time))
|
||
* \par
|
||
* Every Rx service has a maximum amount of time it is willing to have its
|
||
* active calls sit idle (i.e., no new data is read or written for a call
|
||
* marked as RX STATE ACTIVE) before unilaterally shutting down the call. The
|
||
* expired call will have its error field set to RX CALL TIMEOUT. The operative
|
||
* assumption in this situation is that the client code is exhibiting a
|
||
* protocol error that prevents progress from being made on this call, and thus
|
||
* the call's resources on the server side should be freed. The default value,
|
||
* as recorded in the service's idleDeadTime field, is set at service creation
|
||
* time to be 60 seconds. The rx SetIdleTime() macro allows a caller to
|
||
* dynamically set this idle call timeout value.
|
||
* \par
|
||
* The service parameter should resolve to an object of type struct rx service.
|
||
* Also, the time parameter should resolve to an object of type short. finally,
|
||
* an instance of the rx SetIdleDeadTime() macro itself resolves into the
|
||
* result of the assignment, which is an object of type short.
|
||
*
|
||
* \subsubsection sec5-5-3-5 Section 5.5.3.5: rx SetServiceDeadTime()
|
||
*
|
||
* \par
|
||
* \#define rx_SetServiceDeadTime(service, seconds)
|
||
* ((service)->secondsUntilDead = (seconds))
|
||
* \note This macro definition is obsolete and should NOT be used. Including it
|
||
* in application code will generate a compile-time error, since the service
|
||
* structure no longer has such a field defined.
|
||
* \par
|
||
* See the description of the rx SetConnDeadTime() macro below to see how hard
|
||
* timeouts may be set for situations of complete call inactivity.
|
||
*
|
||
* \subsubsection sec5-5-3-6 Section 5.5.3.6: rx SetRxDeadTime()
|
||
*
|
||
* \par
|
||
* \#define rx_SetRxDeadTime(seconds) (rx_connDeadTime = (seconds))
|
||
* \par
|
||
* Inform the Rx facility of the maximum number of seconds of complete
|
||
* inactivity that will be tolerated on an active call. The exported rx
|
||
* connDeadTime variable tracks this value, and is initialized to a value of 12
|
||
* seconds. The current value of rx connDeadTime will be copied into new Rx
|
||
* service and connection records upon their creation.
|
||
* \par
|
||
* The seconds argument determines the value of rx connDeadTime, and should
|
||
* resolve to an object of type int. An instance of the rx SetRxDeadTime()
|
||
* macro itself resolves into the result of the assignment, which is an object
|
||
* of type int.
|
||
*
|
||
* \subsubsection sec5-5-3-7 Section 5.5.3.7: rx SetConnDeadTime()
|
||
*
|
||
* \par
|
||
* \#define rx_SetConnDeadTime(conn, seconds) (rxi_SetConnDeadTime(conn,
|
||
* seconds))
|
||
* \par
|
||
* Every Rx connection has a maximum amount of time it is willing to have its
|
||
* active calls on a server connection sit without receiving packets of any
|
||
* kind from its peer. After such a quiescent time, during which neither data
|
||
* packets (regardless of whether they are properly sequenced or duplicates)
|
||
* nor keep-alive packets are received, the call's error field is set to RX
|
||
* CALL DEAD and the call is terminated. The operative assumption in this
|
||
* situation is that the client making the call has perished, and thus the
|
||
* call's resources on the server side should be freed. The default value, as
|
||
* recorded in the connection's secondsUntilDead field, is set at connection
|
||
* creation time to be the same as its parent service. The rx SetConnDeadTime()
|
||
* macro allows a caller to dynamically set this timeout value.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* Also, the seconds parameter should resolve to an object of type int.
|
||
* finally, an instance of the rx SetConnDeadTime() macro itself resolves into
|
||
* the a call to rxi SetConnDeadTime(), whose return value is void.
|
||
*
|
||
* \subsubsection sec5-5-3-8 Section 5.5.3.8: rx SetConnHardDeadTime()
|
||
*
|
||
* \par
|
||
* \#define rx_SetConnHardDeadTime(conn, seconds) ((conn)->hardDeadTime =
|
||
* (seconds))
|
||
* \par
|
||
* It is convenient to be able to specify that calls on certain Rx connections
|
||
* have a hard absolute timeout. This guards against protocol errors not caught
|
||
* by other checks in which one or both of the client and server are looping.
|
||
* The rx SetConnHardDeadTime() macro is available for this purpose. It will
|
||
* limit calls on the connection identified by the conn parameter to execution
|
||
* times of no more than the given number of seconds. By default, active calls
|
||
* on an Rx connection may proceed for an unbounded time, as long as they are
|
||
* not totally quiescent (see Section 5.5.3.7 for a description of the rx
|
||
* SetConnDeadTime()) or idle (see Section 5.5.3.4 for a description of the rx
|
||
* SetIdleDeadTime()).
|
||
* \par
|
||
* The conn parameter should resolve to an object of type (struct rx connection
|
||
* *). The seconds parameter should resolve to an object of type u short. An
|
||
* instance of the rx SetConnHardDeadTime() macro itself resolves into the
|
||
* result of the assignment, which is an object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-3-9 Section 5.5.3.9: rx GetBeforeProc()
|
||
*
|
||
* \par
|
||
* \#define rx_GetBeforeProc(service) ((service)->beforeProc)
|
||
* \par
|
||
* Return a pointer of type (VOID *)() to the procedure associated with the
|
||
* given Rx service that will be called immediately upon activation of a server
|
||
* thread to handle an incoming call. The service parameter should resolve to
|
||
* an object of type struct rx service.
|
||
* \par
|
||
* When an Rx service is first created (via a call to the rx NewService()
|
||
* function), its beforeProc field is set to a null pointer. See the
|
||
* description of the rx SetBeforeProc() below.
|
||
*
|
||
* \subsubsection sec5-5-3-10 Section 5.5.3.10: rx SetBeforeProc()
|
||
*
|
||
* \par
|
||
* \#define rx_SetBeforeProc(service, proc) ((service)->beforeProc = (proc))
|
||
* \par
|
||
* Instruct the Rx facility to call the procedure identified by the proc
|
||
* parameter immediately upon activation of a server thread to handle an
|
||
* incoming call. The specified procedure will be called with a single
|
||
* parameter, a pointer of type struct rx call, identifying the call this
|
||
* thread will now be responsible for handling. The value returned by the
|
||
* procedure, if any, is discarded.
|
||
* \par
|
||
* The service parameter should resolve to an object of type struct rx service.
|
||
* The proc parameter should resolve to an object of type (VOID *)(). An
|
||
* instance of the rx SetBeforeProc() macro itself resolves into the result of
|
||
* the assignment, which is an object of type (VOID *)().
|
||
*
|
||
* \subsubsection sec5-5-3-11 Section 5.5.3.11: rx GetAfterProc()
|
||
*
|
||
* \par
|
||
* \#define rx_GetAfterProc(service) ((service)->afterProc)
|
||
* \par
|
||
* Return a pointer of type (VOID *)() to the procedure associated with the
|
||
* given Rx service that will be called immediately upon completion of the
|
||
* particular Rx call for which a server thread was activated. The service
|
||
* parameter should resolve to an object of type struct rx service.
|
||
* \par
|
||
* When an Rx service is first created (via a call to the rx NewService()
|
||
* function), its afterProc field is set to a null pointer. See the description
|
||
* of the rx SetAfterProc() below.
|
||
*
|
||
* \subsubsection sec5-5-3-12 Section 5.5.3.12: rx SetAfterProc()
|
||
*
|
||
* \par
|
||
* \#define rx_SetAfterProc(service, proc) ((service)->afterProc = (proc))
|
||
* \par
|
||
* Instruct the Rx facility to call the procedure identified by the proc
|
||
* parameter immediately upon completion of the particular Rx call for which a
|
||
* server thread was activated. The specified procedure will be called with a
|
||
* single parameter, a pointer of type struct rx call, identifying the call
|
||
* this thread just handled. The value returned by the procedure, if any, is
|
||
* discarded.
|
||
* \par
|
||
* The service parameter should resolve to an object of type struct rx service.
|
||
* The proc parameter should resolve to an object of type (VOID *)(). An
|
||
* instance of the rx SetAfterProc() macro itself resolves into the result of
|
||
* the assignment, which is an object of type (VOID *)().
|
||
*
|
||
* \subsubsection sec5-5-3-13 Section 5.5.3.13: rx SetNewConnProc()
|
||
*
|
||
* \par
|
||
* \#define rx_SetNewConnProc(service, proc) ((service)->newConnProc = (proc))
|
||
* \par
|
||
* Instruct the Rx facility to call the procedure identified by the proc
|
||
* parameter as the last step in the creation of a new Rx server-side
|
||
* connection for the given service. The specified procedure will be called
|
||
* with a single parameter, a pointer of type (struct rx connection *),
|
||
* identifying the connection structure that was just built. The value returned
|
||
* by the procedure, if any, is discarded.
|
||
* \par
|
||
* The service parameter should resolve to an object of type struct rx service.
|
||
* The proc parameter should resolve to an object of type (VOID *)(). An
|
||
* instance of the rx SetNewConnProc() macro itself resolves into the result of
|
||
* the assignment, which is an object of type (VOID *)().
|
||
* \note There is no access counterpart defined for this macro, namely one that
|
||
* returns the current setting of a service's newConnProc.
|
||
*
|
||
* \subsubsection sec5-5-3-14 Section 5.5.3.14: rx SetDestroyConnProc()
|
||
*
|
||
* \par
|
||
* \#define rx_SetDestroyConnProc(service, proc) ((service)->destroyConnProc =
|
||
* (proc))
|
||
* \par
|
||
* Instruct the Rx facility to call the procedure identified by the proc
|
||
* parameter just before a server connection associated with the given Rx
|
||
* service is destroyed. The specified procedure will be called with a single
|
||
* parameter, a pointer of type (struct rx connection *), identifying the
|
||
* connection about to be destroyed. The value returned by the procedure, if
|
||
* any, is discarded.
|
||
* \par
|
||
* The service parameter should resolve to an object of type struct rx service.
|
||
* The proc parameter should resolve to an object of type (VOID *)(). An
|
||
* instance of the rx SetDestroyConnProc() macro itself resolves into the
|
||
* result of the assignment, which is an object of type (VOID *)().
|
||
* \note There is no access counterpart defined for this macro, namely one that
|
||
* returns the current setting of a service's destroyConnProc.
|
||
*
|
||
* \subsection sec5-5-4 Section 5.5.4: Security-Related Operations
|
||
*
|
||
* \par
|
||
* The following macros are callable by Rx security modules, and assist in
|
||
* getting and setting header and trailer lengths, setting actual packet size,
|
||
* and finding the beginning of the security header (or data).
|
||
*
|
||
* \subsubsection sec5-5-4-1 Section 5.5.4.1: rx GetSecurityHeaderSize()
|
||
*
|
||
* \par
|
||
* \#define rx_GetSecurityHeaderSize(conn) ((conn)->securityHeaderSize)
|
||
* \par
|
||
* Generate a reference to the field in an Rx connection structure that records
|
||
* the length in bytes of the associated security module's packet header data.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* An instance of the rx GetSecurityHeaderSize() macro itself resolves into an
|
||
* object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-4-2 Section 5.5.4.2: rx SetSecurityHeaderSize()
|
||
*
|
||
* \par
|
||
* \#define rx_SetSecurityHeaderSize(conn, length) ((conn)->securityHeaderSize
|
||
* = (length))
|
||
* \par
|
||
* Set the field in a connection structure that records the length in bytes of
|
||
* the associated security module's packet header data.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* The length parameter should resolve to an object of type u short. An
|
||
* instance of the rx SetSecurityHeaderSize() macro itself resolves into the
|
||
* result of the assignment, which is an object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-4-3 Section 5.5.4.3: rx
|
||
* GetSecurityMaxTrailerSize()
|
||
*
|
||
* \par
|
||
* \#define rx_GetSecurityMaxTrailerSize(conn) ((conn)->securityMaxTrailerSize)
|
||
* \par
|
||
* Generate a reference to the field in an Rx connection structure that records
|
||
* the maximum length in bytes of the associated security module's packet
|
||
* trailer data.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* An instance of the rx GetSecurityMaxTrailerSize() macro itself resolves into
|
||
* an object of type u short.
|
||
*
|
||
* \subsubsection sec5-5-4-4 Section 5.5.4.4: rx
|
||
* SetSecurityMaxTrailerSize()
|
||
*
|
||
* \par
|
||
* \#define rx_SetSecurityMaxTrailerSize(conn, length)
|
||
* ((conn)->securityMaxTrailerSize = (length))
|
||
* \par
|
||
* Set the field in a connection structure that records the maximum length in
|
||
* bytes of the associated security module's packet trailer data.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* The length parameter should resolve to an object of type u short. An
|
||
* instance of the rx SetSecurityHeaderSize() macro itself resolves into the
|
||
* result of the assignment, which is an object of type u short.
|
||
*
|
||
* \subsection sec5-5-5 Section 5.5.5: Sizing Operations
|
||
*
|
||
* \par
|
||
* The macros described in this section assist the application programmer in
|
||
* determining the sizes of the various Rx packet regions, as well as their
|
||
* placement within a packet buffer.
|
||
*
|
||
* \subsubsection sec5-5-5-1 Section 5.5.5.1: rx UserDataOf()
|
||
*
|
||
* \par
|
||
* \#define rx_UserDataOf(conn, packet) (((char *) (packet)->wire.data) +
|
||
* (conn)->securityHeaderSize)
|
||
* \par
|
||
* Generate a pointer to the beginning of the actual user data in the given Rx
|
||
* packet, that is associated with the connection described by the conn
|
||
* pointer. User data appears immediately after the packet's security header
|
||
* region, whose length is determined by the security module used by the
|
||
* connection. The conn parameter should resolve to an object of type struct rx
|
||
* connection. The packet parameter should resolve to an object of type struct
|
||
* rx packet. An instance of the rx UserDataOf() macro itself resolves into an
|
||
* object of type (char *).
|
||
*
|
||
* \subsubsection sec5-5-5-2 Section 5.5.5.2: rx MaxUserDataSize()
|
||
*
|
||
* \par
|
||
* \#define rx_MaxUserDataSize(conn)
|
||
* \n ((conn)->peer->packetSize
|
||
* \n -RX_HEADER_SIZE
|
||
* \n -(conn)->securityHeaderSize
|
||
* \n -(conn)->securityMaxTrailerSize)
|
||
* \par
|
||
* Return the maximum number of user data bytes that may be carried by a packet
|
||
* on the Rx connection described by the conn pointer. The overall packet size
|
||
* is reduced by the IP, UDP, and Rx headers, as well as the header and trailer
|
||
* areas required by the connection's security module.
|
||
* \par
|
||
* The conn parameter should resolve to an object of type struct rx connection.
|
||
* An instance of the rx MaxUserDataSize() macro itself resolves into the an
|
||
* object of type (u short).
|
||
*
|
||
* \subsection sec5-5-6 Section 5.5.6: Complex Operations
|
||
*
|
||
* \par
|
||
* Two Rx macros are designed to handle potentially complex operations, namely
|
||
* reading data from an active incoming call and writing data to an active
|
||
* outgoing call. Each call structure has an internal buffer that is used to
|
||
* collect and cache data traveling through the call. This buffer is used in
|
||
* conjunction with reading or writing to the actual Rx packets traveling on
|
||
* the wire in support of the call. The rx Read() and rx Write() macros allow
|
||
* their caller to simply manipulate the internal data buffer associated with
|
||
* the Rx call structures whenever possible, thus avoiding the overhead
|
||
* associated with a function call. When buffers are either filled or drained
|
||
* (depending on the direction of the data flow), these macros will then call
|
||
* functions to handle the more complex cases of generating or receiving
|
||
* packets in support of the operation.
|
||
*
|
||
* \subsubsection sec5-5-6-1 Section 5.5.6.1: rx Read()
|
||
*
|
||
* \par
|
||
* \#define rx_Read(call, buf, nbytes)
|
||
* \n ((call)->nLeft > (nbytes) ?
|
||
* \n memcpy((buf), (call)->bufPtr, (nbytes)),
|
||
* \n (call)->nLeft -= (nbytes), (call)->bufPtr += (nbytes), (nbytes)
|
||
* \n : rx_ReadProc((call), (buf), (nbytes)))
|
||
* \par
|
||
* Read nbytes of data from the given Rx call into the buffer to which buf
|
||
* points. If the call's internal buffer has at least nbytes bytes already
|
||
* filled, then this is done in-line with a copy and some pointer and counter
|
||
* updates within the call structure. If the call's internal buffer doesn't
|
||
* have enough data to satisfy the request, then the rx ReadProc() function
|
||
* will handle this more complex situation.
|
||
* \par
|
||
* In either case, the rx Read() macro returns the number of bytes actually
|
||
* read from the call, resolving to an object of type int. If rx Read() returns
|
||
* fewer than nbytes bytes, the call status should be checked via the rx
|
||
* Error() macro.
|
||
*
|
||
* \subsubsection sec5-5-6-2 Section 5.5.6.2: rx Write()
|
||
*
|
||
* \par
|
||
* \#define rx_Write(call, buf, nbytes)
|
||
* \n ((call)->nFree > (nbytes) ?
|
||
* \n memcpy((call)->bufPtr, (buf), (nbytes)),
|
||
* \n (call)->nFree -= (nbytes),
|
||
* \n (call)->bufPtr += (nbytes), (nbytes)
|
||
* \n : rx_WriteProc((call), (buf), (nbytes)))
|
||
* \par
|
||
* Write nbytes of data from the buffer pointed to by buf into the given Rx
|
||
* call. If the call's internal buffer has at least nbytes bytes free, then
|
||
* this is done in-line with a copy and some pointer and counter updates within
|
||
* the call structure. If the call's internal buffer doesn't have room, then
|
||
* the rx WriteProc() function will handle this more complex situation.
|
||
* \par
|
||
* In either case, the rx Write() macro returns the number of bytes actually
|
||
* written to the call, resolving to an object of type int. If zero is
|
||
* returned, the call status should be checked via the rx Error() macro.
|
||
*
|
||
* \subsection sec5-5-7 Section 5.5.7: Security Operation Invocations
|
||
*
|
||
* \par
|
||
* Every Rx security module is required to implement an identically-named set
|
||
* of operations, through which the security mechanism it defines is invoked.
|
||
* This characteristic interface is reminiscent of the vnode interface defined
|
||
* and popularized for file systems by Sun Microsystems [4]. The structure
|
||
* defining this function array is described in Section 5.3.1.1.
|
||
* \par
|
||
* These security operations are part of the struct rx securityClass, which
|
||
* keeps not only the ops array itself but also any private data they require
|
||
* and a reference count. Every Rx service contains an array of these security
|
||
* class objects, specifying the range of security mechanisms it is capable of
|
||
* enforcing. Every Rx connection within a service is associated with exactly
|
||
* one of that service's security objects, and every call issued on the
|
||
* connection will execute the given security protocol.
|
||
* \par
|
||
* The macros described below facilitate the execution of the security module
|
||
* interface functions. They are covered in the same order they appear in the
|
||
* struct rx securityOps declaration.
|
||
*
|
||
* \subsubsection sec5-5-7-1 Section 5.5.7.1: RXS OP()
|
||
*
|
||
* \code
|
||
* #if defined(__STDC__) && !defined(__HIGHC__)
|
||
* #define RXS_OP(obj, op, args)
|
||
* ((obj->ops->op_ ## op) ? (*(obj)->ops->op_ ## op)args : 0)
|
||
* #else
|
||
* #define RXS_OP(obj, op, args)
|
||
* ((obj->ops->op_op) ? (*(obj)->ops->op_op)args : 0)
|
||
* #endif
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The RXS OP macro represents the workhorse macro in this group, used by all
|
||
* the others. It takes three arguments, the first of which is a pointer to the
|
||
* security object to be referenced. This obj parameter must resolve to an
|
||
* object of type (struct rx securityOps *). The second parameter identifies
|
||
* the specific op to be performed on this security object. The actual text of
|
||
* this op argument is used to name the desired opcode function. The third and
|
||
* final argument, args, specifies the text of the argument list to be fed to
|
||
* the chosen security function. Note that this argument must contain the
|
||
* bracketing parentheses for the function call's arguments. In fact, note that
|
||
* each of the security function access macros defined below provides the
|
||
* enclosing parentheses to this third RXS OP() macro.
|
||
*
|
||
* \subsubsection sec5-5-7-2 Section 5.5.7.1: RXS Close()
|
||
*
|
||
* \par
|
||
* \#define RXS_Close(obj) RXS_OP(obj, Close, (obj))
|
||
* \par
|
||
* This macro causes the execution of the interface routine occupying the op
|
||
* Close() slot in the Rx security object identified by the obj pointer. This
|
||
* interface function is invoked by Rx immediately before a security object is
|
||
* discarded. Among the responsibilities of such a function might be
|
||
* decrementing the object's refCount field, and thus perhaps freeing up any
|
||
* space contained within the security object's private storage region,
|
||
* referenced by the object's privateData field.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). In generating a call to the security object's op Close() routine, the
|
||
* obj pointer is used as its single parameter. An invocation of the RXS
|
||
* Close() macro results in a return value identical to that of the op Close()
|
||
* routine, namely a value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-3 Section 5.5.7.3: RXS NewConnection()
|
||
*
|
||
* \par
|
||
* \#define RXS_NewConnection(obj, conn) RXS_OP(obj, NewConnection, (obj,
|
||
* conn))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* NewConnection() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx immediately after a
|
||
* connection using the given security object is created. Among the
|
||
* responsibilities of such a function might be incrementing the object's
|
||
* refCount field, and setting any per-connection information based on the
|
||
* associated security object's private storage region, as referenced by the
|
||
* object's privateData field.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the newly-created connection
|
||
* structure, and must resolve into an object of type (struct rx connection *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* NewConnection() slot, the obj and conn pointers are used as its two
|
||
* parameters. An invocation of the RXS NewConnection() macro results in a
|
||
* return value identical to that of the op NewConnection() routine, namely a
|
||
* value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-4 Section 5.5.7.4: RXS PreparePacket()
|
||
*
|
||
* \par
|
||
* \#define RXS_PreparePacket(obj, call, packet)
|
||
* \n RXS_OP(obj, PreparePacket, (obj, call, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* PreparePacket() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx each time it prepares an
|
||
* outward-bound packet. Among the responsibilities of such a function might be
|
||
* computing information to put into the packet's security header and/or
|
||
* trailer.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The call argument contains a pointer to the Rx call to which the given
|
||
* packet belongs, and must resolve to an object of type (struct rx call *).
|
||
* The final argument, packet, contains a pointer to the packet itself. It
|
||
* should resolve to an object of type (struct rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* PreparePacket() slot, the obj, call, and packet pointers are used as its
|
||
* three parameters. An invocation of the RXS PreparePacket() macro results in
|
||
* a return value identical to that of the op PreparePacket() routine, namely a
|
||
* value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-5 Section 5.5.7.5: RXS SendPacket()
|
||
*
|
||
* \par
|
||
* \#define RXS_SendPacket(obj, call, packet) RXS_OP(obj, SendPacket, (obj,
|
||
* call, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine occupying the op
|
||
* SendPacket() slot in the Rx security object identified by the obj pointer.
|
||
* This interface function is invoked by Rx each time it physically transmits
|
||
* an outward-bound packet. Among the responsibilities of such a function might
|
||
* be recomputing information in the packet's security header and/or trailer.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The call argument contains a pointer to the Rx call to which the given
|
||
* packet belongs, and must resolve to an object of type (struct rx call *).
|
||
* The final argument, packet, contains a pointer to the packet itself. It
|
||
* should resolve to an object of type (struct rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* SendPacket() slot, the obj, call, and packet pointers are used as its three
|
||
* parameters. An invocation of the RXS SendPacket() macro results in a return
|
||
* value identical to that of the op SendPacket() routine, namely a value of
|
||
* type int.
|
||
*
|
||
* \subsubsection sec5-5-7-6 Section 5.5.7.6: RXS CheckAuthentication()
|
||
*
|
||
* \par
|
||
* \#define RXS_CheckAuthentication(obj, conn) RXS_OP(obj, CheckAuthentication,
|
||
* (obj, conn))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* CheckAuthentication() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx each time it needs to
|
||
* check whether the given connection is one on which authenticated calls are
|
||
* being performed. Specifically, a value of 0 is returned if authenticated
|
||
* calls are not being executed on this connection, and a value of 1 is
|
||
* returned if they are.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection checked as to
|
||
* whether authentication is being performed, and must resolve to an object of
|
||
* type (struct rx connection *).
|
||
* \par
|
||
* In generating a call to the routine in the security object's op
|
||
* CheckAuthentication() slot, the obj and conn pointers are used as its two
|
||
* parameters. An invocation of the RXS CheckAuthentication() macro results in
|
||
* a return value identical to that of the op CheckAuthentication() routine,
|
||
* namely a value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-7 Section 5.5.7.7: RXS CreateChallenge()
|
||
*
|
||
* \par
|
||
* \#define RXS_CreateChallenge(obj, conn) RXS_OP(obj, CreateChallenge, (obj,
|
||
* conn))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* CreateChallenge() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx each time a challenge
|
||
* event is constructed for a given connection. Among the responsibilities of
|
||
* such a function might be marking the connection as temporarily
|
||
* unauthenticated until the given challenge is successfully met.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection for which the
|
||
* authentication challenge is being constructed, and must resolve to an object
|
||
* of type (struct rx connection *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* CreateChallenge() slot, the obj and conn pointers are used as its two
|
||
* parameters. An invocation of the RXS CreateChallenge() macro results in a
|
||
* return value identical to that of the op CreateChallenge() routine, namely a
|
||
* value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-8 Section 5.5.7.8: RXS GetChallenge()
|
||
*
|
||
* \par
|
||
* \#define RXS_GetChallenge(obj, conn, packet) RXS_OP(obj, GetChallenge, (obj,
|
||
* conn, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine occupying the op
|
||
* GetChallenge() slot in the Rx security object identified by the obj pointer.
|
||
* This interface function is invoked by Rx each time a challenge packet is
|
||
* constructed for a given connection. Among the responsibilities of such a
|
||
* function might be constructing the appropriate challenge structures in the
|
||
* area of packet dedicated to security matters.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection to which the
|
||
* given challenge packet belongs, and must resolve to an object of type
|
||
* (struct rx connection *). The final argument, packet, contains a pointer to
|
||
* the challenge packet itself. It should resolve to an object of type (struct
|
||
* rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* GetChallenge() slot, the obj, conn, and packet pointers are used as its
|
||
* three parameters. An invocation of the RXS GetChallenge() macro results in a
|
||
* return value identical to that of the op GetChallenge() routine, namely a
|
||
* value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-9 Section 5.5.7.9: RXS GetResponse()
|
||
*
|
||
* \par
|
||
* \#define RXS_GetResponse(obj, conn, packet) RXS_OP(obj, GetResponse, (obj,
|
||
* conn, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine occupying the op
|
||
* GetResponse() slot in the Rx security object identified by the obj pointer.
|
||
* This interface function is invoked by Rx on the server side each time a
|
||
* response to a challenge packet must be received.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx client connection that
|
||
* must respond to the authentication challenge, and must resolve to a (struct
|
||
* rx connection *) object. The final argument, packet, contains a pointer to
|
||
* the packet to be built in response to the challenge. It should resolve to an
|
||
* object of type (struct rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* GetResponse() slot, the obj, conn, and packet pointers are used as its three
|
||
* parameters. An invocation of the RXS GetResponse() macro results in a return
|
||
* value identical to that of the op GetResponse() routine, namely a value of
|
||
* type int.
|
||
*
|
||
* \subsubsection sec5-5-7-10 Section 5.5.7.10: RXS CheckResponse()
|
||
*
|
||
* \par
|
||
* \#define RXS_CheckResponse(obj, conn, packet) RXS_OP(obj, CheckResponse,
|
||
* (obj, conn, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* CheckResponse() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx on the server side each
|
||
* time a response to a challenge packet is received for a given connection.
|
||
* The responsibilities of such a function might include verifying the
|
||
* integrity of the response, pulling out the necessary security information
|
||
* and storing that information within the affected connection, and otherwise
|
||
* updating the state of the connection.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx server connection to
|
||
* which the given challenge response is directed. This argument must resolve
|
||
* to an object of type (struct rx connection *). The final argument, packet,
|
||
* contains a pointer to the packet received in response to the challenge
|
||
* itself. It should resolve to an object of type (struct rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* CheckResponse() slot, the obj, conn, and packet pointers are ued as its
|
||
* three parameters. An invocation of the RXS CheckResponse() macro results in
|
||
* a return value identical to that of the op CheckResponse() routine, namely a
|
||
* value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-11 Section 5.5.7.11: RXS CheckPacket()
|
||
*
|
||
* \par
|
||
* \#define RXS_CheckPacket(obj, call, packet) RXS_OP(obj, CheckPacket, (obj,
|
||
* call, packet))
|
||
* \par
|
||
* This macro causes the execution of the interface routine occupying the op
|
||
* CheckPacket() slot in the Rx security object identified by the obj pointer.
|
||
* This interface function is invoked by Rx each time a packet is received. The
|
||
* responsibilities of such a function might include verifying the integrity of
|
||
* given packet, detecting any unauthorized modifications or tampering.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection to which the
|
||
* given challenge response is directed, and must resolve to an object of type
|
||
* (struct rx connection *). The final argument, packet, contains a pointer to
|
||
* the packet received in response to the challenge itself. It should resolve
|
||
* to an object of type (struct rx packet *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* CheckPacket() slot, the obj, conn, and packet pointers are used as its three
|
||
* parameters. An invocation of the RXS CheckPacket() macro results in a return
|
||
* value identical to that of the op CheckPacket() routine, namely a value of
|
||
* type int.
|
||
* \par
|
||
* Please note that any non-zero return will cause Rx to abort all calls on the
|
||
* connection. Furthermore, the connection itself will be marked as being in
|
||
* error in such a case, causing it to reject any further incoming packets.
|
||
*
|
||
* \subsubsection sec5-5-7-12 Section 5.5.7.12: RXS DestroyConnection()
|
||
*
|
||
* \par
|
||
* \#define RXS_DestroyConnection(obj, conn) RXS_OP(obj, DestroyConnection,
|
||
* (obj, conn))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* DestroyConnection() slot in the Rx security object identified by the obj
|
||
* pointer. This interface function is invoked by Rx each time a connection
|
||
* employing the given security object is being destroyed. The responsibilities
|
||
* of such a function might include deleting any private data maintained by the
|
||
* security module for this connection.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection being reaped,
|
||
* and must resolve to a (struct rx connection *) object.
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* DestroyConnection() slot, the obj and conn pointers are used as its two
|
||
* parameters. An invocation of the RXS DestroyConnection() macro results in a
|
||
* return value identical to that of the op DestroyConnection() routine, namely
|
||
* a value of type int.
|
||
*
|
||
* \subsubsection sec5-5-7-13 Section 5.5.7.13: RXS GetStats()
|
||
*
|
||
* \par
|
||
* \#define RXS_GetStats(obj, conn, stats) RXS_OP(obj, GetStats, (obj, conn,
|
||
* stats))
|
||
* \par
|
||
* This macro causes the execution of the interface routine in the op
|
||
* GetStats() slot in the Rx security object identified by the obj pointer.
|
||
* This interface function is invoked by Rx each time current statistics
|
||
* concerning the given security object are desired.
|
||
* \par
|
||
* The obj parameter must resolve into an object of type (struct rx securityOps
|
||
* *). The conn argument contains a pointer to the Rx connection using the
|
||
* security object to be examined, and must resolve to an object of type
|
||
* (struct rx connection *). The final argument, stats, contains a pointer to a
|
||
* region to be filled with the desired statistics. It should resolve to an
|
||
* object of type (struct rx securityObjectStats *).
|
||
* \par
|
||
* In generating a call to the routine located at the security object's op
|
||
* GetStats() slot, the obj, conn, and stats pointers are used as its three
|
||
* parameters. An invocation of the RXS GetStats() macro results in a return
|
||
* value identical to that of the op GetStats() routine, namely a value of type
|
||
* int.
|
||
*
|
||
* \section sec5-6 Section 5.6: Functions
|
||
*
|
||
* \par
|
||
* Rx exports a collection of functions that, in conjuction with the macros
|
||
* explored in Section 5.5, allows its clients to set up and export services,
|
||
* create and tear down connections to these services, and execute remote
|
||
* procedure calls along these connections.
|
||
* \par
|
||
* This paper employs two basic categorizations of these Rx routines. One set
|
||
* of functions is meant to be called directly by clients of the facility, and
|
||
* are referred to as the exported operations. The individual members of the
|
||
* second set of functions are not meant to be called directly by Rx clients,
|
||
* but rather are called by the collection of defined macros, so they must
|
||
* still be lexically visible. These indirectly-executed routines are referred
|
||
* to here as the semi-exported operations.
|
||
* \par
|
||
* All Rx routines return zero upon success. The range of error codes employed
|
||
* by Rx is defined in Section 5.2.15.
|
||
*
|
||
* \subsection sec5-6-1 Section 5.6.1: Exported Operations
|
||
*
|
||
* \subsection sec5-6-2 Section 5.6.2: rx Init _ Initialize Rx
|
||
*
|
||
* \par
|
||
* int rx Init(IN int port)
|
||
* \par Description
|
||
* Initialize the Rx facility. If a non-zero port number is provided, it
|
||
* becomes the default port number for any service installed later. If 0 is
|
||
* provided for the port, a random port will be chosen by the system. The rx
|
||
* Init() function sets up internal tables and timers, along with starting up
|
||
* the listener thread.
|
||
* \par Error Codes
|
||
* RX ADDRINUSE The port provided has already been taken.
|
||
*
|
||
* \subsection sec5-6-3 Section 5.6.3: rx NewService _ Create and install
|
||
* a new service
|
||
*
|
||
* \par
|
||
* struct rx service *rx NewService(IN u short port; IN u short serviceId; IN
|
||
* char *serviceName; IN struct rx securityClass **securityObjects; IN int
|
||
* nSecurityObjects; IN long (*serviceProc)())
|
||
* \par Description
|
||
* Create and advertise a new Rx service. A service is uniquely named by a UDP
|
||
* port number plus a non-zero 16-bit serviceId on the given host. The port
|
||
* argument may be set to zero if rx Init() was called with a non-zero port
|
||
* number, in which case that original port will be used. A serviceName must
|
||
* also be provided, to be used for identification purposes (e.g., the service
|
||
* name might be used for probing for statistics). A pointer to an array of
|
||
* nSecurityObjects security objects to be associated with the new service is
|
||
* given in . securityObjects. The service's executeRequestProc() pointer is
|
||
* set to serviceProc.
|
||
* \par
|
||
* The function returns a pointer to a descriptor for the requested Rx service.
|
||
* A null return value indicates that the new service could not be created.
|
||
* Possible reasons include:
|
||
* \li The serviceId parameter was found to be zero.
|
||
* \li A port value of zero was specified at Rx initialization time (i.e., when
|
||
* rx init() was called), requiring a non-zero value for the port parameter
|
||
* here.
|
||
* \li Another Rx service is already using serviceId.
|
||
* \li Rx has already created the maximum RX MAX SERVICES Rx services (see
|
||
* Section 5.2.1).
|
||
* \par Error Codes
|
||
* (struct rx service *) NULL The new Rx service could not be created, due to
|
||
* one of the errors listed above.
|
||
*
|
||
* \subsection sec5-6-4 Section 5.6.4: rx NewConnection _ Create a new
|
||
* connection to a given service
|
||
*
|
||
* \par
|
||
* struct rx connection *rx NewConnection( IN u long shost, IN u short sport,
|
||
* IN u short sservice, IN struct rx securityClass *securityObject, IN int
|
||
* service SecurityIndex)
|
||
* \par Description
|
||
* Create a new Rx client connection to service sservice on the host whose IP
|
||
* address is contained in shost and to that host's sport UDP port. The
|
||
* corresponding Rx service identifier is expected in sservice. The caller also
|
||
* provides a pointer to the security object to use for the connection in
|
||
* securityObject, along with that object's serviceSecurityIndex among the
|
||
* security objects associated with service sservice via a previous rx
|
||
* NewService() call (see Section 5.6.3).
|
||
* \note It is permissible to provide a null value for the securityObject
|
||
* parameter if the chosen serviceSecurityIndex is zero. This corresponds to
|
||
* the pre-defined null security object, which does not engage in authorization
|
||
* checking of any kind.
|
||
* \par Error Codes
|
||
* --- A pointer to an initialized Rx connection is always returned, unless osi
|
||
* Panic() is called due to memory allocation failure.
|
||
*
|
||
* \subsection sec5-6-5 Section 5.6.5: rx NewCall _ Start a new call on
|
||
* the given connection
|
||
*
|
||
* \par
|
||
* struct rx call *rx NewCall( IN struct rx connection *conn)
|
||
* \par Description
|
||
* Start a new Rx remote procedure call on the connection specified by the conn
|
||
* parameter. The existing call structures (up to RX MAXCALLS of them) are
|
||
* examined in order. The first non-active call encountered (i.e., either
|
||
* unused or whose call->state is RX STATE DALLY) will be appropriated and
|
||
* reset if necessary. If all call structures are in active use, the RX CONN
|
||
* MAKECALL WAITING flag is set in the conn->flags field, and the thread
|
||
* handling this request will sleep until a call structure comes free. Once a
|
||
* call structure has been reserved, the keep-alive protocol is enabled for it.
|
||
* \par
|
||
* The state of the given connection determines the detailed behavior of the
|
||
* function. The conn->timeout field specifies the absolute upper limit of the
|
||
* number of seconds this particular call may be in operation. After this time
|
||
* interval, calls to such routines as rx SendData() or rx ReadData() will fail
|
||
* with an RX CALL TIMEOUT indication.
|
||
* \par Error Codes
|
||
* --- A pointer to an initialized Rx call is always returned, unless osi
|
||
* Panic() is called due to memory allocation failure.
|
||
*
|
||
* \subsection sec5-6-6 Section 5.6.6: rx EndCall _ Terminate the given
|
||
* call
|
||
*
|
||
* \par
|
||
* int rx EndCall(
|
||
* \param IN struct rx call *call,
|
||
* \param IN long rc
|
||
* \n )
|
||
* \par Description
|
||
* Indicate that the Rx call described by the structure located at call is
|
||
* finished, possibly prematurely. The value passed in the rc parameter is
|
||
* returned to the peer, if appropriate. The final error code from processing
|
||
* the call will be returned as rx EndCall()'s value. The given call's state
|
||
* will be set to RX STATE DALLY, and threads waiting to establish a new call
|
||
* on this connection are signalled (see the description of the rx NewCall() in
|
||
* Section 5.6.5).
|
||
* \par Error Codes
|
||
* -1 Unspecified error has occurred.
|
||
*
|
||
* \subsection sec5-6-7 Section 5.6.7: rx StartServer _ Activate installed
|
||
* rx service(s)
|
||
*
|
||
* \par
|
||
* void rx StartServer( IN int donateMe)
|
||
* \par Description
|
||
* This function starts server threads in support of the Rx services installed
|
||
* via calls to rx NewService() (see Section 5.6.3). This routine first
|
||
* computes the number of server threads it must create, governed by the
|
||
* minProcs and maxProcs fields in the installed service descriptors. The
|
||
* minProcs field specifies the minimum number of threads that are guaranteed
|
||
* to be concurrently available to the given service. The maxProcs field
|
||
* specifies the maximum number of threads that may ever be concurrently
|
||
* assigned to the particular service, if idle threads are available. Using
|
||
* this information, rx StartServer() computes the correct overall number of
|
||
* threads as follows: For each installed service, minProcs threads will be
|
||
* created, enforcing the minimality guarantee. Calculate the maximum
|
||
* difference between the maxProcs and minProcs fields for each service, and
|
||
* create this many additional server threads, enforcing the maximality
|
||
* guarantee.
|
||
* \par
|
||
* If the value placed in the donateMe argument is zero, then rx StartServer()
|
||
* will simply return after performing as described above. Otherwise, the
|
||
* thread making the rx StartServer() call will itself begin executing the
|
||
* server thread loop. In this case, the rx StartServer() call will never
|
||
* return.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \subsection sec5-6-8 Section 5.6.8: rx PrintStats -- Print basic
|
||
* statistics to a file
|
||
*
|
||
* \par
|
||
* void rx PrintStats( IN FILE *file)
|
||
* \par Description
|
||
* Prints Rx statistics (basically the contents of the struct rx stats holding
|
||
* the statistics for the Rx facility) to the open file descriptor identified
|
||
* by file. The output is ASCII text, and is intended for human consumption.
|
||
* \note This function is available only if the Rx package has been compiled
|
||
* with the RXDEBUG flag.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \subsection sec5-6-9 Section 5.6.9: rx PrintPeerStats _ Print peer
|
||
* statistics to a file
|
||
* \par
|
||
* void rx PrintPeerStats( IN FILE *file, IN struct rx peer *peer)
|
||
* \par Description
|
||
* Prints the Rx peer statistics found in peer to the open file descriptor
|
||
* identified by file. The output is in normal ASCII text, and is intended for
|
||
* human consumption.
|
||
* \note This function is available only if the Rx package has been compiled
|
||
* with the RXDEBUG flag.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \subsection sec5-6-10 Section 5.6.10: rx finalize _ Shut down Rx
|
||
* gracefully
|
||
*
|
||
* \par
|
||
* void rx finalize()
|
||
* \par Description
|
||
* This routine may be used to shut down the Rx facility for either server or
|
||
* client applications. All of the client connections will be gracefully
|
||
* garbage-collected after their active calls are cleaned up. The result of
|
||
* calling rx finalize() from a client program is that the server-side entity
|
||
* will be explicitly advised that the client has terminated. This notification
|
||
* frees the server-side application from having to probe the client until its
|
||
* records eventually time out, and also allows it to free resources currently
|
||
* assigned to that client's support.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \subsection sec5-6-11 Section 5.6.11: Semi-Exported Operations
|
||
*
|
||
* \par
|
||
* As described in the introductory text in Section 5.6, entries in this
|
||
* lexically-visible set of Rx functions are not meant to be called directly by
|
||
* client applications, but rather are invoked by Rx macros called by users.
|
||
*
|
||
* \subsection sec5-6-12 Section 5.6.12: rx WriteProc _ Write data to an
|
||
* outgoing call
|
||
*
|
||
* \par
|
||
* int rx WriteProc( IN struct rx call *call, IN char *buf, IN int nbytes)
|
||
* \par Description
|
||
* Write nbytes of data from buffer buf into the Rx call identified by the call
|
||
* parameter. The value returned by rx WriteProc() reports the number of bytes
|
||
* actually written into the call. If zero is returned, then the rx Error()
|
||
* macro may be used to obtain the call status.
|
||
* \par
|
||
* This routine is called by the rx Write() macro, which is why it must be
|
||
* exported by the Rx facility.
|
||
* \par Error Codes
|
||
* Indicates error in the given Rx call; use the rx Error() macro to determine
|
||
* the call status.
|
||
*
|
||
* \subsection sec5-6-13 Section 5.6.13: rx ReadProc _ Read data from an
|
||
* incoming call
|
||
*
|
||
* \par
|
||
* int rx ReadProc( IN struct rx call *call, IN char *buf, IN int nbytes)
|
||
* \par Description
|
||
* Read up to nbytes of data from the Rx call identified by the call parameter
|
||
* into the buf buffer. The value returned by rx ReadProc() reports the number
|
||
* of bytes actually read from the call. If zero is returned, then the rx
|
||
* Error() macro may be used to obtain the call status.
|
||
* \par
|
||
* This routine is called by the rx Read() macro, which is why it must be
|
||
* exported by the Rx facility.
|
||
* \par Error Codes
|
||
* Indicates error in the given Rx call; use the rx Error() macro to determine
|
||
* the call status.
|
||
*
|
||
* \subsection sec5-6-1 Section 5.6.1: rx FlushWrite -- Flush buffered
|
||
* data on outgoing call
|
||
*
|
||
* \par
|
||
* void rx FlushWrite( IN struct rx call *call)
|
||
* \par Description
|
||
* Flush any buffered data on the given Rx call to the stream. If the call is
|
||
* taking place on a server connection, the call->mode is set to RX MODE EOF.
|
||
* If the call is taking place on a client connection, the call->mode is set to
|
||
* RX MODE RECEIVING.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \subsection sec5-6-15 Section 5.6.15: rx SetArrivalProc _ Set function
|
||
* to invoke upon call packet arrival
|
||
*
|
||
* \par
|
||
* void rx SetArrivalProc( IN struct rx call *call, IN VOID (*proc)(), IN VOID
|
||
* *handle, IN VOID *arg)
|
||
* \par Description
|
||
* Establish a procedure to be called when a packet arrives for a call. This
|
||
* routine will be called at most once after each call, and will also be called
|
||
* if there is an error condition on the call or the call is complete. The rx
|
||
* SetArrivalProc() function is used by multicast Rx routines to build a
|
||
* selection function that determines which of several calls is likely to be a
|
||
* good one to read from. The implementor's comments in the Rx code state that,
|
||
* due to the current implementation, it is probably only reasonable to use rx
|
||
* SetArrivalProc() immediately after an rx NewCall(), and to only use it once.
|
||
* \par Error Codes
|
||
* ---None.
|
||
*
|
||
* \page chap6 Chapter 6 -- Example Server and Client
|
||
*
|
||
* \section sec6-1 Section 6.1: Introduction
|
||
*
|
||
* \par
|
||
* This chapter provides a sample program showing the use of Rx. Specifically,
|
||
* the rxdemo application, with all its support files, is documented and
|
||
* examined. The goal is to provide the reader with a fully-developed and
|
||
* operational program illustrating the use of both regular Rx remote procedure
|
||
* calls and streamed RPCs. The full text of the rxdemo application is
|
||
* reproduced in the sections below, along with additional commentary.
|
||
* \par
|
||
* Readers wishing to directly experiment with this example Rx application are
|
||
* encouraged to examine the on-line version of rxdemo. Since it is a program
|
||
* of general interest, it has been installed in the usr/contrib tree in the
|
||
* grand.central.org cell. This area contains user-contributed software for the
|
||
* entire AFS community. At the top of this tree is the
|
||
* /afs/grand.central.org/darpa/usr/contrib directory. Both the server-side and
|
||
* client-side rxdemo binaries (rxdemo server and rxdemo client, respectively)
|
||
* may be found in the bin subdirectory. The actual sources reside in the
|
||
* .site/grand.central.org/rxdemo/src subdirectory.
|
||
* \par
|
||
* The rxdemo code is composed of two classes of files, namely those written by
|
||
* a human programmer and those generated from the human-written code by the
|
||
* Rxgen tool. Included in the first group of files are:
|
||
* \li rxdemo.xg This is the RPC interface definition file, providing
|
||
* high-level definitions of the supported calls.
|
||
* \li rxdemo client.c: This is the rxdemo client program, calling upon the
|
||
* associated server to perform operations defined by rxdemo.xg.
|
||
* \li rxdemo server.c: This is the rxdemo server program, implementing the
|
||
* operations promised in rxdemo.xg.
|
||
* \li Makefile: This is the file that directs the compilation and
|
||
* installation of the rxdemo code.
|
||
* \par
|
||
* The class of automatically-generated files includes the following items:
|
||
* \li rxdemo.h: This header file contains the set of constant definitions
|
||
* present in rxdemo.xg, along with information on the RPC opcodes defined for
|
||
* this Rx service.
|
||
* \li rxdemo.cs.c: This client-side stub file performs all the marshalling and
|
||
* unmarshalling of the arguments for the RPC routines defined in rxdemo.xg.
|
||
* \li rxdemo.ss.c: This stub file similarly defines all the marshalling and
|
||
* unmarshalling of arguments for the server side of the RPCs, invokes the
|
||
* routines defined within rxdemo server.c to implement the calls, and also
|
||
* provides the dispatcher function.
|
||
* \li rxdemo.xdr.c: This module defines the routines required to convert
|
||
* complex user-defined data structures appearing as arguments to the Rx RPC
|
||
* calls exported by rxdemo.xg into network byte order, so that correct
|
||
* communication is guaranteed between clients and server with different memory
|
||
* organizations.
|
||
* \par
|
||
* The chapter concludes with a section containing sample output from running
|
||
* the rxdemo server and client programs.
|
||
*
|
||
* \section sec6-2 Section 6.2: Human-Generated files
|
||
*
|
||
* \par
|
||
* The rxdemo application is based on the four human-authored files described
|
||
* in this section. They provide the basis for the construction of the full set
|
||
* of modules needed to implement the specified Rx service.
|
||
*
|
||
* \subsection sec6-2-1 Section 6.2.1: Interface file: rxdemo.xg
|
||
*
|
||
* \par
|
||
* This file serves as the RPC interface definition file for this application.
|
||
* It defines various constants, including the Rx service port to use and the
|
||
* index of the null security object (no encryption is used by rxdemo). It
|
||
* defines the RXDEMO MAX and RXDEMO MIN constants, which will be used by the
|
||
* server as the upper and lower bounds on the number of Rx listener threads to
|
||
* run. It also defines the set of error codes exported by this facility.
|
||
* finally, it provides the RPC function declarations, namely Add() and
|
||
* Getfile(). Note that when building the actual function definitions, Rxgen
|
||
* will prepend the value of the package line in this file, namely "RXDEMO ",
|
||
* to the function declarations. Thus, the generated functions become RXDEMO
|
||
* Add() and RXDEMO Getfile(), respectively. Note the use of the split keyword
|
||
* in the RXDEMO Getfile() declaration, which specifies that this is a streamed
|
||
* call, and actually generates two client-side stub routines (see Section
|
||
* 6.3.1).
|
||
*
|
||
* \code
|
||
* /*=======================================================================
|
||
* * Interface for an example Rx server/client application, using both * *
|
||
* standard and streamed calls. * ** * Edward R. Zayas * * Transarc
|
||
* Corporation * ** ** * The United States Government has rights in this
|
||
* work pursuant * * to contract no. MDA972-90-C-0036 between the United
|
||
* States Defense * * Advanced Research Projects Agency and Transarc
|
||
* Corporation. * ** * (C) Copyright 1991 Transarc Corporation * ** *
|
||
* Redistribution and use in source and binary forms are permitted *
|
||
* provided that: (1) source distributions retain this entire copy- * *
|
||
* right notice and comment, and (2) distributions including binaries * *
|
||
* display the following acknowledgement: * ** * ''This product includes
|
||
* software developed by Transarc * * Corporation and its contributors'' *
|
||
* ** * in the documentation or other materials mentioning features or * *
|
||
* use of this software. Neither the name of Transarc nor the names * * of
|
||
* its contributors may be used to endorse or promote products * * derived
|
||
* from this software without specific prior written * * permission. * **
|
||
* * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED *
|
||
* * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF *
|
||
* * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
* =======================================================================*/
|
||
*
|
||
* package RXDEMO_
|
||
* %#include <rx/rx.h>
|
||
* %#include <rx/rx_null.h>
|
||
* %#define RXDEMO_SERVER_PORT 8000 /* Service port to advertise */
|
||
* %#define RXDEMO_SERVICE_PORT 0 /* User server's port */
|
||
* %#define RXDEMO_SERVICE_ID 4 /* Service ID */
|
||
* %#define RXDEMO_NULL_SECOBJ_IDX 0 /* Index of null security object */
|
||
*
|
||
* /* Maximum number of requests that will be handled by this service
|
||
* * simultaneously. This number will be guaranteed to execute in
|
||
* * parallel if other service's results are being processed. */
|
||
*
|
||
* %#define RXDEMO_MAX 3
|
||
*
|
||
* /* Minimum number of requests that are guaranteed to be
|
||
* * handled simultaneously. */
|
||
*
|
||
* %#define RXDEMO_MIN 2
|
||
*
|
||
* /* Index of the "null" security class in the sample service. */
|
||
*
|
||
* %#define RXDEMO_NULL 0
|
||
*
|
||
* /* Maximum number of characters in a file name (for demo purposes). */
|
||
*
|
||
* %#define RXDEMO_NAME_MAX_CHARS 64
|
||
*
|
||
* /* Define the max number of bytes to transfer at one shot. */
|
||
*
|
||
* %#define RXDEMO_BUFF_BYTES 512
|
||
*
|
||
* /* Values returned by the RXDEMO_Getfile() call.
|
||
* * RXDEMO_CODE_SUCCESS : Everything went fine.
|
||
* * RXDEMO_CODE_CANT_OPEN : Can't open named file.
|
||
* * RXDEMO_CODE_CANT_STAT : Can't stat open file.
|
||
* * RXDEMO_CODE_CANT_READ : Error reading the open file.
|
||
* * RXDEMO_CODE_WRITE_ERROR : Error writing the open file. */
|
||
*
|
||
* /* ------------Interface calls defined for this service ----------- */
|
||
* %#define RXDEMO_CODE_SUCCESS 0
|
||
* %#define RXDEMO_CODE_CANT_OPEN 1
|
||
* %#define RXDEMO_CODE_CANT_STAT 2
|
||
* %#define RXDEMO_CODE_CANT_READ 3
|
||
* %#define RXDEMO_CODE_WRITE_ERROR 4
|
||
* /* -------------------------------------------------------------------
|
||
* * RXDEMO_Add *
|
||
* *
|
||
* * Summary:
|
||
* * Add the two numbers provided and return the result. *
|
||
* * Parameters:
|
||
* * int a_first : first operand.
|
||
* * int a_second : Second operand.
|
||
* * int *a_result : Sum of the above. *
|
||
* * Side effects: None.
|
||
* *-------------------------------------------------------------------- */
|
||
*
|
||
* Add(IN int a, int b, OUT int *result) = 1;
|
||
* /*-------------------------------------------------------------------
|
||
* * RXDEMO_Getfile *
|
||
* * Summary:
|
||
* * Return the contents of the named file in the server's environment.
|
||
* * Parameters:
|
||
* * STRING a_nameToRead : Name of the file whose contents are to be
|
||
* * fetched.
|
||
* * int *a_result : Set to the result of opening and reading the file
|
||
* * on the server side. *
|
||
* * Side effects: None.
|
||
* *-------------------------------------------------------------------- */
|
||
*
|
||
* Getfile(IN string a_nameToRead<RXDEMO_NAME_MAX_CHARS>, OUT int *a_result)
|
||
* split = 2;
|
||
* \endcode
|
||
*
|
||
* \subsection sec6-2-2 Section 6.2.2: Client Program: rxdemo client.c
|
||
*
|
||
* \par
|
||
* The rxdemo client program, rxdemo client, calls upon the associated server
|
||
* to perform operations defined by rxdemo.xg. After its header, it defines a
|
||
* private GetIPAddress() utility routine, which given a character string host
|
||
* name will return its IP address.
|
||
*
|
||
* \code
|
||
* /*=======================================================================
|
||
* % Client side of an example Rx application, using both standard and % %
|
||
* streamed calls. % %% % Edward R. Zayas % % Transarc Corporation % %%
|
||
* %% % The United States Government has rights in this work pursuant % %
|
||
* to contract no. MDA972-90-C-0036 between the United States Defense % %
|
||
* Advanced Research Projects Agency and Transarc Corporation. % %% % (C)
|
||
* Copyright 1991 Transarc Corporation % %% % Redistribution and use in source
|
||
* and binary forms are permitted % % provided that: (1) source distributions
|
||
* retain this entire copy- % % right notice and comment, and (2) distributions
|
||
* including binaries % % display the following acknowledgement: % %% %
|
||
* ''This product includes software developed by Transarc % % Corporation and
|
||
* its contributors'' % %% % in the documentation or other materials mentioning
|
||
* features or % % use of this software. Neither the name of Transarc nor the
|
||
* names % % of its contributors may be used to endorse or promote products % %
|
||
* derived from this software without specific prior written % % permission.
|
||
* % %% % THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||
* % % WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF % %
|
||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
* % %=======================================================================
|
||
* */
|
||
*
|
||
* #include <sys/types.h>
|
||
* #include <netdb.h>
|
||
* #include <stdio.h>
|
||
* #include "rxdemo.h"
|
||
* static char pn[] = "rxdemo"; /* Program name */
|
||
* static u_long GetIpAddress(a_hostName) char *a_hostName;
|
||
* { /* GetIPAddress */
|
||
* static char rn[] = "GetIPAddress"; /* Routine name */
|
||
* struct hostent *hostEntP; /* Ptr to host descriptor */
|
||
* u_long hostIPAddr; /* Host IP address */
|
||
* hostEntP = gethostbyname(a_hostName);
|
||
* if (hostEntP == (struct hostent *)0) {
|
||
* printf("[%s:%s] Host '%s' not found\n",
|
||
* pn, rn, a_hostName);
|
||
* exit(1);
|
||
* }
|
||
* if (hostEntP->h_length != sizeof(u_long)) {
|
||
* printf("[%s:%s] Wrong host address length (%d bytes instead of
|
||
* %d)",
|
||
* pn, rn, hostEntP->h_length, sizeof(u_long));
|
||
* exit(1);
|
||
* }
|
||
* memcpy(&hostIPAddr, hostEntP->h_addr, sizeof(hostIPAddr));
|
||
* return(hostIPAddr);
|
||
* } /* GetIpAddress */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The main program section of the client code, after handling its command line
|
||
* arguments, starts off by initializing the Rx facility.
|
||
*
|
||
* \code
|
||
* main(argc, argv)
|
||
* int argc;
|
||
* char **argv;
|
||
* { /* Main */
|
||
* struct rx_connection *rxConnP; /* Ptr to server connection */
|
||
* struct rx_call *rxCallP; /* Ptr to Rx call descriptor */
|
||
* u_long hostIPAddr; /* IP address of chosen host */
|
||
* int demoUDPPort; /* UDP port of Rx service */
|
||
* struct rx_securityClass *nullSecObjP; /* Ptr to null security object */
|
||
* int operand1, operand2; /* Numbers to add int sum; Their sum */
|
||
* int code; /* Return code */
|
||
* char fileName[64]; /* Buffer for desired file's name */
|
||
* long fileDataBytes; /* Num bytes in file to get */
|
||
* char buff[RXDEMO_BUFF_BYTES+1]; /* Read buffer */
|
||
* int currBytesToRead; /* Num bytes to read in one iteration */
|
||
* int maxBytesToRead; /* Max bytes to read in one iteration */
|
||
* int bytesReallyRead; /* Num bytes read off Rx stream */
|
||
* int getResults; /* Results of the file fetch */
|
||
* printf("\n%s: Example Rx client process\n\n", pn);
|
||
* if ((argc < 2) || (argc > 3)) {
|
||
* printf("Usage: rxdemo <HostName> [PortToUse]");
|
||
* exit(1);
|
||
* }
|
||
* hostIPAddr = GetIpAddress(argv[1]);
|
||
* if (argc > 2)
|
||
* demoUDPPort = atoi(argv[2]);
|
||
* else
|
||
* demoUDPPort = RXDEMO_SERVER_PORT;
|
||
* /* Initialize the Rx facility. */
|
||
* code = rx_Init(htons(demoUDPPort));
|
||
* if (code) {
|
||
* printf("** Error calling rx_Init(); code is %d\n", code);
|
||
* exit(1);
|
||
* }
|
||
* /* Create a client-side null security object. */
|
||
* nullSecObjP = rxnull_NewClientSecurityObject();
|
||
* if (nullSecObjP == (struct rx_securityClass *)0) {
|
||
* printf("%s: Can't create a null client-side security
|
||
* object!\n", pn);
|
||
* exit(1);
|
||
* }
|
||
* /* Set up a connection to the desired Rx service, telling it to use
|
||
* * the null security object we just created. */
|
||
* printf("Connecting to Rx server on '%s', IP address 0x%x, UDP port
|
||
* %d\n", argv[1], hostIPAddr, demoUDPPort);
|
||
* rxConnP = rx_NewConnection(hostIPAddr, RXDEMO_SERVER_PORT,
|
||
* RXDEMO_SERVICE_ID, nullSecObjP, RXDEMO_NULL_SECOBJ_IDX);
|
||
* if (rxConnP == (struct rx_connection *)0) {
|
||
* printf("rxdemo: Can't create connection to server!\n");
|
||
* exit(1);
|
||
* } else
|
||
* printf(" ---> Connected.\n");
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The rx Init() invocation initializes the Rx library and defines the desired
|
||
* service UDP port (in network byte order). The rxnull
|
||
* NewClientSecurityObject() call creates a client-side Rx security object that
|
||
* does not perform any authentication on Rx calls. Once a client
|
||
* authentication object is in hand, the program calls rx NewConnection(),
|
||
* specifying the host, UDP port, Rx service ID, and security information
|
||
* needed to establish contact with the rxdemo server entity that will be
|
||
* providing the service.
|
||
* \par
|
||
* With the Rx connection in place, the program may perform RPCs. The first one
|
||
* to be invoked is RXDEMO Add():
|
||
*
|
||
* \code
|
||
* /* Perform our first, simple remote procedure call. */
|
||
* operand1 = 1;
|
||
* operand2 = 2;
|
||
* printf("Asking server to add %d and %d: ", operand1, operand2);
|
||
* code = RXDEMO_Add(rxConnP, operand1, operand2, &sum);
|
||
* if (code) {
|
||
* printf(" // ** Error in the RXDEMO_Add RPC: code is %d\n", code);
|
||
* exit(1);
|
||
* }
|
||
* printf("Reported sum is %d\n", sum);
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The first argument to RXDEMO Add() is a pointer to the Rx connection
|
||
* established above. The client-side body of the RXDEMO Add() function was
|
||
* generated from the rxdemo.xg interface file, and resides in the rxdemo.cs.c
|
||
* file (see Section 6.3.1). It gives the appearance of being a normal C
|
||
* procedure call.
|
||
* \par
|
||
* The second RPC invocation involves the more complex, streamed RXDEMO
|
||
* Getfile() function. More of the internal Rx workings are exposed in this
|
||
* type of call. The first additional detail to consider is that we must
|
||
* manually create a new Rx call on the connection.
|
||
*
|
||
* \code
|
||
* /* Set up for our second, streamed procedure call. */
|
||
* printf("Name of file to read from server: ");
|
||
* scanf("%s", fileName);
|
||
* maxBytesToRead = RXDEMO_BUFF_BYTES;
|
||
* printf("Setting up an Rx call for RXDEMO_Getfile...");
|
||
* rxCallP = rx_NewCall(rxConnP);
|
||
* if (rxCallP == (struct rx_call *)0) {
|
||
* printf("** Can't create call\n");
|
||
* exit(1);
|
||
* }
|
||
* printf("done\n");
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Once the Rx call structure has been created, we may begin executing the call
|
||
* itself. Having been declared to be split in the interface file, Rxgen
|
||
* creates two function bodies for rxdemo Getfile() and places them in
|
||
* rxdemo.cs.c. The first, StartRXDEMO Getfile(), is responsible for
|
||
* marshalling the outgoing arguments and issuing the RPC. The second,
|
||
* EndRXDEMO Getfile(), takes care of unmarshalling the non-streamed OUT
|
||
* function parameters. The following code fragment illustrates how the RPC is
|
||
* started, using the StartRXDEMO Getfile() routine to pass the call parameters
|
||
* to the server.
|
||
*
|
||
* \code
|
||
* /* Sending IN parameters for the streamed call. */
|
||
* code = StartRXDEMO_Getfile(rxCallP, fileName);
|
||
* if (code) {
|
||
* printf("** Error calling StartRXDEMO_Getfile(); code is %d\n",
|
||
* code);
|
||
* exit(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Once the call parameters have been shipped, the server will commence
|
||
* delivering the "stream" data bytes back to the client on the given Rx call
|
||
* structure. The first longword to come back on the stream specifies the
|
||
* number of bytes to follow.
|
||
*
|
||
* \par
|
||
* Begin reading the data being shipped from the server in response to * our
|
||
* setup call. The first longword coming back on the Rx call is
|
||
* the number of bytes to follow. It appears in network byte order,
|
||
* so we have to fix it up before referring to it.
|
||
*
|
||
* \code
|
||
* bytesReallyRead = rx_Read(rxCallP, &fileDataBytes, sizeof(long));
|
||
* if (bytesReallyRead != sizeof(long)) {
|
||
* printf("** Only %d bytes read for file length; should have been %d\n",
|
||
* bytesReallyRead, sizeof(long));
|
||
* exit(1);
|
||
* }
|
||
* fileDataBytes = ntohl(fileDataBytes);
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Once the client knows how many bytes will be sent, it runs a loop in which
|
||
* it reads a buffer at a time from the Rx call stream, using rx Read() to
|
||
* accomplish this. In this application, all that is done with each
|
||
* newly-acquired buffer of information is printing it out.
|
||
*
|
||
* \code
|
||
* /* Read the file bytes via the Rx call, a buffer at a time. */
|
||
* printf("[file contents (%d bytes) fetched over the Rx call appear
|
||
* below]\n\n", fileDataBytes);
|
||
* while (fileDataBytes > 0)
|
||
* {
|
||
* currBytesToRead = (fileDataBytes > maxBytesToRead ? maxBytesToRead :
|
||
* fileDataBytes);
|
||
* bytesReallyRead = rx_Read(rxCallP, buff, currBytesToRead);
|
||
* if (bytesReallyRead != currBytesToRead)
|
||
* {
|
||
* printf("\nExpecting %d bytes on this read, got %d instead\n",
|
||
* currBytesToRead, bytesReallyRead);
|
||
* exit(1);
|
||
* }
|
||
* /* Null-terminate the chunk before printing it. */
|
||
* buff[currBytesToRead] = 0;
|
||
* printf("%s", buff);
|
||
* /* Adjust the number of bytes left to read. */
|
||
* fileDataBytes -= currBytesToRead;
|
||
* } /* Read one bufferful of the file */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* After this loop terminates, the Rx stream has been drained of all data. The
|
||
* Rx call is concluded by invoking the second of the two
|
||
* automatically-generated functions, EndRXDEMO Getfile(), which retrieves the
|
||
* call's OUT parameter from the server.
|
||
*
|
||
* \code
|
||
* /* finish off the Rx call, getting the OUT parameters. */
|
||
* printf("\n\n[End of file data]\n");
|
||
* code = EndRXDEMO_Getfile(rxCallP, &getResults);
|
||
* if (code)
|
||
* {
|
||
* printf("** Error getting file transfer results; code is %d\n",
|
||
* code);
|
||
* exit(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* With both normal and streamed Rx calls accomplished, the client demo code
|
||
* concludes by terminating the Rx call it set up earlier. With that done, the
|
||
* client exits.
|
||
*
|
||
* \code
|
||
* /* finish off the Rx call. */
|
||
* code = rx_EndCall(rxCallP, code);
|
||
* if (code)
|
||
* printf("Error in calling rx_EndCall(); code is %d\n", code);
|
||
*
|
||
* printf("\n\nrxdemo complete.\n");
|
||
* \endcode
|
||
*
|
||
* \subsection sec6-2-3 Server Program: rxdemo server.c
|
||
*
|
||
* \par
|
||
* The rxdemo server program, rxdemo server, implements the operations promised
|
||
* in the rxdemo.xg interface file.
|
||
* \par
|
||
* After the initial header, the external function RXDEMO ExecuteRequest() is
|
||
* declared. The RXDEMO ExecuteRequest() function is generated automatically by
|
||
* rxgen from the interface file and deposited in rxdemo.ss.c. The main program
|
||
* listed below will associate this RXDEMO ExecuteRequest() routine with the Rx
|
||
* service to be instantiated.
|
||
*
|
||
* \code
|
||
* /*======================================================================
|
||
* % % Advanced Research Projects Agency and Transarc Corporation. % %% %
|
||
* (C) Copyright 1991 Transarc Corporation % %% % Redistribution and use in
|
||
* source and binary forms are permitted % % provided that: (1) source
|
||
* distributions retain this entire copy- % % right notice and comment, and
|
||
* (2) distributions including binaries % % display the following
|
||
* acknowledgement: % %% % ''This product includes software developed by
|
||
* Transarc % % Corporation and its contributors'' % %% % in the documentation
|
||
* or other materials mentioning features or % % use of this software. Neither
|
||
* the name of Transarc nor the names % % of its contributors may be used to
|
||
* endorse or promote products % % derived from this software without specific
|
||
* prior written % % permission. % %% % THIS SOFTWARE IS PROVIDED "AS IS" AND
|
||
* WITHOUT ANY EXPRESS OR IMPLIED % % WARRANTIES, INCLUDING, WITHOUT
|
||
* LIMITATION,
|
||
* THE IMPLIED WARRANTIES OF % % MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||
* PURPOSE. % %
|
||
* ====================================================================== */
|
||
*
|
||
* /* Server portion of the example RXDEMO application, using both %
|
||
* standard and streamed calls. % % Edward R. Zayas % Transarc Corporation %
|
||
* % % The United States Government has rights in this work pursuant %
|
||
* to contract no. MDA972-90-C-0036 between the United States Defense % */
|
||
*
|
||
* #include <sys/types.h>
|
||
* #include <sys/stat.h>
|
||
* #include <sys/file.h>
|
||
* #include <netdb.h>
|
||
* #include <stdio.h>
|
||
* #include "rxdemo.h"
|
||
* #define N_SECURITY_OBJECTS 1
|
||
* extern RXDEMO_ExecuteRequest();
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* After choosing either the default or user-specified UDP port on which the Rx
|
||
* service will be established, rx Init() is called to set up the library.
|
||
*
|
||
* \code
|
||
* main(argc, argv)
|
||
* int argc;
|
||
* char **argv;
|
||
* { /* Main */
|
||
* static char pn[] = "rxdemo_server"; /* Program name */
|
||
* struct rx_securityClass
|
||
* (securityObjects[1]); /* Security objs */
|
||
* struct rx_service *rxServiceP; /* Ptr to Rx service descriptor */
|
||
* struct rx_call *rxCallP; /* Ptr to Rx call descriptor */
|
||
* int demoUDPPort; /* UDP port of Rx service */
|
||
* int fd; /* file descriptor */
|
||
* int code; /* Return code */
|
||
* printf("\n%s: Example Rx server process\n\n", pn);
|
||
* if (argc >2) {
|
||
* printf("Usage: rxdemo [PortToUse]");
|
||
* exit(1);
|
||
* }
|
||
* if (argc > 1)
|
||
* demoUDPPort = atoi(argv[1]);
|
||
* else
|
||
* demoUDPPort = RXDEMO_SERVER_PORT;
|
||
*
|
||
* /* Initialize the Rx facility, telling it the UDP port number this
|
||
* * server will use for its single service. */
|
||
*
|
||
* printf("Listening on UDP port %d\n", demoUDPPort);
|
||
* code = rx_Init(demoUDPPort);
|
||
* if (code) {
|
||
* printf("** Error calling rx_Init(); code is %d\n", code);
|
||
* exit(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* A security object specific to the server side of an Rx conversation is
|
||
* created in the next code fragment. As with the client side of the code, a
|
||
* "null" server security object, namely one that does not perform any
|
||
* authentication at all, is constructed with the rxnull
|
||
* NewServerSecurityObject() function.
|
||
*
|
||
* \code
|
||
* /* Create a single server-side security object. In this case, the
|
||
* * null security object (for unauthenticated connections) will be used
|
||
* * to control security on connections made to this server. */
|
||
*
|
||
* securityObjects[RXDEMO_NULL_SECOBJ_IDX] =
|
||
* rxnull_NewServerSecurityObject();
|
||
* if (securityObjects[RXDEMO_NULL_SECOBJ_IDX] == (struct rx_securityClass
|
||
* *) 0) {
|
||
* printf("** Can't create server-side security object\n");
|
||
* exit(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The rxdemo server program is now in a position to create the desired Rx
|
||
* service, primed to recognize exactly those interface calls defined in
|
||
* rxdemo.xg. This is accomplished by calling the rx NewService() library
|
||
* routine, passing it the security object created above and the generated Rx
|
||
* dispatcher routine.
|
||
*
|
||
* \code
|
||
* /* Instantiate a single sample service. The rxgen-generated procedure
|
||
* * called to dispatch requests is passed in (RXDEMO_ExecuteRequest). */
|
||
*
|
||
* rxServiceP = rx_NewService( 0,
|
||
* RXDEMO_SERVICE_ID,
|
||
* "rxdemo",
|
||
* securityObjects,
|
||
* 1,
|
||
* RXDEMO_ExecuteRequest
|
||
* );
|
||
* if (rxServiceP == (struct rx_service *) 0) {
|
||
* printf("** Can't create Rx service\n");
|
||
* exit(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The final step in this main routine is to activate servicing of calls to the
|
||
* exported Rx interface. Specifically, the proper number of threads are
|
||
* created to handle incoming interface calls. Since we are passing a non-zero
|
||
* argument to the rx StartServer() call, the main program will itself begin
|
||
* executing the server thread loop, never returning from the rx StartServer()
|
||
* call. The print statement afterwards should never be executed, and its
|
||
* presence represents some level of paranoia, useful for debugging
|
||
* malfunctioning thread packages.
|
||
*
|
||
* \code
|
||
* /* Start up Rx services, donating this thread to the server pool. */
|
||
* rx_StartServer(1);
|
||
* /* We should never return from the previous call. */
|
||
* printf("** rx_StartServer() returned!!\n"); exit(1);
|
||
* } /* Main */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Following the main procedure are the functions called by the
|
||
* automatically-generated routines in the rxdemo.ss.c module to implement the
|
||
* specific routines defined in the Rx interface.
|
||
* \par
|
||
* The first to be defined is the RXDEMO Add() function. The arguments for this
|
||
* routine are exactly as they appear in the interface definition, with the
|
||
* exception of the very first. The a rxCallP parameter is a pointer to the Rx
|
||
* structure describing the call on which this function was activated. All
|
||
* user-supplied routines implementing an interface function are required to
|
||
* have a pointer to this structure as their first parameter. Other than
|
||
* printing out the fact that it has been called and which operands it
|
||
* received, all that RXDEMO Add() does is compute the sum and place it in the
|
||
* output parameter.
|
||
* \par
|
||
* Since RXDEMO Add() is a non-streamed function, with all data travelling
|
||
* through the set of parameters, this is all that needs to be done. To mark a
|
||
* successful completion, RXDEMO Add() returns zero, which is passed all the
|
||
* way through to the RPC's client.
|
||
*
|
||
* \code
|
||
* int RXDEMO_Add(a_rxCallP, a_operand1, a_operand2, a_resultP)
|
||
* struct rx_call *a_rxCallP;
|
||
* int a_operand1, a_operand2;
|
||
* int *a_resultP;
|
||
* { /* RXDEMO_Add */
|
||
* printf("\t[Handling call to RXDEMO_Add(%d, %d)]\n",
|
||
* a_operand1, a_operand2);
|
||
* *a_resultP = a_operand1 + a_operand2;
|
||
* return(0);
|
||
* } /* RXDEMO_Add */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The next and final interface routine defined in this file is RXDEMO
|
||
* Getfile(). Declared as a split function in the interface file, RXDEMO
|
||
* Getfile() is an example of a streamed Rx call. As with RXDEMO Add(), the
|
||
* initial parameter is required to be a pointer to the Rx call structure with
|
||
* which this routine is associated, Similarly, the other parameters appear
|
||
* exactly as in the interface definition, and are handled identically.
|
||
* \par
|
||
* The difference between RXDEMO Add() and RXDEMO Getfile() is in the use of
|
||
* the rx Write() library routine by RXDEMO Getfile() to feed the desired
|
||
* file's data directly into the Rx call stream. This is an example of the use
|
||
* of the a rxCallP argument, providing all the information necessary to
|
||
* support the rx Write() activity.
|
||
* \par
|
||
* The RXDEMO Getfile() function begins by printing out the fact that it's been
|
||
* called and the name of the requested file. It will then attempt to open the
|
||
* requested file and stat it to determine its size.
|
||
*
|
||
* \code
|
||
* int RXDEMO_Getfile(a_rxCallP, a_nameToRead, a_resultP)
|
||
* struct rx_call *a_rxCallP;
|
||
* char *a_nameToRead;
|
||
* int *a_resultP;
|
||
* { /* RXDEMO_Getfile */
|
||
* struct stat fileStat; /* Stat structure for file */
|
||
* long fileBytes; /* Size of file in bytes */
|
||
* long nbofileBytes; /* file bytes in network byte order */
|
||
* int code; /* Return code */
|
||
* int bytesReallyWritten; /* Bytes written on Rx channel */
|
||
* int bytesToSend; /* Num bytes to read & send this time */
|
||
* int maxBytesToSend; /* Max num bytes to read & send ever */
|
||
* int bytesRead; /* Num bytes read from file */
|
||
* char buff[RXDEMO_BUFF_BYTES+1]; /* Read buffer */
|
||
* int fd; /* file descriptor */
|
||
* maxBytesToSend = RXDEMO_BUFF_BYTES;
|
||
* printf("\t[Handling call to RXDEMO_Getfile(%s)]\n", a_nameToRead);
|
||
* fd = open(a_nameToRead, O_RDONLY, 0444);
|
||
* if (fd <0) {
|
||
* printf("\t\t[**Can't open file '%s']\n", a_nameToRead);
|
||
* *a_resultP = RXDEMO_CODE_CANT_OPEN;
|
||
* return(1);
|
||
* } else
|
||
* printf("\t\t[file opened]\n");
|
||
* /* Stat the file to find out how big it is. */
|
||
* code = fstat(fd, &fileStat);
|
||
* if (code) {
|
||
* a_resultP = RXDEMO_CODE_CANT_STAT;
|
||
* printf("\t\t[file closed]\n");
|
||
* close(fd);
|
||
* return(1);
|
||
* }
|
||
* fileBytes = fileStat.st_size;
|
||
* printf("\t\t[file has %d bytes]\n", fileBytes);
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Only standard unix operations have been used so far. Now that the file is
|
||
* open, we must first feed the size of the file, in bytes, to the Rx call
|
||
* stream. With this information, the client code can then determine how many
|
||
* bytes will follow on the stream. As with all data that flows through an Rx
|
||
* stream, the longword containing the file size, in bytes, must be converted
|
||
* to network byte order before being sent. This insures that the recipient may
|
||
* properly interpret the streamed information, regardless of its memory
|
||
* architecture.
|
||
*
|
||
* \code
|
||
* nbofileBytes = htonl(fileBytes);
|
||
* /* Write out the size of the file to the Rx call. */
|
||
* bytesReallyWritten = rx_Write(a_rxCallP, &nbofileBytes, sizeof(long));
|
||
* if (bytesReallyWritten != sizeof(long)) {
|
||
* printf("** %d bytes written instead of %d for file length\n",
|
||
* bytesReallyWritten, sizeof(long));
|
||
* *a_resultP = RXDEMO_CODE_WRITE_ERROR;
|
||
* printf("\t\t[file closed]\n");
|
||
* close(fd);
|
||
* return(1);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Once the number of file bytes has been placed in the stream, the RXDEMO
|
||
* Getfile() routine runs a loop, reading a buffer's worth of the file and then
|
||
* inserting that buffer of file data into the Rx stream at each iteration.
|
||
* This loop executes until all of the file's bytes have been shipped. Notice
|
||
* there is no special end-of-file character or marker inserted into the
|
||
* stream.
|
||
* \par
|
||
* The body of the loop checks for both unix read() and rx Write errors. If
|
||
* there is a problem reading from the unix file into the transfer buffer, it
|
||
* is reflected back to the client by setting the error return parameter
|
||
* appropriately. Specifically, an individual unix read() operation could fail
|
||
* to return the desired number of bytes. Problems with rx Write() are handled
|
||
* similarly. All errors discovered in the loop result in the file being
|
||
* closed, and RXDEMO Getfile() exiting with a non-zero return value.
|
||
*
|
||
* \code
|
||
* /* Write out the contents of the file, one buffer at a time. */
|
||
* while (fileBytes > 0) {
|
||
* /* figure out the number of bytes to
|
||
* * read (and send) this time. */
|
||
* bytesToSend = (fileBytes > maxBytesToSend ?
|
||
* maxBytesToSend : fileBytes);
|
||
* bytesRead = read(fd, buff, bytesToSend);
|
||
* if (bytesRead != bytesToSend) {
|
||
* printf("Read %d instead of %d bytes from the file\n",
|
||
* bytesRead, bytesToSend);
|
||
* *a_resultP = RXDEMO_CODE_WRITE_ERROR;
|
||
* printf("\t\t[file closed]\n");
|
||
* close(fd);
|
||
* return(1);
|
||
* }
|
||
* /* Go ahead and send them. */
|
||
* bytesReallyWritten = rx_Write(a_rxCallP, buff, bytesToSend);
|
||
* if (bytesReallyWritten != bytesToSend) {
|
||
* printf("%d file bytes written instead of %d\n",
|
||
* bytesReallyWritten, bytesToSend);
|
||
* *a_resultP = RXDEMO_CODE_WRITE_ERROR;
|
||
* printf("\t\t[file closed]\n");
|
||
* close(fd);
|
||
* return(1);
|
||
* }
|
||
* /* Update the number of bytes left to go. */
|
||
* fileBytes -= bytesToSend;
|
||
* } /* Write out the file to our caller */
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* Once all of the file's bytes have been shipped to the remote client, all
|
||
* that remains to be done is to close the file and return successfully.
|
||
*
|
||
* \code
|
||
* /* Close the file, then return happily. */
|
||
* *a_resultP = RXDEMO_CODE_SUCCESS;
|
||
* printf("\t\t[file closed]\n");
|
||
* close(fd);
|
||
* return(0);
|
||
* } /* RXDEMO_Getfile */
|
||
* \endcode
|
||
*
|
||
* \subsection sec6-2-4 Section 6.2.4: Makefile
|
||
*
|
||
* \par
|
||
* This file directs the compilation and installation of the rxdemo code. It
|
||
* specifies the locations of libraries, include files, sources, and such tools
|
||
* as Rxgen and install, which strips symbol tables from executables and places
|
||
* them in their target directories. This Makefile demostrates cross-cell
|
||
* software development, with the rxdemo sources residing in the
|
||
* grand.central.org cell and the AFS include files and libraries accessed from
|
||
* their locations in the transarc.com cell.
|
||
* \par
|
||
* In order to produce and install the rxdemo server and rxdemo client
|
||
* binaries, the system target should be specified on the command line when
|
||
* invoking make:
|
||
* \code
|
||
* make system
|
||
* \endcode
|
||
* \par
|
||
* A note of caution is in order concerning generation of the rxdemo binaries.
|
||
* While tools exist that deposit the results of all compilations to other
|
||
* (architecture-specific) directories, and thus facilitate multiple
|
||
* simultaneous builds across a variety of machine architectures (e.g.,
|
||
* Transarc's washtool), the assumption is made here that compilations will
|
||
* take place directly in the directory containing all the rxdemo sources.
|
||
* Thus, a user will have to execute a make clean command to remove all
|
||
* machine-specific object, library, and executable files before compiling for
|
||
* a different architecture. Note, though, that the binaries are installed into
|
||
* a directory specifically reserved for the current machine type.
|
||
* Specifically, the final pathname component of the ${PROJ DIR}bin
|
||
* installation target is really a symbolic link to ${PROJ DIR}.bin/@sys.
|
||
* \par
|
||
* Two libraries are needed to support the rxdemo code. The first is obvious,
|
||
* namely the Rx librx.a library. The second is the lightweight thread package
|
||
* library, liblwp.a, which implements all the threading operations that must
|
||
* be performed. The include files are taken from the unix /usr/include
|
||
* directory, along with various AFS-specific directories. Note that for
|
||
* portability reasons, this Makefile only contains fully-qualified AFS
|
||
* pathnames and "standard" unix pathnames (such as /usr/include).
|
||
*
|
||
* \code
|
||
* /*#=======================================================================#
|
||
* # The United States Government has rights in this work pursuant # # to
|
||
* contract no. MDA972-90-C-0036 between the United States Defense # # Advanced
|
||
* Research Projects Agency and Transarc Corporation. # # # # (C) Copyright
|
||
* 1991
|
||
* Transarc Corporation # # # # Redistribution and use in source and binary
|
||
* forms
|
||
* are permitted # # provided that: (1) source distributions retain this entire
|
||
* copy-# # right notice and comment, and (2) distributions including binaries
|
||
* #
|
||
* # display the following acknowledgement: # # # # ''This product includes
|
||
* software developed by Transarc # # Corporation and its contributors'' # # #
|
||
* #
|
||
* in the documentation or other materials mentioning features or # # use of
|
||
* this
|
||
* software. Neither the name of Transarc nor the names # # of its contributors
|
||
* may be used to endorse or promote products # # derived from this software
|
||
* without specific prior written # # permission. # # # # THIS SOFTWARE IS
|
||
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED # # WARRANTIES,
|
||
* INCLUDING,
|
||
* WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # # MERCHANTABILITY AND
|
||
* FITNESS
|
||
* FOR A PARTICULAR PURPOSE. #
|
||
* #=======================================================================# */
|
||
*
|
||
* SHELL = /bin/sh
|
||
* TOOL_CELL = grand.central.org
|
||
* AFS_INCLIB_CELL = transarc.com
|
||
* USR_CONTRIB = /afs/${TOOL_CELL}/darpa/usr/contrib/
|
||
* PROJ_DIR = ${USR_CONTRIB}.site/grand.central.org/rxdemo/
|
||
* AFS_INCLIB_DIR = /afs/${AFS_INCLIB_CELL}/afs/dest/
|
||
* RXGEN = ${AFS_INCLIB_DIR}bin/rxgen
|
||
* INSTALL = ${AFS_INCLIB_DIR}bin/install
|
||
* LIBS = ${AFS_INCLIB_DIR}lib/librx.a \ ${AFS_INCLIB_DIR}lib/liblwp.a
|
||
* CFLAGS = -g \
|
||
* -I. \
|
||
* -I${AFS_INCLIB_DIR}include \
|
||
* -I${AFS_INCLIB_DIR}include/afs \
|
||
* -I${AFS_INCLIB_DIR} \
|
||
* -I/usr/include
|
||
*
|
||
* system: install
|
||
*
|
||
* install: all
|
||
* ${INSTALL} rxdemo_client
|
||
* ${PROJ_DIR}bin
|
||
* ${INSTALL} rxdemo_server
|
||
* ${PROJ_DIR}bin
|
||
*
|
||
* all: rxdemo_client rxdemo_server
|
||
*
|
||
* rxdemo_client: rxdemo_client.o ${LIBS} rxdemo.cs.o ${CC} ${CFLAGS}
|
||
* -o rxdemo_client rxdemo_client.o rxdemo.cs.o ${LIBS}
|
||
*
|
||
* rxdemo_server: rxdemo_server.o rxdemo.ss.o ${LIBS} ${CC} ${CFLAGS}
|
||
* -o rxdemo_server rxdemo_server.o rxdemo.ss.o ${LIBS}
|
||
*
|
||
* rxdemo_client.o: rxdemo.h
|
||
*
|
||
* rxdemo_server.o: rxdemo.h
|
||
*
|
||
* rxdemo.cs.c rxdemo.ss.c rxdemo.er.c rxdemo.h: rxdemo.xg rxgen rxdemo.xg
|
||
*
|
||
* clean: rm -f *.o rxdemo.cs.c rxdemo.ss.c rxdemo.xdr.c rxdemo.h \
|
||
* rxdemo_client rxdemo_server core
|
||
* \endcode
|
||
*
|
||
* \section sec6-3 Section 6.3: Computer-Generated files
|
||
*
|
||
* \par
|
||
* The four human-generated files described above provide all the information
|
||
* necessary to construct the full set of modules to support the rxdemo example
|
||
* application. This section describes those routines that are generated from
|
||
* the base set by Rxgen, filling out the code required to implement an Rx
|
||
* service.
|
||
*
|
||
* \subsection sec6-3-1 Client-Side Routines: rxdemo.cs.c
|
||
*
|
||
* \par
|
||
* The rxdemo client.c program, described in Section 6.2.2, calls the
|
||
* client-side stub routines contained in this module in order to make rxdemo
|
||
* RPCs. Basically, these client-side stubs are responsible for creating new Rx
|
||
* calls on the given connection parameter and then marshalling and
|
||
* unmarshalling the rest of the interface call parameters. The IN and INOUT
|
||
* arguments, namely those that are to be delivered to the server-side code
|
||
* implementing the call, must be packaged in network byte order and shipped
|
||
* along the given Rx call. The return parameters, namely those objects
|
||
* declared as INOUT and OUT, must be fetched from the server side of the
|
||
* associated Rx call, put back in host byte order, and inserted into the
|
||
* appropriate parameter variables.
|
||
* \par
|
||
* The first part of rxdemo.cs.c echoes the definitions appearing in the
|
||
* rxdemo.xg interface file, and also #includes another Rxgen-generated file,
|
||
* rxdemo.h.
|
||
*
|
||
* \code
|
||
* /*======================================================================%
|
||
* * % THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED %
|
||
* * % WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF %
|
||
* * % MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. %
|
||
* * %====================================================================== */
|
||
* /* Machine generated file --Do NOT edit */
|
||
*
|
||
* #include "rxdemo.h"
|
||
* #define RXDEMO_CODE_WRITE_ERROR 4
|
||
*
|
||
* #include <rx/rx.h>
|
||
* #include <rx/rx_null.h>
|
||
* #define RXDEMO_SERVER_PORT 8000 /* Service port to advertise */
|
||
* #define RXDEMO_SERVICE_PORT 0 /* User server's port */
|
||
* #define RXDEMO_SERVICE_ID 4 /* Service ID */
|
||
* #define RXDEMO_NULL_SECOBJ_IDX 0 /* Index of null security object */
|
||
* #define RXDEMO_MAX 3
|
||
* #define RXDEMO_MIN 2
|
||
* #define RXDEMO_NULL 0
|
||
* #define RXDEMO_NAME_MAX_CHARS 64
|
||
* #define RXDEMO_BUFF_BYTES 512
|
||
* #define RXDEMO_CODE_SUCCESS 0
|
||
* #define RXDEMO_CODE_CANT_OPEN 1
|
||
* #define RXDEMO_CODE_CANT_STAT 2
|
||
* #define RXDEMO_CODE_CANT_READ 3
|
||
* #define RXDEMO_CODE_WRITE_ERROR 4
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The next code fragment defines the client-side stub for the RXDEMO Add()
|
||
* routine, called by the rxdemo client program to execute the associated RPC.
|
||
*
|
||
* \code
|
||
* int RXDEMO_Add(z_conn, a, b, result) register struct rx_connection *z_conn;
|
||
* int a, b;
|
||
* int * result;
|
||
* {
|
||
* struct rx_call *z_call = rx_NewCall(z_conn);
|
||
* static int z_op = 1;
|
||
* int z_result;
|
||
* XDR z_xdrs;
|
||
* xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
|
||
* /* Marshal the arguments */
|
||
* if ((!xdr_int(&z_xdrs, &z_op))
|
||
* || (!xdr_int(&z_xdrs, &a))
|
||
* || (!xdr_int(&z_xdrs, &b))) {
|
||
* z_result = RXGEN_CC_MARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* /* Un-marshal the reply arguments */
|
||
* z_xdrs.x_op = XDR_DECODE;
|
||
* if ((!xdr_int(&z_xdrs, result))) {
|
||
* z_result = RXGEN_CC_UNMARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* z_result = RXGEN_SUCCESS;
|
||
* fail: return rx_EndCall(z_call, z_result);
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The very first operation performed by RXDEMO Add() occurs in the local
|
||
* variable declarations, where z call is set to point to the structure
|
||
* describing a newly-created Rx call on the given connection. An XDR
|
||
* structure, z xdrs, is then created for the given Rx call with xdrrx
|
||
* create(). This XDR object is used to deliver the proper arguments, in
|
||
* network byte order, to the matching server stub code. Three calls to xdr
|
||
* int() follow, which insert the appropriate Rx opcode and the two operands
|
||
* into the Rx call. With the IN arguments thus transmitted, RXDEMO Add()
|
||
* prepares to pull the value of the single OUT parameter. The z xdrs XDR
|
||
* structure, originally set to XDR ENCODE objects, is now reset to XDR DECODE
|
||
* to convert further items received into host byte order. Once the return
|
||
* parameter promised by the function is retrieved, RXDEMO Add() returns
|
||
* successfully.
|
||
* \par
|
||
* Should any failure occur in passing the parameters to and from the server
|
||
* side of the call, the branch to fail will invoke Rx EndCall(), which advises
|
||
* the server that the call has come to a premature end (see Section 5.6.6 for
|
||
* full details on rx EndCall() and the meaning of its return value).
|
||
* \par
|
||
* The next client-side stub appearing in this generated file handles the
|
||
* delivery of the IN parameters for StartRXDEMO Getfile(). It operates
|
||
* identically as the RXDEMO Add() stub routine in this respect, except that it
|
||
* does not attempt to retrieve the OUT parameter. Since this is a streamed
|
||
* call, the number of bytes that will be placed on the Rx stream cannot be
|
||
* determined at compile time, and must be handled explicitly by rxdemo
|
||
* client.c.
|
||
*
|
||
* \code
|
||
* int StartRXDEMO_Getfile(z_call, a_nameToRead)
|
||
* register struct rx_call *z_call;
|
||
* char * a_nameToRead;
|
||
* {
|
||
* static int z_op = 2;
|
||
* int z_result;
|
||
* XDR z_xdrs;
|
||
* xdrrx_create(&z_xdrs, z_call, XDR_ENCODE);
|
||
* /* Marshal the arguments */
|
||
* if ((!xdr_int(&z_xdrs, &z_op)) || (!xdr_string(&z_xdrs, &a_nameToRead,
|
||
* RXDEMO_NAME_MAX_CHARS))) {
|
||
* z_result = RXGEN_CC_MARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* z_result = RXGEN_SUCCESS;
|
||
* fail: return z_result;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The final stub routine appearing in this generated file, EndRXDEMO
|
||
* Getfile(), handles the case where rxdemo client.c has already successfully
|
||
* recovered the unbounded streamed data appearing on the call, and then simply
|
||
* has to fetch the OUT parameter. This routine behaves identially to the
|
||
* latter portion of RXDEMO Getfile().
|
||
*
|
||
* \code
|
||
* int EndRXDEMO_Getfile(z_call, a_result)
|
||
* register struct rx_call *z_call;
|
||
* int * a_result;
|
||
* {
|
||
* int z_result;
|
||
* XDR z_xdrs;
|
||
* /* Un-marshal the reply arguments */
|
||
* xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
|
||
* if ((!xdr_int(&z_xdrs, a_result))) {
|
||
* z_result = RXGEN_CC_UNMARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* z_result = RXGEN_SUCCESS; fail:
|
||
* return z_result;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec6-3-2 Server-Side Routines: rxdemo.ss.c
|
||
*
|
||
* \par
|
||
* This generated file provides the core components required to implement the
|
||
* server side of the rxdemo RPC service. Included in this file is the
|
||
* generated dispatcher routine, RXDEMO ExecuteRequest(), which the rx
|
||
* NewService() invocation in rxdemo server.c uses to construct the body of
|
||
* each listener thread's loop. Also included are the server-side stubs to
|
||
* handle marshalling and unmarshalling of parameters for each defined RPC call
|
||
* (i.e., RXDEMO Add() and RXDEMO Getfile()). These stubs are called by RXDEMO
|
||
* ExecuteRequest(). The routine to be called by RXDEMO ExecuteRequest()
|
||
* depends on the opcode received, which appears as the very first longword in
|
||
* the call data.
|
||
* \par
|
||
* As usual, the first fragment is copyright information followed by the body
|
||
* of the definitions from the interface file.
|
||
*
|
||
* \code
|
||
* /*======================================================================%
|
||
* % Edward R. Zayas % % Transarc Corporation % % % % % % The United States
|
||
* Government has rights in this work pursuant % % to contract no.
|
||
* MDA972-90-C-0036 between the United States Defense % % Advanced Research
|
||
* Projects Agency and Transarc Corporation. % % % % (C) Copyright 1991
|
||
* Transarc Corporation % % % % Redistribution and use in source and binary
|
||
* forms are permitted % % provided that: (1) source distributions retain
|
||
* this entire copy<70>% % right notice and comment, and (2) distributions
|
||
* including binaries %
|
||
* %====================================================================== */
|
||
* /* Machine generated file --Do NOT edit */
|
||
*
|
||
* #include "rxdemo.h"
|
||
* #include <rx/rx.h>
|
||
* #include <rx/rx_null.h>
|
||
* #define RXDEMO_SERVER_PORT 8000 /* Service port to advertise */
|
||
* #define RXDEMO_SERVICE_PORT 0 /* User server's port */
|
||
* #define RXDEMO_SERVICE_ID 4 /* Service ID */
|
||
* #define RXDEMO_NULL_SECOBJ_IDX 0 /* Index of null security object */
|
||
* #define RXDEMO_MAX 3
|
||
* #define RXDEMO_MIN 2
|
||
* #define RXDEMO_NULL 0
|
||
* #define RXDEMO_NAME_MAX_CHARS 64
|
||
* #define RXDEMO_BUFF_BYTES 512
|
||
* #define RXDEMO_CODE_SUCCESS 0
|
||
* #define RXDEMO_CODE_CANT_OPEN 1
|
||
* #define RXDEMO_CODE_CANT_STAT 2
|
||
* #define RXDEMO_CODE_CANT_READ 3
|
||
* #define RXDEMO_CODE_WRITE_ERROR 4
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* After this preamble, the first server-side stub appears. This RXDEMO Add()
|
||
* routine is basically the inverse of the RXDEMO Add() client-side stub
|
||
* defined in rxdemo.cs.c. Its job is to unmarshall the IN parameters for the
|
||
* call, invoke the "true" server-side RXDEMO Add() routine (defined in rxdemo
|
||
* server.c), and then package and ship the OUT parameter. Being so similar to
|
||
* the client-side RXDEMO Add(), no further discussion is offered here.
|
||
*
|
||
* \code
|
||
* long _RXDEMO_Add(z_call, z_xdrs)
|
||
* struct rx_call *z_call;
|
||
* XDR *z_xdrs;
|
||
* {
|
||
* long z_result;
|
||
* int a, b;
|
||
* int result;
|
||
* if ((!xdr_int(z_xdrs, &a)) || (!xdr_int(z_xdrs, &b)))
|
||
* {
|
||
* z_result = RXGEN_SS_UNMARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* z_result = RXDEMO_Add(z_call, a, b, &result);
|
||
* z_xdrs->x_op = XDR_ENCODE;
|
||
* if ((!xdr_int(z_xdrs, &result)))
|
||
* z_result = RXGEN_SS_MARSHAL;
|
||
* fail: return z_result;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The second server-side stub, RXDEMO Getfile(), appears next. It operates
|
||
* identically to RXDEMO Add(), first unmarshalling the IN arguments, then
|
||
* invoking the routine that actually performs the server-side work for the
|
||
* call, then finishing up by returning the OUT parameters.
|
||
*
|
||
* \code
|
||
* long _RXDEMO_Getfile(z_call, z_xdrs)
|
||
* struct rx_call *z_call;
|
||
* XDR *z_xdrs;
|
||
* {
|
||
* long z_result;
|
||
* char * a_nameToRead=(char *)0;
|
||
* int a_result;
|
||
* if ((!xdr_string(z_xdrs, &a_nameToRead, RXDEMO_NAME_MAX_CHARS))) {
|
||
* z_result = RXGEN_SS_UNMARSHAL;
|
||
* goto fail;
|
||
* }
|
||
* z_result = RXDEMO_Getfile(z_call, a_nameToRead, &a_result);
|
||
* z_xdrs->x_op = XDR_ENCODE;
|
||
* if ((!xdr_int(z_xdrs, &a_result)))
|
||
* z_result = RXGEN_SS_MARSHAL;
|
||
* fail: z_xdrs->x_op = XDR_FREE;
|
||
* if (!xdr_string(z_xdrs, &a_nameToRead, RXDEMO_NAME_MAX_CHARS))
|
||
* goto fail1;
|
||
* return z_result;
|
||
* fail1: return RXGEN_SS_XDRFREE;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The next portion of the automatically generated server-side module sets up
|
||
* the dispatcher routine for incoming Rx calls. The above stub routines are
|
||
* placed into an array in opcode order.
|
||
*
|
||
* \code
|
||
* long _RXDEMO_Add();
|
||
* long _RXDEMO_Getfile();
|
||
* static long (*StubProcsArray0[])() = {_RXDEMO_Add, _RXDEMO_Getfile};
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The dispatcher routine itself, RXDEMO ExecuteRequest, appears next. This is
|
||
* the function provided to the rx NewService() call in rxdemo server.c, and it
|
||
* is used as the body of each listener thread's service loop. When activated,
|
||
* it decodes the first longword in the given Rx call, which contains the
|
||
* opcode. It then dispatches the call based on this opcode, invoking the
|
||
* appropriate server-side stub as organized in the StubProcsArray.
|
||
*
|
||
* \code
|
||
* RXDEMO_ExecuteRequest(z_call)
|
||
* register struct rx_call *z_call;
|
||
* {
|
||
* int op;
|
||
* XDR z_xdrs;
|
||
* long z_result;
|
||
* xdrrx_create(&z_xdrs, z_call, XDR_DECODE);
|
||
* if (!xdr_int(&z_xdrs, &op))
|
||
* z_result = RXGEN_DECODE;
|
||
* else if (op < RXDEMO_LOWEST_OPCODE || op > RXDEMO_HIGHEST_OPCODE)
|
||
* z_result = RXGEN_OPCODE;
|
||
* else
|
||
* z_result = (*StubProcsArray0[op -RXDEMO_LOWEST_OPCODE])(z_call,
|
||
* &z_xdrs);
|
||
* return z_result;
|
||
* }
|
||
* \endcode
|
||
*
|
||
* \subsection sec6-3-3 External Data Rep file: rxdemo.xdr.c
|
||
*
|
||
* \par
|
||
* This file is created to provide the special routines needed to map any
|
||
* user-defined structures appearing as Rx arguments into and out of network
|
||
* byte order. Again, all on-thewire data appears in network byte order,
|
||
* insuring proper communication between servers and clients with different
|
||
* memory organizations.
|
||
* \par
|
||
* Since the rxdemo example application does not define any special structures
|
||
* to pass as arguments in its calls, this generated file contains only the set
|
||
* of definitions appearing in the interface file. In general, though, should
|
||
* the user define a struct xyz and use it as a parameter to an RPC function,
|
||
* this file would contain a routine named xdr xyz(), which converted the
|
||
* structure field-by-field to and from network byte order.
|
||
*
|
||
* \code
|
||
* /*======================================================================%
|
||
* %% % in the documentation or other materials mentioning features or % %
|
||
* use of this software. Neither the name of Transarc nor the names % % of
|
||
* its contributors may be used to endorse or promote products % % derived
|
||
* from this software without specific prior written % % permission. % % %
|
||
* % THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED %
|
||
* % WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF %
|
||
* % MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. %
|
||
* % Edward R. Zayas % Transarc Corporation % % % The United States
|
||
* Government has rights in this work pursuant to contract no.
|
||
* MDA972-90-C-0036 between the United States Defense % Advanced Research
|
||
* Projects Agency and Transarc Corporation. % % (C) Copyright 1991 Transarc
|
||
* Corporation % % Redistribution and use in source and binary forms are
|
||
* permitted % % provided that: (1) source distributions retain this entire
|
||
* copy<70> % right notice and comment, and (2) distributions including binaries
|
||
* % % display the following acknowledgement: % % % % ``This product includes
|
||
* software developed by Transarc % % Corporation and its contributors'' %
|
||
* %====================================================================== */
|
||
* /* Machine generated file --Do NOT edit */
|
||
*
|
||
* #include "rxdemo.h"
|
||
* #include <rx/rx.h>
|
||
* #include <rx/rx_null.h>
|
||
* #define RXDEMO_SERVER_PORT 8000 /* Service port to advertise */
|
||
* #define RXDEMO_SERVICE_PORT 0 /* User server's port */
|
||
* #define RXDEMO_SERVICE_ID 4 /* Service ID */
|
||
* #define RXDEMO_NULL_SECOBJ_IDX 0 /* Index of null security object */
|
||
* #define RXDEMO_MAX 3
|
||
* #define RXDEMO_MIN 2
|
||
* #define RXDEMO_NULL 0
|
||
* #define RXDEMO_NAME_MAX_CHARS 64
|
||
* #define RXDEMO_BUFF_BYTES 512
|
||
* #define RXDEMO_CODE_SUCCESS 0
|
||
* #define RXDEMO_CODE_CANT_OPEN 1
|
||
* #define RXDEMO_CODE_CANT_STAT 2
|
||
* #define RXDEMO_CODE_CANT_READ 3
|
||
* #define RXDEMO_CODE_WRITE_ERROR 4
|
||
* \endcode
|
||
*
|
||
* \section sec6-4 Section 6.4: Sample Output
|
||
*
|
||
* \par
|
||
* This section contains the output generated by running the example rxdemo
|
||
* server and rxdemo client programs described above. The server end was run on
|
||
* a machine named Apollo, and the client program was run on a machine named
|
||
* Bigtime.
|
||
* \par
|
||
* The server program on Apollo was started as follows:
|
||
* \li apollo: rxdemo_server
|
||
* \li rxdemo_server: Example Rx server process
|
||
* \li Listening on UDP port 8000
|
||
* \par
|
||
* At this point, rxdemo server has initialized its Rx module and started up
|
||
* its listener LWPs, which are sleeping on the arrival of an RPC from any
|
||
* rxdemo client.
|
||
* \par
|
||
* The client portion was then started on Bigtime:
|
||
* \n bigtime: rxdemo_client apollo
|
||
* \n rxdemo: Example Rx client process
|
||
* \n Connecting to Rx server on 'apollo', IP address 0x1acf37c0, UDP port 8000
|
||
* \n ---> Connected. Asking server to add 1 and 2: Reported sum is 3
|
||
* \par
|
||
* The command line instructs rxdemo client to connect to the rxdemo server on
|
||
* host apollo and to use the standard port defined for this service. It
|
||
* reports on the successful Rx connection establishment, and immediately
|
||
* executes an rxdemo Add(1, 2) RPC. It reports that the sum was successfully
|
||
* received. When the RPC request arrived at the server and was dispatched by
|
||
* the rxdemo server code, it printed out the following line:
|
||
* \n [Handling call to RXDEMO_Add(1, 2)]
|
||
* \par
|
||
* Next, rxdemo client prompts for the name of the file to read from the rxdemo
|
||
* server. It is told to fetch the Makefile for the Rx demo directory. The
|
||
* server is executing in the same directory in which it was compiled, so an
|
||
* absolute name for the Makefile is not required. The client echoes the
|
||
* following:
|
||
* \n Name of file to read from server: Makefile Setting up an Rx call for
|
||
* RXDEMO_Getfile...done
|
||
* \par
|
||
* As with the rxdemo Add() call, rxdemo server receives this RPC, and prints
|
||
* out the following information:
|
||
* \li [Handling call to RXDEMO_Getfile(Makefile)]
|
||
* \li [file opened]
|
||
* \li [file has 2450 bytes]
|
||
* \li [file closed]
|
||
* \par
|
||
* It successfully opens the named file, and reports on its size in bytes. The
|
||
* rxdemo server program then executes the streamed portion of the rxdemo
|
||
* Getfile call, and when complete, indicates that the file has been closed.
|
||
* Meanwhile, rxdemo client prints out the reported size of the file, follows
|
||
* it with the file's contents, then advises that the test run has completed:
|
||
*
|
||
* \code
|
||
* [file contents (2450 bytes) fetched over the Rx call appear below]
|
||
*
|
||
* /*#=======================================================================#
|
||
* # The United States Government has rights in this work pursuant # # to
|
||
* contract no. MDA972-90-C-0036 between the United States Defense # # Advanced
|
||
* Research Projects Agency and Transarc Corporation. # # # # (C) Copyright
|
||
* 1991 Transarc Corporation # # # # Redistribution and use in source and
|
||
* binary forms are permitted # # provided that: (1) source distributions
|
||
* retain this entire copy-# # right notice and comment, and (2) distributions
|
||
* including binaries # # display the following acknowledgement: # # # # ''This
|
||
* product includes software developed by Transarc # # Corporation and its
|
||
* contributors'' # # # # in the documentation or other materials mentioning
|
||
* features or # # use of this software. Neither the name of Transarc nor the
|
||
* names # # of its contributors may be used to endorse or promote products #
|
||
* # derived from this software without specific prior written # # permission.
|
||
* # # # # THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||
* # # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # #
|
||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. #
|
||
* #=======================================================================# */
|
||
*
|
||
* SHELL = /bin/sh
|
||
* TOOL_CELL = grand.central.org
|
||
* AFS_INCLIB_CELL = transarc.com
|
||
* USR_CONTRIB = /afs/${TOOL_CELL}/darpa/usr/contrib/
|
||
* PROJ_DIR = ${USR_CONTRIB}.site/grand.central.org/rxdemo/
|
||
* AFS_INCLIB_DIR = /afs/${AFS_INCLIB_CELL}/afs/dest/
|
||
* RXGEN = ${AFS_INCLIB_DIR}bin/rxgen
|
||
* INSTALL = ${AFS_INCLIB_DIR}bin/install
|
||
* LIBS = ${AFS_INCLIB_DIR}lib/librx.a \ ${AFS_INCLIB_DIR}lib/liblwp.a
|
||
* CFLAGS = -g \
|
||
* -I. \
|
||
* -I${AFS_INCLIB_DIR}include \
|
||
* -I${AFS_INCLIB_DIR}include/afs \
|
||
* -I${AFS_INCLIB_DIR} \
|
||
* -I/usr/include
|
||
*
|
||
* system: install
|
||
*
|
||
* install: all
|
||
* ${INSTALL} rxdemo_client ${PROJ_DIR}bin
|
||
* ${INSTALL} rxdemo_server ${PROJ_DIR}bin
|
||
*
|
||
* all: rxdemo_client rxdemo_server
|
||
*
|
||
* rxdemo_client: rxdemo_client.o ${LIBS} rxdemo.cs.o ${CC} ${CFLAGS}
|
||
* -o rxdemo_client rxdemo_client.o rxdemo.cs.o ${LIBS}
|
||
*
|
||
* rxdemo_server: rxdemo_server.o rxdemo.ss.o ${LIBS} ${CC} ${CFLAGS}
|
||
* -o rxdemo_server rxdemo_server.o rxdemo.ss.o ${LIBS}
|
||
*
|
||
* rxdemo_client.o: rxdemo.h
|
||
*
|
||
* rxdemo_server.o: rxdemo.h
|
||
*
|
||
* rxdemo.cs.c rxdemo.ss.c rxdemo.er.c rxdemo.h: rxdemo.xg rxgen rxdemo.xg
|
||
*
|
||
* clean: rm -f *.o rxdemo.cs.c rxdemo.ss.c rxdemo.xdr.c rxdemo.h \
|
||
* rxdemo_client rxdemo_server core
|
||
*
|
||
* [End of file data]
|
||
* rxdemo complete.
|
||
* \endcode
|
||
*
|
||
* \par
|
||
* The rxdemo server program continues to run after handling these calls,
|
||
* offering its services to any other callers. It can be killed by sending it
|
||
* an interrupt signal using Control-C (or whatever mapping has been set up for
|
||
* the shell's interrupt character).
|
||
*
|
||
* \section Bibliography Bibliography
|
||
*
|
||
* \li [1] Transarc Corporation. AFS 3.0 System Administrator's Guide,
|
||
* F-30-0-D102, Pittsburgh, PA, April 1990.
|
||
* \li [2] S.P. Miller, B.C. Neuman, J.I. Schiller, J.H. Saltzer. Kerberos
|
||
* Authentication and Authorization System, Project Athena Technical Plan,
|
||
* Section E.2.1, M.I.T., December 1987.
|
||
* \li [3] Bill Bryant. Designing an Authentication System: a Dialogue
|
||
* in Four Scenes, Project Athena internal document, M.I.T, draft of 8 February
|
||
* 1988.
|
||
* \li [4] S. R. Kleinman. Vnodes: An Architecture for Multiple file
|
||
* System Types in Sun UNIX, Conference Proceedings, 1986 Summer Usenix
|
||
* Technical Conference, pp. 238-247, El Toro, CA, 1986.
|
||
*
|
||
* @}
|
||
*/
|