1 Copyright (c) 2000, 2001 Sendmail, Inc. All rights reserved.
6 This document explains how the generated erlang modules work, and
7 the relationship between the different modules. It also describes
8 the API to the rpc package.
10 The purpose of this document is to give an overview of the package.
11 It might not be completely correct and up-to-date; consult the code
14 This package conforms to rfc1831 and rfc1832. Note that not all rpc
15 generation packages implement the full RPC language. For example,
16 some C packages does not allow a rpc procedure to take more than one
17 parameter. This package does not have these limitations. Keep that
18 in mind if your creating RPC specifications which should be
33 strings are represented as binaries.
34 structs are represented as tuples.
35 unions are represented as tuples where the first element
37 all arrays are represented as lists (i.e. w/o explicit size tag)
38 bools are represented as true | false.
39 everything else is straightforward, e.g. hyper as int etc.
43 Given the following contents of "xx.x":
55 union regevent switch (eventtype type) {
62 Correct erlang representations:
64 {'EVENT_CREATE', {2, <<"hi mom">>}}
69 union regevent switch (int type) {
76 Correct erlang representations:
78 {1, {2, <<"hi mom">>}}
84 Each type in the .x file gets a enc_type/1 function:
85 enc_type(Term) -> IoList.
89 xx_xdr:enc_regevent({'EVENT_DELETE', 3}) ->
90 [<<0,0,0,2>>, <<0,0,0,3>>]
94 Each type in the .x file gets a dec_type/2 function:
95 dec_type(Bin, Offset) -> {Term, NewOffset}
97 The Offset is an offset in the Binary where to start decoding.
101 xx_xdr:dec_regevent(<<0,0,0,2,0,0,0,3>>, 0) ->
102 {{'EVENT_DELETE', 3}, 8}
103 xx_xdr:dec_regevent(<<1,2,3,4,0,0,0,2,0,0,0,3>>, 4) ->
104 {{'EVENT_DELETE', 3}, 12}
108 The library module rpc_client, and the generated xx_clnt module
109 provides complete client implementations for TCP and UDP.
111 The user must start a rpc_client process explicitly. Each
112 rpc_client process handles one RPC protocol over one socket only.
113 Each rpc_client can handle many erlang clients though - all calls
114 are multiplexed over the socket.
118 The following diagram illustrates the processes and modules
121 A user calls xx_clnt:xx_proc1_1(Term) in some process.
122 xx_clnt:xx_proc1_1(Term) calls xx_xdr:enc() to encode the Term into
123 a io list. This io list is passed to rpc_client:call(), which
124 performs a gen_server:call to the client process.
126 The client process constructs a rpc msg and sends it to the rpc
127 server over a socket. The reply is decoded by xx_clnt before it is
128 returned to the user.
131 xx_clnt.erl xx_xdr.erl
132 +--------------+ +----------+
133 | xx_proc1_1() | --> | enc() | rpc_client
134 | | <-- +----------+ process
135 | | gen_server:call +--------------+
136 | | ---------------------> | send rpc msg | ---> socket
137 | | <-------------------- | reply | <---
138 | | xx_xdr.erl +--------------+
151 open(Host, PrgNum, PrgVsn, Proto)
152 open(Host, PrgNum, PrgVsn, Proto, Port) ->
153 <suitable for a child to a supervisor>
156 If no Port is given, the client contacts the port mapper daemon
157 on the Host for the PrgNum and PrgVsn.
159 Note that this function returns a linked pid. If the socket is
160 closed, the pid exits.
163 Terminates the client.
165 <lots of control and statistics functions, see the code for
171 The library module rpc_server, and the generated xx_svc module
172 provides server implementations for TCP and UDP.
174 The server logic can be implemented in two different ways, either as
175 a gen_server process which receives all rpc requests as gen_server
176 calls, or as a rpc_server behaviour callback module. These variants
179 The user must start the rpc_server process explicitly. Each
180 rpc_server process is capable of handling both TCP and UDP at the
183 5.1. Server Implementations
185 5.1.1 gen_server implementation
187 The following diagram illustrates the processes and modules
190 A RPC client sends a RPC call on a socket. The rpc_server process
191 recieves the messages and decodes it. Then it calls the xx_svc
192 module, providing the procedure number and arguments. The xx_svc
193 module translates the procedure number to an erlang atom, calls
194 xx_xdr to decode parameters, then performs a gen_server:call to
195 the user defined server implementation.
199 +----------+ xx_svc.erl xx_xdr.erl
200 socket | | +----------+ +----------+ user's
201 ---> | | -> | xx_prog | -> | dec() | server
202 | | | | <- +----------+ process
203 | | | | gen_server:call +--------+
204 | | | | --------------> | |
205 | | | | <-------------- +--------+
207 | | | | -> +----------+
211 socket | | +----------+
215 Division of labor (on a per-process basis) (follow the arrows upward):
217 [--A---][------------------------B---------------------][---C----]
219 ... where A is the socket port, B is the generic rpc_server, and C is
220 the user-defined gen_server.
222 This is the most generic and transparent way of implementing an rpc
223 server. The drawback is that each rpc request (and its reply) is
224 sent as a message to the user's process. Furthermore, the user's
225 server process is a gen_server. By default, gen_servers can only
226 process one call at a time; this is a performance bottleneck when
227 dealing with multiple RPC clients simultaneously.
229 5.1.2. rpc_server implementation
231 The following diagram illustrates the processes and modules
234 A RPC client sends a RPC call on a socket. The rpc_server process
235 recieves the messages and decodes it. Then it calls the xx_svc
236 module, providing the procedure number and arguments. The xx_svc
237 module translates the procedure number to an erlang atom, calls
238 xx_xdr to decode parameters, then calls the user defined rpc_server
243 +----------+ xx_svc.erl xx_xdr.erl
244 socket | | +----------+ +----------+ user's
245 ---> | | -> | xx_prog | -> | dec() | rpc_server
246 | | | | <- +----------+ module
247 | | | | apply +--------+
248 | | | | ---------------> | |
249 | | | | <--------------- +--------+
251 | | | | -> +----------+
255 socket | | +----------+
259 Division of labor (on a per-process basis) (follow the arrows upward):
261 [--A---][------------------------B-------------------------------]
263 ... where A is the socket port, B is the generic rpc_server.
265 The advantage of this model is that no copies are made for the rpc
268 The rpc_server behaviour is decribed in 5.2.2.2
271 5.2.1.1 Multi-threaded rpc_server implementation
273 rpc_server allows the callback function return {noreply, S}.
274 This can be used to implement a multi-threaded rpc server:
277 This diagram extends the diagram above, not showing the leftmost
284 | | -----------------------------> spawn new proc
286 +--------+ +------------+
288 xx_xdr.erl rpc_server:reply | |
289 +--------+ <---------------- | |
290 | enc() | +------------+
291 sock <-------- +--------+
293 Division of labor (on a per-process basis) (follow the arrows upward):
296 [-------------------C------------------------]
297 [-------------------D------------------------]
298 [-------------------E------------------------]
300 ... where C,D, and E are dynamically spwawned processes for each, or
303 Note that the reply is sent directly to the socket, to via the
311 start_link(Protos, PrgNum, PrgName, PrgVsnLo, PrgVsnHi, Mod, InitArgs)
312 start_link(Name, Protos, PrgName, PrgNum, PrgVsnLo, PrgVsnHi, Mod, InitArgs) ->
313 <suitable for a child to a supervisor>
314 Name = see gen_server(3)
315 Protos = [{tcp|udp, Ip, Port, Pmap_p, SockOpts}]
316 XXX SLF Yes, putting the tuple inside a list is annoying,
317 but it's necessary unless I want to rip out the multiple
318 protocol-handling stuff in the bowels of the socket handler,
319 and since I don't fully understand how that stuff works,
320 I'll just leave it in for now. XXX SLF
321 Pmap_p = bool() if true, the server registers itself with
322 the local port mapper.
323 SockOpts = list of extra socket options (see the code)
324 PrgNum = int() RPC Program number
325 PrgName = atom() RPC Program name, used to construct the callback
326 function name in Mod to handle a particular RPC call.
328 PrgVsnHi = int() The server handles vsns in the interval Lo - Hi
329 Mod = atom() Dispatch module.
330 InitArgs = list(), passed to Mod:init/1.
333 Note that the client() datatype might contain temporary data
334 associated with the current client call, such as Xid. Thus, it
335 can't directly be used to identify a client. Use the access
336 functions described below to extract information from the
337 datatype. For example, client_ip() can be used to identify a
340 NOTE: The callback module described here is usually not written
341 by the user. Instead, give the name of the generated xx_svc
342 module here; it conforms to the interface defined above. For a
343 description of how to implement a server using xx_svc, see 5.2.2.
344 For completeness, the dispatch module API is described in 5.2.1.1.
346 Note on PrgName: This atom is used to construct the function name
347 in module Mod to handle an RPC call. That function is named
348 PrgNum_PrgVsn, e.g. name_4 for version RPC program version 4.
349 See 5.2.2.1 below for more information.
351 client_ip(Clnt) -> {ok, {Ip, Port}} | {error, Reason}
354 Can be used by a server implementation to get the Ip and Port of
357 client_socket(Clnt) -> Socket
360 Can be used by a server implementation to get the socket of the
361 current client. Note that for UDP, one socket is used for all
364 reply(Clnt, Reply) -> void()
367 Used to asynchronously send a rpc reply to a client. Can only be
368 used when a server is implemented with the rpc_server behaviour,
369 and a callback function returned {noreply, S'}.
371 5.2.1.1 Dispatch module
373 This is the API the dispatch module must follow. It's recommended
374 to use erpcgen to generate a xx_svc module (see 5.2.2), which is
375 used the dispatch module. xx_svc conforms to the API described
378 Mod:init/1, handle_call/3, handle_cast/2,
379 handle_info/2, terminate/2 -- like gen_server
381 These functions are called like the gen_server functions.
382 Specifically, the following functions are called:
383 Mod:handle_info({tcp_new, Sock}, State)
384 Mod:handle_info({tcp_closed, Sock}, State)
385 when a tcp client connects resp. disconnects.
387 Mod:ProgN(Proc,Bin,Offset,Clnt,State) ->
388 {success, Result, NState} |
391 {garbage_args, Nstate} |
393 ProgN = atom() on the form <program>_<program-vsn>
396 This function is called when a request is received for the
400 5.2.2 xx_svc callback API
402 5.2.2.1 gen_server implementation
404 If erpcgen is given the flag 'svc', the xx_svc module is generated
405 with functions that calls gen_server:call for each rpc request.
407 Thus, the user must define a gen_server process which must be
408 locally registered as xx_server. The following calls are defined:
410 {Procedure_PrgVsn, Arg1, Arg2, ..., Clnt}
411 Called when a client makes a RPC request the reply value is
412 the erlang representation of the return value for the
413 procedure. The reply is the return value of the rpc
416 The "Procedure" portion of the function name is taken from the
417 "program" directive in the RPC specification file, e.g.
423 ... will create a callback function mountprog_3/5.
425 The following messages are sent directly to the process:
428 when a tcp client is connected
431 when a tcp client closes it's socket
433 NOTE: The RPC server state variable State is not available to
434 gen_server implementations.
436 5.2.2.2 rpc_server implementation
438 If erpcgen is given the flag 'svc_callback', the xx_svc module is
439 generated with functions that calls a callback module each rpc
442 The rpc_server behaviour is like gen_server, with the follwoing
445 o The process must not change the trap_exit process flag. The
446 process traps exists.
448 o The process must not open tcp or udp sockets in active mode,
449 since the messages will interfere with the rpc messages.
451 o The callback module must be prepared to handle the messages
452 {tcp_new, Sock}, {tcp_closed, Sock}, and {tcp_error, Sock} in
453 its handle_info/2 function.
455 The callback module must export a function for each rpc procedure it
456 implements, in addition to the normal gen_server callbacks:
458 Procedure_PrgVsn({Arg1, ..., ArgN}, Clnt, S) ->
463 If {noreply, S'} is returned, the function rpc_server:reply() must
464 be called, not necessarily by the same process, to reply to the rpc
467 Typically, this method would be used by invoking erpcgen as:
469 erpcgen -a '[svc_callback,xdr]' foo.x
471 ... which will create foo_svc.erl and foo_xdr.erl.
472 rpc_server:start_link/7 would then be called with PrgName argument as
473 'ProgramDirective_PrgVsn'. XXX SLF This is complicated. Perhaps a
474 definition of terms at the beginning of this doc would help clear up which
475 name to use, the basename of the RPC spec file vs. the name specified by
476 the "program" directive inside the RPC spec file. XXX SLF
478 The foo_svc.erl file provides a layer of code that
483 1. Generate xx_clnt.erl, xx_xdr.erl, xx.hrl
486 rpc_client:open(Host, Program, Version, Proto)
487 rpc_client:open(Host, Program, Version, Proto, Port) ->
488 {ok, LinkedPid} | {error, Reason}
490 Note that the client pid is linked. The client exits if
491 the socket is closed or if there is any socket error.