Chapter 5 -- Programming Interface

age chap4 Chapter 4 -- Rx Support Packages

Section 4.1: Introduction

This chapter documents three packages defined directly in support of the Rx facility.
References to constants, structures, and functions defined by these support packages will appear in the following API chapter.

Section 4.2: The rx queue Package

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.
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.

Section 4.2.1: struct queue

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.
fields
Note that a null Rx queue consists of a single struct queue object whose next and previous pointers refer to itself.

Section 4.2.2: Internal Operations

This section describes the internal operations defined for Rx queues. They will be referenced by the external operations documented in Section 4.2.3.

Section 4.2.2.1: Q(): Coerce type to a queue

element

#define _Q(x) ((struct queue *)(x))
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.

Section 4.2.2.2: QA(): Add a queue element

before/after another element

#define _QA(q,i,a,b) (((i->a=q->a)->b=i)->b=q, q->a=i)
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.

QR(): Remove a queue element

#define _QR(i) ((_Q(i)->prev->next=_Q(i)->next)->prev=_Q(i)->prev)
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.

QS(): Splice two queues together

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

Section 4.2.3: External Operations

Section 4.2.3.1: queue Init(): Initialize a

queue header

#define queue_Init(q) (_Q(q))->prev = (_Q(q))->next = (_Q(q))
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.

Section 4.2.3.2: queue Prepend(): Put element

at the head of a queue

#define queue_Prepend(q,i) _QA(_Q(q),_Q(i),next,prev)
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.

Section 4.2.3.3: queue Append(): Put an

element a the tail of a queue

#define queue_Append(q,i) _QA(_Q(q),_Q(i),prev,next)
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.

Section 4.2.3.4: queue InsertBefore(): Insert a

queue element before another element

#define queue_InsertBefore(i1,i2) _QA(_Q(i1),_Q(i2),prev,next)
Insert queue element i2 before element i1 in i1's queue. The new queue element, i2, should not currently be on any queue.

Section 4.2.3.5: queue InsertAfter(): Insert

a queue element after another element

#define queue_InsertAfter(i1,i2) _QA(_Q(i1),_Q(i2),next,prev)
Insert queue element i2 after element i1 in i1's queue. The new queue element, i2, should not currently be on any queue.

Section: 4.2.3.6: queue SplicePrepend():

Splice one queue before another

#define queue_SplicePrepend(q1,q2) _QS(_Q(q1),_Q(q2),next,prev)
Splice the members of the queue located at q2 to the beginning of the queue located at q1, reinitializing queue q2.

Section 4.2.3.7: queue SpliceAppend(): Splice

one queue after another

#define queue_SpliceAppend(q1,q2) _QS(_Q(q1),_Q(q2),prev,next)
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().

Section 4.2.3.8: queue Replace(): Replace the

contents of a queue with that of another

#define queue_Replace(q1,q2) (*_Q(q1) = *_Q(q2),
_Q(q1)->next->prev = _Q(q1)->prev->next = _Q(q1),
queue_Init(q2))
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.

Section 4.2.3.9: queue Remove(): Remove an

element from its queue

#define queue_Remove(i) (_QR(i), _Q(i)->next = 0)
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.

Section 4.2.3.10: queue MoveAppend(): Move

an element from its queue to the end of another queue

#define queue_MoveAppend(q,i) (_QR(i), queue_Append(q,i))
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.

Section 4.2.3.11: queue MovePrepend(): Move

an element from its queue to the head of another queue

#define queue_MovePrepend(q,i) (_QR(i), queue_Prepend(q,i))
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.

Section 4.2.3.12: queue first(): Return the

first element of a queue, coerced to a particular type

#define queue_first(q,s) ((struct s *)_Q(q)->next)
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.

Section 4.2.3.13: queue Last(): Return the

last element of a queue, coerced to a particular type

#define queue_Last(q,s) ((struct s *)_Q(q)->prev)
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.

Section 4.2.3.14: queue Next(): Return the

next element of a queue, coerced to a particular type

#define queue_Next(i,s) ((struct s *)_Q(i)->next)
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.

Section 4.2.3.15: queue Prev(): Return the

next element of a queue, coerced to a particular type

#define queue_Prev(i,s) ((struct s *)_Q(i)->prev)
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.

Section 4.2.3.16: queue IsEmpty(): Is the

given queue empty?

#define queue_IsEmpty(q) (_Q(q)->next == _Q(q))
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.

Section 4.2.3.17: queue IsNotEmpty(): Is the

given queue not empty?

