This module implements an RPC client, i.e. provides means to connect to an RPC service and call remote procedures. In general, this module works in an asynchronous way and is implemented event-driven. All events are handled by an event queue of type Unixqueue.t that must already exist and to which this module adds its own event handlers and event resources. This means that this module can co-exist with other services and share the same event queue with them. You can push several procedure calls on the event queue at once. The queue serves then as a pipeline; the calls are sent to the server as long as the server accepts new calls. Replies are received in any order, and the return values of the remote procedures are delivered using a callback function. You can set timeouts and force automatic retransmission if you want this; these features are enabled by default if the underlying transport mechanism is UDP. Timeouts and other exceptions are delivered to the callback functions, too. The whole mechanism is designed to allow maximum parallelism without needing to use the multi-threading features of O'Caml. Especially, the following parallelisms can be done: - Call several procedures of the same server in parallel. Note that this does not necessarily mean that the procedures are run in parallel since the server is free to decide whether to work in a synchronous or asynchronous way. - Call several procedures of different servers in parallel. To do so, simply add several RPC clients to the same event queue. - Call a procedure and do something completely different in the background; this works well as long as the other task can be programmed using file descriptor events, too.
TODO: add_auth_method. This requires dynamic extension of the RPC representation
The following exceptions are delivered to the callback function:
got EOF when some pending procedure calls were not replied or even sent
After all retransmissions, there was still no reply
exception Communication_error of exn
an I/O error happened
The type of RPC clients
type connector = Inet of (string * int) (* Hostname, port *) | InetNumeric of (int * int * int * int * int) (* IP addr, port *) | Unix of string (* path to unix dom sock *) | Descriptor of Unix.file_descr
val create : Unixqueue.event_system -> (* the event queue to be used *) connector -> (* Connect to which RPC server? *) protocol -> (* which protocol
type *) Rpc_program.t -> (* signatures of the remote program *) t
Opens a connection to the server specified by the 'connector'. The server is assumed to implement an RPC program as specified by the Rpc_program.t argument. All communication to the server is handled using the given queue. All handlers, events and resources are associated to a new group.
If the protocol is Tcp, the communication will be handled stream- oriented. In this case, no timeout is detected and no retransmissions are done. If the protocol is Udp, a datagram-oriented communication style is used. This works only for Internet UDP sockets because these are bidirectional (Unix domain sockets are unidirectional and do not work). For Udp, there is a timeout of 15 seconds and a maximum of 3 retransmissions (i.e. a total of 4 transmission trials).
val configure : t -> int -> float -> unit
configure client retransmissions timeout: sets the number of retransmissions and the timeout for the next calls. (These values are defaults; the actual values are stored with each call.) Values of retransmissions > 0 are semantically only valid if the called procedures are idempotent, i.e. invoking them several times with the same values has the same effect as only one invocation. Positive values for 'retransmissions' should only be used for Udp-style communication. The timeout value determines how long the client waits until the next retransmission is done, or, if no more retransmissions are permitted, a Message_timeout exception is delivered to the receiving callback function. A timeout value of 0.0 means immediate timeout and is senseless. A negative timeout value means 'no timeout'. Positive timeout values are possible for both Udp and Tcp connections. Timeout values are measured in seconds.
val set_exception_handler : t -> (exn -> unit) -> unit
sets an exception handler (the default is a 'do nothing' exception handler). Only exceptions resulting from invocations of a callback function are forwarded to this handler. Exceptions occuring in the handler itself are silently dropped.
NOTE ON EXCEPTIONS:
Uncaught exceptions are terrific in an asynchronous environment. It is unclear what to do with them, since there is usually no 'caller' who can get them. The Unixqueue module implements a special handling for uncaught exceptions. A special 'abort' routine is performed that can be specified. This module adds such an 'abort' routine that does all necessary cleanup, i.e. the file descriptors are shut down and so on. After this has been done, the client is in a clean state; but nobody has been notified about this special situation. As the callback functions serve as communication endpoints, these functions are telled that such an exception has happened using Communication_error x. (If there are no more pending or waiting calls, exceptions are silently dropped.) If these functions do not catch this kind of exception, the global exception handler is used.
val add_call : t -> (* which client *) string -> (* name of the procedure *) xdr_value -> (* parameter of the procedure *) ((unit -> xdr_value) -> unit) ->
this function is called back when the result has been received. The function passed as parameter either evaluates to the returned value or raises an exception.
add a call to the queue of unprocessed calls
val event_system : t -> Unixqueue.event_system
Returns the unixqueue to which the client is attached
val program : t -> Rpc_program.t
Returns the program the client represents
val sync_call : t -> (* which client *) string -> (* which procedure (name) *) xdr_value -> (* the parameter of the procedure *) xdr_value (* the result of the procedure *)
Calls the procedure synchronously. Note that this implies that the underlying unixqueue is started and that all events are processed regardless of whether they have something to do with this call or not.
val shut_down : t -> unit
Shuts down the connection. Any unprocessed calls get the exception Message_lost. Note that the file descriptor is only shut down if the connection has been opened by this module itself, i.e. if the 'connector' was not Descriptor.
val verbose : bool -> unit
set whether you want debug messages or not
Caution! This function is not protected against concurrent invocations from several threads.
Go to the first, previous, next, last section, table of contents.