1 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
2 <!ENTITY gras-DataDesc SYSTEM "sgml/DataDesc.sgml">
3 <!ENTITY gras-Globals SYSTEM "sgml/Globals.sgml">
4 <!ENTITY gras-Messages SYSTEM "sgml/Messages.sgml">
5 <!ENTITY gras-Socks SYSTEM "sgml/Socks.sgml">
7 <!ENTITY gras-err SYSTEM "sgml/core_err.sgml">
8 <!ENTITY gras-log SYSTEM "sgml/core_log.sgml">
9 <!ENTITY gras-dynar SYSTEM "sgml/core_dynar.sgml">
10 <!ENTITY gras-dico SYSTEM "sgml/core_dico.sgml">
11 <!ENTITY gras-cfg SYSTEM "sgml/core_cfg.sgml">
13 <!ENTITY gras-gras SYSTEM "sgml/gras.sgml">
14 <!ENTITY gras-gras-private SYSTEM "sgml/gras_private.sgml">
15 <!ENTITY gras-gras-rl SYSTEM "sgml/gras_rl.sgml">
16 <!ENTITY gras-gras-sg SYSTEM "sgml/gras_sg.sgml">
18 <!ENTITY overview SYSTEM "overview.sgml">
22 <title>Grid Reality And Simulation Reference Manual</title>
26 <title>GRAS user manual</title>
36 =head2 Sending (or receiving) dynamic sized arrays
38 To overcome the impossibility to send structure having dynamic-sized array,
39 it is possible to send several times the same structures, the number of time
40 being given in the header. The idea here is to say that we want to send a
41 C<STORE_STATE> message containing not one C<struct state> to store, but for
42 example three different C<state>s. We will come back on this in the next
45 =head1 Describing hosts
47 Before any GRAS communication, you have to do some initialization work. For
48 that, use the GRAS_EstablishHost() function.
50 GRAS_EstablishHost(char **addresses,
51 unsigned int addressesCount,
53 void (*initFunction)(void),
54 int (*exitFunction)(void),
55 unsigned int serveEvery,
56 GRAS_host_t *hostdescriptor);
58 It takes as argument the name (or IP) of the host on which you want to
59 establish this host (in RL, you may want to pass a list of all IP addresses
60 served by this host), the port on which it will listen by default, the init
61 and exit functions, how often (in millisecond) it will try to handle the
62 incoming requests and returns a descriptor to the newly created host
65 The init function is supposed to return to a userdata, which will be passed
66 to all functions, and which should contain the I<state> of your server, if
69 =head1 Preparing to accept incomming messages
71 To be able to accept any incomming messages, you have first to open a socket
72 in listening mode. For that, simply use the GRAS_IncomingSocket(). In RL,
73 GRAS try to bind() to the socket, and then accept(). In SG, it tries to lock
74 the given channel. Here is the prototype of this function.
77 GRAS_IncomingSocket(unsigned short startingPort,
78 unsigned short endingPort,
80 unsigned short *socketPort);
82 It tries to open an incoming socket on a port between C<startingPort> and
83 C<endingPort>, returns the created C<socket> and the C<socketPort> on which we
84 managed to create this socket. The return value of the function is true if we
85 managed to create it, and false if not.
87 =head1 Sending messages
89 Sending data is pretty simple. First, you have to create a outgoing socket,
90 and then use it as argument to the GRAS_SendMessage*() function.
92 GRAS_OutgoingSocket() can be used to build a new outgoing socket.
93 Alternatively, you can pass a reference to a Socket you know using
94 C<socketDescriptor> and C<socketDescriptorLength> in messages.
96 In fact, an outgoing socket is nothing more than an address to remote socket
97 openned in listing mode.
100 GRAS_OutgoingSocket(char *host,
104 Once you have a reference to the peer with which you want to communicate,
105 sending messages is as easy as using the GRAS_SendMessage() function.
108 GRAS_SendMessage(GRAS_Socket_t *sd,
115 C<GRAS_SendMessage> allows you to send a message with several sequence of
116 structures as payload. For each sequence, you have to pass three extra
117 arguments to the function. The prototype of those arguments would be:
120 const DataDescriptor *description,
123 This allows you to specify that the given sequence is a C<howMany>-long
124 array of structure described by C<description>, and stored at the memory
125 location pointed by C<data>.
127 This function is blocking until the message is actually sent, and you must
128 free the data when you're done with it.
130 =head1 Receiving messages
132 GRAS_IncomingSocket() prepared the host to receive messages, but did not
133 explain how to handle incoming messages. There is 3 kinds of handling to
138 =item default callback
140 you can register default callbacks to well known messages which will always
141 be handled the same way. This is for example used in the NWS memory server
142 to handle C<STORE_STATE> messages by actually writing the state on disk. For
143 that, use the function GRAS_RegisterListener() to register the function
144 C<listener> as listener to message type C<message> (which name to use in
145 debugging messages is C<name>).
147 typedef void (*GRAS_ListenerFunction)(GRAS_Socket_t *from,
153 GRAS_RegisterListener (int message,const char *name,
154 GRAS_ListenFunction listener);
156 The C<va> argument passed to the listener function is the pending of the
157 extra args passed to the GRAS_SendMessage function. That is to say that it
158 will contain C<sequence_count> sequence of data, each of them being
159 described by three arguments:
162 const DataDescriptor *description,
165 The data are allocated by GRAS for you when the message incomes, but must be
166 freed by you after use in the listener function.
168 =item Actually waiting for data
170 You can also ask to receive the next message of a given type. For example,
171 the sensor sending data to the memory using the C<STORE_STATE> message will
172 wait for an answer of the memory (which will use a C<STORED_STATE> to
173 indicate if the operation was successfull or not). For that, use the
174 GRAS_RecvMessage() function. If the next message to be received is not of
175 the waited type, this message is queued until we get the message we expect,
176 and handled afterward.
179 GRAS_RecvMessage(GRAS_Socket_t *sd,
185 Like always, sequence count is set to the number of sequences in the
186 message's payload, and the extra arguments should describe each sequence.
187 Their prototype will be:
190 const DataDescriptor **description,
193 Note that there is a level of indirection more than in previous functions,
194 since their values will be set by the GRAS_RecvMessage() function.
196 The C<data> fields are allocated by the GRAS_RecvMessage, and must be freed
199 =item one-way callback
201 As you can see, calling GRAS_RecvMessage() is blocking for that host in that
202 sense that no other messages can be server until the expected message is
203 received. To avoid that problem, it is possible to declare I<one-way
204 callback>. As GRAS_RecvMessage(), this is to be used when you wait for the
205 answer of a peer, but when you don't want to block on this. The handling of
206 the message (or of the associated timeout) have to be moved to another
207 function, which will be passed as callback to the expected message. This
208 allows GRAS to handle other incoming messages before the answer to the
209 request comes and improve the reactivity of code. Sadly, this makes the code
210 quite difficult to read and maintain...
213 GRAS_RegisterOneWayListener (int message,const char *name,
214 GRAS_ListenerFunction listener);
216 If you do several calls to this function for the same message, callbacks are
217 stacked, and their use will pop this stack. It is possible to use this
218 function to interceipt messages having a default callback.
222 =head1 Handling computation
224 SG is a simulator, and you when you simulate a computationnal server, you
225 don't want to see him actually doing the computation, rather, you want to
226 see this work I<simulated>.
228 For that, use the GRAS_computation() macro. If running in RL, the provided
229 code will actually be done, and if running SG, a task of the provided
230 C<size> will be scheduled on the host (and the computation done will be the
231 one passed in the else branch).
233 GRAS_computation_if_RL(size) {
234 code to execute when running in RL;
236 code to execute when running in SG;
239 If running RL, this macro will be rewritten to
243 and if running SG, this macro will be rewritten to
245 if (<code to simulate the task>, 0)
249 We belive that the sort of raw RPC we presented here permits to run the same
250 code both in RL and SG because GRAS will do the unpleasant job of moving
251 data from one namespace to another if needed, sending it over the network if
254 GRAS Agents never really define the main function. The main function you
255 write in your code does only call to GRAS_EstablishHost(), which is in
256 charge of initializing the GRAS mecanism on the right hosts.
264 Make sure this proposal is more or less flawless. That's a RFC ;)
266 We could go one step further on the main() problem, by using the SG scenario
267 files, and a way to actuate it in RL.
273 In RL, it should pretty straightforward, since GRAS functions are more or
274 less wrappers to the NWS communication library.
276 In SG, it shouldn't be that difficult either ;)
285 <title>GRAS toolbox</title>
294 <title>GRAS implementation</title>