#define queue_IsNotEmpty(q) (_Q(q)->next != _Q(q))
Return a non-zero value if the queue located at q has at least one element in it other than the queue header itself.

Section 4.2.3.18: queue IsOnQueue(): Is an

element currently queued?

#define queue_IsOnQueue(i) (_Q(i)->next != 0)
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.

Section 4.2.3.19: queue Isfirst(): Is an

element the first on a queue?

#define queue_Isfirst(q,i) (_Q(q)->first == _Q(i))
This macro returns a non-zero value if the queue item located at i is the first element in the queue denoted by q.

Section 4.2.3.20: queue IsLast(): Is an

element the last on a queue?

#define queue_IsLast(q,i) (_Q(q)->prev == _Q(i))
This macro returns a non-zero value if the queue item located at i is the last element in the queue denoted by q.

Section 4.2.3.21: queue IsEnd(): Is an

element the end of a queue?

#define queue_IsEnd(q,i) (_Q(q) == _Q(i))
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.

Section 4.2.3.22: queue Scan(): for loop

test for scanning a queue in a forward direction

#define queue_Scan(q, qe, next, s)
(qe) = queue_first(q, s), next = queue_Next(qe, s);
!queue_IsEnd(q, qe);
(qe) = (next), next = queue_Next(qe, s)
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 *).
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.
 struct mystruct { 
        struct queue q; 
        int myval; 
 }; 
 struct queue demoQueue; 
 struct mystruct *currItemP, *nextItemP; 
 ... 
 for (queue_Scan(&demoQueue, currItemP, nextItemP, mystruct)) { 
        currItemP->myval++; 
 } 

Note that extra initializers can be added before the body of the queue Scan() invocation above, and extra expressions can be added afterwards.

Section 4.2.3.23: queue ScanBackwards(): for

loop test for scanning a queue in a reverse direction

define queue_ScanBackwards(q, qe, prev, s)
(qe) = queue_Last(q, s), prev = queue_Prev(qe, s);
!queue_IsEnd(q, qe);
(qe) = prev, prev = queue_Prev(qe, s)
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 4.3: The rx clock Package

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.

Section 4.3.1: struct clock

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.
fields
long sec -Seconds since call to clock Init().
long usec -Microseconds since call to clock Init().

Section 4.3.12: clock nUpdates

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.

Section 4.3.3: Operations

Section 4.3.3.1: clock Init(): Initialize the

clock package

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.

Section 4.3.3.2: clock UpdateTime(): Compute

the current time

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.

Section 4.3.3.3: clock GetTime(): Return the

current clock time

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.

Section 4.3.3.5: clock ElapsedTime(): Measure

milliseconds between two given clock values

This macro returns the elapsed time in milliseconds between the two clock structure pointers provided as arguments, cv1 and cv2.

Section 4.3.3.6: clock Advance(): Advance the

recorded clock time by a specified clock value

This macro takes a single (struct clock *) pointer argument, cv, and adds this clock value to the internal clock value maintined by the package.

Section 4.3.3.7: clock Gt(): Is a clock value

greater than another?

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.

Section 4.3.3.8: clock Ge(): Is a clock value

greater than or equal to another?

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.

Section 4.3.3.9: clock Gt(): Are two clock

values equal?

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.

value less than or equal to another?

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.

Section 4.3.3.11: clock Lt(): Is a clock

value less than another?

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.

Section 4.3.3.12: clock IsZero(): Is a clock

value zero?

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.

Section 4.3.3.13: clock Zero(): Set a clock

value to zero

This macro takes a single parameter of type (struct clock *), c. It sets the given clock value to zero.

Section 4.3.3.14: clock Add(): Add two clock

values together
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.

Section 4.3.3.15: clock Sub(): Subtract two

clock values

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.

Section 4.3.3.16: clock Float(): Convert a

clock time into floating point

This macro takes a single parameter of type (struct clock *), c. It expresses the given clock value as a floating point number.

Section 4.4: The rx event Package

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.
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.

Section 4.4.1: struct rxevent

This structure defines the format of an Rx event record.
fields
struct queue junk -The queue to which this event belongs.
struct clock eventTime -The clock time recording when this event comes due.
int (*func)() -The user-supplied function to call upon expiration.
char *arg -The first argument to the (*func)() function above.
char *arg1 -The second argument to the (*func)() function above.

Section 4.4.2: Operations

This section covers the interface routines provided for the Rx event package.

Section 4.4.2.1: rxevent Init(): Initialize

the event package

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.
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.

