Next: , Previous: Building an RPC Client, Up: Implementation of ONC RPC


4.3.2 Building an RPC Server

The (rpc rpc server) module provides helpful facilities for building an ONC RPC server. In particular, it provides tools to decode RPC call messages, as well as an event loop mechanisms that allows RPC calls to be automatically dispatched to the corresponding Scheme handlers.

— Scheme Procedure: procedure-call-information call-msg

Return an <rpc-call> object that denotes the procedure call requested in call-msg (the result of an (xdr-decode rpc-message port) operation). If call-msg is not an appropriate RPC call message, an error condition is raised.

The error condition raised may be either onc-rpc-version-mismatch-error? or rpc-invalid-call-message-error?.

The returned object can be queried using the rpc-call- procedures described below.

— Scheme Procedure: rpc-call-xid call

Return the transaction ID (“xid” for short) of call.

— Scheme Procedure: rpc-call-program call
— Scheme Procedure: rpc-call-version call
— Scheme Procedure: rpc-call-procedure call

Return the program, version or procedure number of call.

— Scheme Procedure: rpc-call-credentials call
— Scheme Procedure: rpc-call-verifier call

Return the credentials and verifier provided by the client for call. FIXME: As of version 0.3, this information is not usable.

The following procedures allow the description of RPC “programs”. Such descriptions can then be readily used to produced a full-blown RPC processing loop.

— Scheme Procedure: make-rpc-program number versions

Return a new object describing the RPC program identified by number and consisting of the versions listed in versions.

— Scheme Procedure: make-rpc-program-version number procedures

Return a new object describing the RPC program version identified by number and consisting of the procedures listed in procedures.

— Scheme Procedure: make-rpc-procedure number argument-xdr-type result-xdr-type handler [one-way?]

Return a new object describing a procedure whose number is number, whose argument type is argument-xdr-type and whose result type is result-xdr-type (see XDR Type Representations). handler should be a procedure that will be invoked upon reception of an RPC call for that procedure.

If synchronous RPC processing is used, i.e., through serve-one-stream-request, then handler is passed the decoded argument and should return a result type that may be encoded as result-xdr-type. If asynchronous processing is used, i.e., through serve-one-stream-request/asynchronous, then handler is passed the decoded argument along with a continuation that must be invoked to actually return the result.

If one-way? is passed and is true, then the returned procedure is marked as “one-way” (see make-one-way-rpc-call). For one-way procedures, run-stream-rpc-server and similar procedures ignores the return value of handler and don't send any reply when procedure number is invoked.

Once a program, its versions and procedures have been defined, an RPC server for that program (and possibly others) can be run using the following procedures.

— Scheme Procedure: run-stream-rpc-server sockets+rpc-programs timeout close-connection-proc idle-thunk

Run a full-blown connection-oriented (i.e., SOCK_STREAM, be it PF_UNIX or PF_INET) RPC server for the given listening sockets and RPC programs. sockets+rpc-programs should be a list of listening socket-RPC program pairs (where “RPC programs” are objects as returned by make-rpc-program). timeout should be a number of microseconds that the loop should wait for input; when no input is available, idle-thunk is invoked, thus at most every timeout microseconds. If close-connection-proc is a procedure, it is called when a connection is being closed is passed the corresponding <stream-connection> object.

While an RPC server is running over a stream-oriented transport such as TCP using run-stream-rpc-server, its procedure handlers can get information about the current connection and client:

— Scheme Procedure: current-stream-connection

This procedure returns a <stream-connection> object describing the current TCP connection (when within a run-stream-rpc-server invocation). This object can be queried with the procedures described below.

— Scheme Procedure: stream-connection? obj

Return #t if obj is a <stream-connection> object.

— Scheme Procedure: stream-connection-port connection

Return the I/O port (not the TCP port) for connection.

— Scheme Procedure: stream-connection-peer-address connection

Return the IP address of the peer/client of connection (see Network Socket Address).

— Scheme Procedure: stream-connection-rpc-program connection

Return the RPC program object corresponding to connection.

For a complete RPC server example, Creating the Server.

The run-stream-rpc-server mechanism is limited to servers managing only RPC connections, and only over stream-oriented transports. Should your server need to handle other input sources, a more geneneral event handling mechanism is available. This works by first creating a set of I/O managers and then passing run-input-event-loop a list of I/O manager-file descriptor pairs to actually handle I/O events.

— Scheme Procedure: make-i/o-manager exception-handler read-handler

Return an I/O manager. When data is available for reading, read-handler will be called and passed a port to read from; when an exception occurs on a port, exception-handler is called and passed the failing port.

— Scheme Procedure: i/o-manager? obj

Return #t if obj is an I/O manager.

— Scheme Procedure: i/o-manager-exception-handler manager
— Scheme Procedure: i/o-manager-read-handler manager

Return, respectively, the exception handler and the read handler of manager.

— Scheme Procedure: run-input-event-loop fd+manager-list timeout idle-thunk

Run an input event loop based on fd+manager-list, a list of pairs of input ports (or file descriptors) and I/O managers. I/O managers are invoked are invoked and passed the corresponding port when data becomes readable or when an exception occurs. I/O manager handlers can:

When timeout (a number of microseconds) is reached, idle-thunk is invoked. If timeout is #f, then an infinite timeout is assumed and idle-thunk is never run. The event loop returns when no watched port is left.

The event loop provided by run-input-event-loop should cover a wide range of applications. However, it will turn out to be insufficient in situations where tasks must be executed at specific times, and where the interval between consecutive executions varies over the program's lifetime.

Finally, a lower-level mechanism is available to handle a single incoming RPC:

— Scheme Procedure: serve-one-stream-request program port

Serve one RPC for program, reading the RPC from port (using the record-marking protocol) and writing the reply to port. If port is closed or the end-of-file was reached, an &rpc-connection-lost-error is raised.

— Scheme Procedure: serve-one-stream-request/asynchronous program port

Same as serve-one-stream-request except that the RPC is to be handled in an asynchronous fashion.

Concretely, the procedure handler passed to make-rpc-procedure is called with two arguments instead of one: the first one is the actual procedure argument, and the second one is a one-argument procedure that must be invoked to return the procedure's result—in other words, procedure call processing is decoupled from procedure call return using continuation-passing style.