Section 4.4.2.2: rxevent Post(): Schedule an

event

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.
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.

Section 4.4.2.3: rxevent Cancel 1(): Cancel

an event (internal use)

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.
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.

Section 4.4.2.4: rxevent Cancel(): Cancel an

event (external use)

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.

Section 4.4.2.4: rxevent RaiseEvents():

Initialize the event package

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.
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.

Section 4.4.2.6: rxevent TimeToNextEvent():

Get amount of time until the next event expires

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.

Section 5.1: Introduction

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.
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.
An example application illustrating the use of this interface, showcasing code from both server and client sides, appears in the following chapter.

Section 5.2: Constants

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:
An attempt has been made to relate these constant definitions to the objects or routines that utilize them.

Section 5.2.1: Configuration Quantities

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.
Name
RX IDLE DEAD TIME
Value
60
Description
Default idle dead time for connections, in seconds.
Name
RX MAX SERVICES
Value
20
Description
The maximum number of Rx services that may be installed within one application.
Name
RX PROCESS MAXCALLS
Value
4
Description
The maximum number of asynchronous calls active simultaneously on any given Rx connection. This value must be set to a power of two.
Name
RX DEFAULT STACK SIZE
Value
16,000
Description
Default lightweight thread stack size, measured in bytes. This value may be overridden by calling the rx_SetStackSize() macro.
Name
RX PROCESS PRIORITY
Value
LWP NORMAL PRIORITY
Description
This is the priority under which an Rx thread should run. There should not generally be any reason to change this setting.
Name
RX CHALLENGE TIMEOUT
Value
2
Description
The number of seconds before another authentication request packet is generated.
Name
RX MAXACKS
Value
255
Description
Maximum number of individual acknowledgements that may be carried in an Rx acknowledgement packet.

Section 5.2.2: Waiting Options

These definitions provide readable values indicating whether an operation should block when packet buffer resources are not available.
Name
RX DONTWAIT
Value
0
Description
Wait until the associated operation completes.
Name
RX WAIT
Value
1
Description
Don't wait if the associated operation would block.

Section 5.2.3: Connection ID Operations

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.
Name
RX CIDSHIFT
Value
2
Description
Number of bits to right-shift to isolate a connection ID. Must be set to the log (base two) of RX MAXCALLS.
Name
RX CHANNELMASK
Value
(RX MAXCALLS-1)
Description
Mask used to isolate a call channel from a connection ID field.
Name
RX CIDMASK
Value
(~RX CHANNELMASK)
Description
Mask used to isolate the connection ID from its field, masking out the call channel information.

Section 5.2.4: Connection Flags

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.
Name
RX CONN MAKECALL WAITING
Value
1
Description
rx MakeCall() is waiting for a channel.
Name
RX CONN DESTROY ME
Value
2
Description
Destroy this (client) connection after its last call completes.
Name
RX CONN USING PACKET CKSUM
Value
4
Description
This packet is using security-related check-summing (a non-zero header, spare field has been seen.)

Section 5.2.5: Connection Types

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.
Name
RX CLIENT CONNECTION
Value
0
Description
This is a client-side connection.
Name
CONNECTION
Value
1
Description
This is a server-side connection.

Section 5.2.6: Call States

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.
Name
RX STATE NOTINIT
Value
0
Description
The call structure has never been used, and is thus still completely uninitialized.
Name
RX STATE PRECALL
Value
1
Description
A call is not yet in progress, but packets have arrived for it anyway. This only applies to calls within server-side connections.
Name
RX STATE ACTIVE
Value
2
Description
This call is fully active, having an attached lightweight thread operating on its behalf.
Name
RX STATE DAILY
Value
3
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.

Section 5.2.7: Call Flags:

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.
Name
RX CALL READER WAIT
Value
1
Description
Reader is waiting for next packet.
Name
RX CALL WAIT WINDOW ALLOC
Value
2
Description
Sender is waiting for a window so that it can allocate buffers.
Name
RX CALL WAIT WINDOW SEND
Value
4
Description
Sender is waiting for a window so that it can send buffers.
Name
RX CALL WAIT PACKETS
Value
8
Description
Sender is waiting for packet buffers.
Name
RX CALL RECEIVE DONE
Value
16
Description
The call is waiting for a lightweight thread to be assigned to the operation it has just received.
Name
RX CALL RECEIVE DONE
Value
32
Description
All packets have been received on this call.
Name
RX CALL CLEARED
Value
64
Description
The receive queue has been cleared when in precall state.

Section 5.2.8: Call Modes

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.
Name
RX MODE SENDING
Value
1
Description
We are sending or ready to send.
Name
RX MODE RECEIVING
Value
2
Description
We are receiving or ready to receive.
Name
RX MODE ERROR
Value
3
Description
Something went wrong in the current conversation.
Name
RX MODE EOF
Value
4
Description
The server side has flushed (or the client side has read) the last reply packet.

Section 5.2.9: Packet Header Flags

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:
Name
RX CLIENT INITIATED
Value
1
Description
Signifies that a packet has been sent/received from the client side of the call.
Name
RX REQUEST ACK
Value
2
Description
The Rx calls' peer entity requests an acknowledgement.
Name
RX LAST PACKET
Value
4
Description
This is the final packet from this side of the call.
Name
RX MORE PACKETS
Value
8
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.
Name
RX PRESET FLAGS
Value
(RX CLIENT INITIATED | RX LAST PACKET)
Description
This flag is preset once per Rx packet. It doesn't change on retransmission of the packet.

Section 5.2.10: Packet Sizes

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.
Name
RX IPUDP SIZE
Value
28
Description
The number of bytes taken up by IP/UDP headers.
Name
RX MAX PACKET SIZE
Value
(1500 - RX IPUDP SIZE)
Description
This is the Ethernet MTU minus IP and UDP header sizes.
Name
RX HEADER SIZE
Value
sizeof (struct rx header)
Description
The number of bytes in an Rx packet header.
Name
RX MAX PACKET DATA SIZE
Value
(RX MAX PACKET SIZE RX - HEADER SIZE)
Description
Maximum size in bytes of the user data in a packet.
Name
RX LOCAL PACKET SIZE
Value
RX MAX PACKET SIZE
Description
Packet size in bytes to use when being sent to a host on the same net.
Name
RX REMOTE PACKET SIZE
Value
(576 - RX IPUDP SIZE)
Description
Packet size in bytes to use when being sent to a host on a different net.

Section 5.2.11: Packet Types

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.
Name
RX PACKET TYPE DATA
Value
1
Description
A user data packet.
Name
RX PACKET TYPE ACK
Value
2
Description
Acknowledgement packet.
Name
RX PACKET TYPE BUSY
Value
3
Description
Busy packet. The server-side entity cannot accept the call at the moment, but the requestor is encouraged to try again later.
Name
RX PACKET TYPE ABORT
Value
4
Description
Abort packet. No response is needed for this packet type.
Name
RX PACKET TYPE ACKALL
Value
5
Description
Acknowledges receipt of all packets on a call.
Name
RX PACKET TYPE CHALLENGE
Value
6
Description
Challenge the client's identity, requesting credentials.
Name
RX PACKET TYPE RESPONSE
Value
7
Description
Response to a RX PACKET TYPE CHALLENGE authentication challenge packet.
Name
RX PACKET TYPE DEBUG
Value
8
Description
Request for debugging information.
Name
RX N PACKET TYPES
Value
9
Description
The number of Rx packet types defined above. Note that it also includes packet type 0 (which is unused) in the count.
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.
 {
        "data", 
        "ack", 
        "busy", 
        "abort", 
        "ackall", 
        "challenge", 
        "response", 
        "debug" 
 } 

Section 5.2.12: Packet Classes

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.
Name
RX PACKET CLASS RECEIVE
Value
0
Description
Receive packet for user data.
Name
RX PACKET CLASS SEND
Value
1
Description
Send packet for user data.
Name
RX PACKET CLASS SPECIAL
Value
2
Description
A special packet that does not hold user data, such as an acknowledgement or authentication challenge.
Name
RX N PACKET CLASSES
Value
3
Description
The number of Rx packet classes defined above.

Section 5.2.13: Conditions Prompting Ack Packets

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.
Name
RX ACK REQUESTED
Value
1
Description
The peer has explicitly requested an ack on this packet.
Name
RX ACK DUPLICATE
Value
2
Description
A duplicate packet has been received.
Name
RX ACK OUT OF SEQUENCE
Value
3
Description
A packet has arrived out of sequence.
Name
RX ACK EXCEEDS WINDOW
Value
4
Description
A packet sequence number higher than maximum value allowed by the call's window has been received.
Name
RX ACK NOSPACE
Value
5
Description
No packet buffer space is available.
Name
RX ACK PING
Value
6
Description
Acknowledgement for keep-alive purposes.
Name
RX ACK PING RESPONSE
Value
7
Description
Response to a RX ACK PING packet.
Name
RX ACK DELAY
Value
8
Description
An ack generated due to a period of inactivity after normal packet receptions.

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.
Name
RX ACK TYPE NACK
Value
0
Description
Receiver doesn't currently have the associated packet; it may never hae been received, or received and then later dropped before processing.
Name
RX ACK TYPE ACK
Value
1
Description
Receiver has the associated packet queued, although it may later decide to discard it.

Section 5.2.15: Error Codes

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.
Name
RX CALL DEAD
Value
-1
Description
A connection has been inactive past Rx's tolerance levels and has been shut down.
Name
RX INVALID OPERATION
Value
-2
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.
Name
RX CALL TIMEOUT
Value
-3
Description
The (optional) timeout value placed on this call has been exceeded (see Sections 5.5.3.4 and 5.6.5).
Name
RX EOF
Value
-4
Description
Unexpected end of data on a read operation.
Name
RX PROTOCOL ERROR
Value
-5
Description
An unspecified low-level Rx protocol error has occurred.
Name
RX USER ABORT
Value
-6
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.

Section 5.2.16: Debugging Values

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.

Section 5.2.16.1: Version Information

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.
Name
RX DEBUGI VERSION MINIMUM
Value
'L'
Description
The earliest version of Rx statistics available.
Name
RX DEBUGI VERSION
Value
'M'
Description
The latest version of Rx statistics available.
Name
RX DEBUGI VERSION W SECSTATS
Value
'L'
Description
Identifies the earliest version in which statistics concerning Rx security objects is available.
Name
RX DEBUGI VERSION W GETALLCONN
Value
'M'
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.
Name
RX DEBUGI VERSION W RXSTATS
Value
'M'
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.
Name
RX DEBUGI VERSION W UNALIGNED CONN
Value
'L'
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.

Section 5.2.16.2: Opcodes

When requesting debugging/statistics information, the caller specifies one of the following supported data collections:
Name
RX DEBUGI GETSTATS
Value
1
Description
Get basic Rx statistics.
Name
RX DEBUGI GETCONN
Value
2
Description
Get information on all Rx connections considered "interesting" (as defined below), and no others.
Name
RX DEBUGI GETALLCONN
Value
3
Description
Get information on all existing Rx connection structures, even "uninteresting" ones.
Name
RX DEBUGI RXSTATS
Value
4
Description
Get all available Rx stats.
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.

Section 5.2.16.3: Queuing

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.
Name
RX OTHER IN
Value
1
Description
Packets available in in queue.
Name
RX OTHER OUT
Value
2
Description
Packets available in out queue.

Section 5.3: Structures

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:
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.

Section 5.3.1: Security Objects

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.

Section 5.3.1.1: struct rx securityOps

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.
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.
fields

Section 5.2.1.2: struct rx securityClass

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.
fields

Section 5.3.1.3: struct rx

securityObjectStats

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.
fields

Section 5.3.2: Protocol Objects

The structures describing the main abstractions and entities provided by Rx, namely services, peers, connections and calls are covered in this section.

Section 5.3.2.1: struct rx service

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.
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.
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.
fields

Section 5.3.2.2: struct rx connection

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.
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.
fields

Section 5.3.2.3: struct rx peer

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.
fields

Section 5.3.2.4: struct rx call

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.
fields

Section 5.3.3: Packet Formats

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.

Section 5.3.3.1: struct rx header

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.
fields

Section 5.3.3.2: struct rx packet

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.
fields

Section 5.3.3.3: struct rx ackPacket

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.
fields
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.
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.

Section 5.3.4: Debugging and Statistics

The following structures are defined in support of the debugging and statistics-gathering interfaces provided by Rx.

Section 5.3.4.1: struct rx stats

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.
fields

Section 5.3.4.2: struct rx debugIn

This structure defines the data format for a packet requesting one of the statistics collections maintained by Rx.
fields

Section 5.3.4.3: struct rx debugStats

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.
fields

Section 5.3.4.4: struct rx debugConn

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.
fields

Section 5.3.4.5: struct rx debugConn vL

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 5.4: Exported Variables

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).

Section 5.4.1: rx connDeadTime

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.

Section 5.4.2: rx idleConnectionTime

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.

Section 5.4.3: rx idlePeerTime

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.

Section 5.4.4: rx extraQuota

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.

Section 5.4.5: rx extraPackets

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.

Section 5.4.6: rx nPackets

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.

Section 5.4.7: rx nFreePackets

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.

Section 5.4.8: rx stackSize

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.

Section 5.4.9: rx packetTypes

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.

Section 5.4.10: rx stats

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 5.5: Macros

Rx uses many macro definitions in preference to calling C functions directly. There are two main reasons for doing this:
The set of Rx macros is described according to the following categories.

Section 5.5.1: field Selections/Assignments

These macros facilitate the fetching and setting of fields from the structures described Chapter 5.3.

Section 5.5.1.1: rx ConnectionOf()

#define rx_ConnectionOf(call) ((call)->conn)
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.

Section 5.5.1.2: rx PeerOf()

#define rx_PeerOf(conn) ((conn)->peer)
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.

Section 5.5.1.3: rx HostOf()

#define rx_HostOf(peer) ((peer)->host)
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.

Section 5.5.1.4: rx PortOf()

#define rx_PortOf(peer) ((peer)->port)
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.

Section 5.5.1.5: rx GetLocalStatus()

#define rx_GetLocalStatus(call, status) ((call)->localStatus)
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.

Section 5.5.1.6: rx SetLocalStatus()

#define rx_SetLocalStatus(call, status) ((call)->localStatus = (status))
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.

Section 5.5.1.7: rx GetRemoteStatus()

#define rx_GetRemoteStatus(call) ((call)->remoteStatus)
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.

Section 5.5.1.8: rx Error()

#define rx_Error(call) ((call)->error)
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.

Section 5.5.1.9: rx DataOf()

#define rx_DataOf(packet) ((char *) (packet)->wire.data)
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 *).

Section 5.5.1.10: rx GetDataSize()

#define rx_GetDataSize(packet) ((packet)->length)
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.

Section 5.5.1.11: rx SetDataSize()

#define rx_SetDataSize(packet, size) ((packet)->length = (size))
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.

Section 5.5.1.12: rx GetPacketCksum()

#define rx_GetPacketCksum(packet) ((packet)->header.spare)
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.

Section 5.5.1.13: rx SetPacketCksum()

#define rx_SetPacketCksum(packet, cksum) ((packet)->header.spare = (cksum))
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.

Section 5.5.1.14: rx GetRock()

#define rx_GetRock(obj, type) ((type)(obj)->rock)
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.

Section 5.5.1.15: rx SetRock()

#define rx_SetRock(obj, newrock) ((obj)->rock = (VOID *)(newrock))
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 *).

Section 5.5.1.16: rx SecurityClassOf()

#define rx_SecurityClassOf(conn) ((conn)->securityIndex)
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.

Section 5.5.1.17: rx SecurityObjectOf()

#define rx_SecurityObjectOf(conn) ((conn)->securityObject)
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 *).

Section 5.5.2: Boolean Operations

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.

Section 5.5.2.1: rx IsServerConn()

#define rx_IsServerConn(conn) ((conn)->type == RX_SERVER_CONNECTION)
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.

Section 5.5.2.2: rx IsClientConn()

#define rx_IsClientConn(conn) ((conn)->type == RX_CLIENT_CONNECTION)
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.

Section 5.5.2.2: rx IsUsingPktCksum()

#define rx_IsUsingPktCksum(conn) ((conn)->flags & RX_CONN_USING_PACKET_CKSUM)
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.

Section 5.5.3: Service Attributes

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.

Section 5.5.3.1: rx SetStackSize()

rx_stackSize = (((stackSize) stackSize) > rx_stackSize) ? stackSize : rx_stackSize)
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.
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.
An instance of the rx SetStackSize() macro itself resolves into the result of the assignment, which is an object of type int.

Section 5.5.3.2: rx SetMinProcs()

#define rx_SetMinProcs(service, min) ((service)->minProcs = (min))
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.

Section 5.5.3.3: rx SetMaxProcs()

#define rx_SetMaxProcs(service, max) ((service)->maxProcs = (max))
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.

Section 5.5.3.4: rx SetIdleDeadTime()

#define rx_SetIdleDeadTime(service, time) ((service)->idleDeadTime = (time))
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.
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.

Section 5.5.3.5: rx SetServiceDeadTime()

#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.
See the description of the rx SetConnDeadTime() macro below to see how hard timeouts may be set for situations of complete call inactivity.

Section 5.5.3.6: rx SetRxDeadTime()

#define rx_SetRxDeadTime(seconds) (rx_connDeadTime = (seconds))
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.
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.

Section 5.5.3.7: rx SetConnDeadTime()

#define rx_SetConnDeadTime(conn, seconds) (rxi_SetConnDeadTime(conn, seconds))
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.
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.

Section 5.5.3.8: rx SetConnHardDeadTime()

#define rx_SetConnHardDeadTime(conn, seconds) ((conn)->hardDeadTime = (seconds))
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()).
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.

Section 5.5.3.9: rx GetBeforeProc()

#define rx_GetBeforeProc(service) ((service)->beforeProc)
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.
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.

Section 5.5.3.10: rx SetBeforeProc()

#define rx_SetBeforeProc(service, proc) ((service)->beforeProc = (proc))
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.
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 *)().

Section 5.5.3.11: rx GetAfterProc()

#define rx_GetAfterProc(service) ((service)->afterProc)
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.
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.

Section 5.5.3.12: rx SetAfterProc()

#define rx_SetAfterProc(service, proc) ((service)->afterProc = (proc))
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.
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 *)().

Section 5.5.3.13: rx SetNewConnProc()

#define rx_SetNewConnProc(service, proc) ((service)->newConnProc = (proc))
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.
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.

Section 5.5.3.14: rx SetDestroyConnProc()

#define rx_SetDestroyConnProc(service, proc) ((service)->destroyConnProc = (proc))
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.
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.

Section 5.5.4: Security-Related Operations

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).

Section 5.5.4.1: rx GetSecurityHeaderSize()

#define rx_GetSecurityHeaderSize(conn) ((conn)->securityHeaderSize)
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.
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.

Section 5.5.4.2: rx SetSecurityHeaderSize()

#define rx_SetSecurityHeaderSize(conn, length) ((conn)->securityHeaderSize = (length))
Set the field in a connection structure that records the length in bytes of the associated security module's packet header data.
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.

Section 5.5.4.3: rx

GetSecurityMaxTrailerSize()

#define rx_GetSecurityMaxTrailerSize(conn) ((conn)->securityMaxTrailerSize)
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.
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.

Section 5.5.4.4: rx

SetSecurityMaxTrailerSize()

#define rx_SetSecurityMaxTrailerSize(conn, length) ((conn)->securityMaxTrailerSize = (length))
Set the field in a connection structure that records the maximum length in bytes of the associated security module's packet trailer data.
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.

Section 5.5.5: Sizing Operations

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.

Section 5.5.5.1: rx UserDataOf()

#define rx_UserDataOf(conn, packet) (((char *) (packet)->wire.data) + (conn)->securityHeaderSize)
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 *).

Section 5.5.5.2: rx MaxUserDataSize()

#define rx_MaxUserDataSize(conn)
((conn)->peer->packetSize
-RX_HEADER_SIZE
-(conn)->securityHeaderSize
-(conn)->securityMaxTrailerSize)
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.
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).

Section 5.5.6: Complex Operations

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.

Section 5.5.6.1: rx Read()

#define rx_Read(call, buf, nbytes)
((call)->nLeft > (nbytes) ?
bcopy((call)->bufPtr, (buf), (nbytes)),
(call)->nLeft -= (nbytes), (call)->bufPtr += (nbytes), (nbytes)
: rx_ReadProc((call), (buf), (nbytes)))
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.
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.

Section 5.5.6.2: rx Write()

#define rx_Write(call, buf, nbytes)
((call)->nFree > (nbytes) ?
bcopy((buf), (call)->bufPtr, (nbytes)),
(call)->nFree -= (nbytes),
(call)->bufPtr += (nbytes), (nbytes)
: rx_WriteProc((call), (buf), (nbytes)))
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.
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.

Section 5.5.7: Security Operation Invocations

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.
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.
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.

Section 5.5.7.1: RXS OP()

 #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 

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.

Section 5.5.7.1: RXS Close()

#define RXS_Close(obj) RXS_OP(obj, Close, (obj))
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.
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.

Section 5.5.7.3: RXS NewConnection()

#define RXS_NewConnection(obj, conn) RXS_OP(obj, NewConnection, (obj, conn))
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.
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 *).
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.

Section 5.5.7.4: RXS PreparePacket()

#define RXS_PreparePacket(obj, call, packet)
RXS_OP(obj, PreparePacket, (obj, call, packet))
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.
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 *).
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.

Section 5.5.7.5: RXS SendPacket()

#define RXS_SendPacket(obj, call, packet) RXS_OP(obj, SendPacket, (obj, call, packet))
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.
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 *).
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.

Section 5.5.7.6: RXS CheckAuthentication()

#define RXS_CheckAuthentication(obj, conn) RXS_OP(obj, CheckAuthentication, (obj, conn))
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.
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 *).
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.

Section 5.5.7.7: RXS CreateChallenge()

#define RXS_CreateChallenge(obj, conn) RXS_OP(obj, CreateChallenge, (obj, conn))
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.
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 *).
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.

Section 5.5.7.8: RXS GetChallenge()

#define RXS_GetChallenge(obj, conn, packet) RXS_OP(obj, GetChallenge, (obj, conn, packet))
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.
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 *).
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.

Section 5.5.7.9: RXS GetResponse()

#define RXS_GetResponse(obj, conn, packet) RXS_OP(obj, GetResponse, (obj, conn, packet))
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.
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 *).
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.

Section 5.5.7.10: RXS CheckResponse()

#define RXS_CheckResponse(obj, conn, packet) RXS_OP(obj, CheckResponse, (obj, conn, packet))
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.
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 *).
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.

Section 5.5.7.11: RXS CheckPacket()

#define RXS_CheckPacket(obj, call, packet) RXS_OP(obj, CheckPacket, (obj, call, packet))
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.
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 *).
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.
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.

Section 5.5.7.12: RXS DestroyConnection()

#define RXS_DestroyConnection(obj, conn) RXS_OP(obj, DestroyConnection, (obj, conn))
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.
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.
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.

Section 5.5.7.13: RXS GetStats()

#define RXS_GetStats(obj, conn, stats) RXS_OP(obj, GetStats, (obj, conn, stats))
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.
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 *).
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 5.6: Functions

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.
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.
All Rx routines return zero upon success. The range of error codes employed by Rx is defined in Section 5.2.15.

Section 5.6.1: Exported Operations

Section 5.6.2: rx Init _ Initialize Rx

int rx Init(IN int port)
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.
Error Codes
RX ADDRINUSE The port provided has already been taken.

Section 5.6.3: rx NewService _ Create and install

a new service

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)())
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.
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:
Error Codes
(struct rx service *) NULL The new Rx service could not be created, due to one of the errors listed above.

Section 5.6.4: rx NewConnection _ Create a new

connection to a given service

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)
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.
Error Codes
--- A pointer to an initialized Rx connection is always returned, unless osi Panic() is called due to memory allocation failure.

Section 5.6.5: rx NewCall _ Start a new call on

the given connection

struct rx call *rx NewCall( IN struct rx connection *conn)
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.
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.
Error Codes
--- A pointer to an initialized Rx call is always returned, unless osi Panic() is called due to memory allocation failure.

Section 5.6.6: rx EndCall _ Terminate the given

call

int rx EndCall(
Parameters:
IN struct rx call *call,
IN long rc
)
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).
Error Codes
-1 Unspecified error has occurred.

Section 5.6.7: rx StartServer _ Activate installed

rx service(s)

void rx StartServer( IN int donateMe)
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.
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.
Error Codes
---None.

Section 5.6.8: rx PrintStats -- Print basic

statistics to a file

void rx PrintStats( IN FILE *file)
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.
Error Codes
---None.

Section 5.6.9: rx PrintPeerStats _ Print peer

statistics to a file
void rx PrintPeerStats( IN FILE *file, IN struct rx peer *peer)
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.
Error Codes
---None.

Section 5.6.10: rx finalize _ Shut down Rx

gracefully

void rx finalize()
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.
Error Codes
---None.

Section 5.6.11: Semi-Exported Operations

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.

Section 5.6.12: rx WriteProc _ Write data to an

outgoing call

int rx WriteProc( IN struct rx call *call, IN char *buf, IN int nbytes)
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.
This routine is called by the rx Write() macro, which is why it must be exported by the Rx facility.
Error Codes
Indicates error in the given Rx call; use the rx Error() macro to determine the call status.

Section 5.6.13: rx ReadProc _ Read data from an

incoming call

int rx ReadProc( IN struct rx call *call, IN char *buf, IN int nbytes)
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.
This routine is called by the rx Read() macro, which is why it must be exported by the Rx facility.
Error Codes
Indicates error in the given Rx call; use the rx Error() macro to determine the call status.

Section 5.6.1: Exported Operations

data on outgoing call

void rx FlushWrite( IN struct rx call *call)
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.
Error Codes
---None.

Section 5.6.15: rx SetArrivalProc _ Set function

to invoke upon call packet arrival

void rx SetArrivalProc( IN struct rx call *call, IN VOID (*proc)(), IN VOID *handle, IN VOID *arg)
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.
Error Codes
---None.

Generated on Mon Aug 3 00:32:00 2009 by  doxygen 1.5.1