blob: 378d59d2eb5d33da4127234df57e6091e92b10e7 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001CONCEPT
2 erq - External Request Demon
3
4DESCRIPTION
5 Up to version 3.2.1@61, LPMud utilized two external programs
6 in an ad-hoc manner to solve problems: the 'hname' program to
7 resolve IP addresses into meaningful hostnames, and the
8 'indent' program to properly indent LPC files.
9 In version 3.2.1@61 both functions were united in a
10 generalized 'erq' process, to which additional functions may
11 be attached. Unfortunately it was never documented by Amylaar,
12 so the information presented here had to be reverse engineered
13 from the sources - better take it with a grain of salt.
14
15 The erq feature is available if the driver is compiled with
16 ERQ_DEMON defined (in config.h).
17
18 When the driver starts up, it tries to fork off the program
19 'BINDIR/erq --forked <other args>' (with BINDIR defined in
20 the Makefile). If this succeeds, the erq may talk with
21 the driver through stdin and stdout (piped through AF_UNIX
22 sockets). The erq has to signal its successfull start by
23 writing the character '1' back to the driver.
24
25 The erq has to understand these commandline arguments:
26
27 --forked: explained above
28 --execdir <dir>: The directory where the callable executables
29 can be found. If not specified, ERQ_DIR is used.
30 <dir> must not end in a '/' and should be absolute.
31
32 At runtime, the erq may be changed/removed from within the
33 mudlib using the efun attach_erq_demon(). This efun is given
34 an interactive object as argument, and takes the connection
35 away(!) from this object and stores it as the erq connection
36 to use (an old erq connection is closed first). The object
37 (which now no longer is interactive) is then no longer needed,
38 but may continue to exist.
39 The erq attached this way of course has to use the sockets it
40 opened to communicate with the driver.
41
42 Most of the communication between erq and driver is going to
43 be initiated by the driver (the erq has to look up the
44 hostnames for given IP addresses), but using the efun
45 send_erq() the mudlib may talk with the erq as well.
46
47 The communication between driver and erq is done using
48 messages of specified structures and constants (defined in
49 util/erq.h resp. sys/erq.h). The 'int32's are signed integers
50 of four byte length, and are sent with the MSByte first.
51 Every message must be sent atomically!
52
53 The head of the messages is always the same:
54
55 struct erq_msghead {
56 int32 msglen; /* Total size of message in bytes */
57 int32 handle; /* Identification number */
58 }
59
60 The 'handle' number is set by the driver (do not make
61 assumptions about its value) and is used to associated the erq
62 responses with the pending requests. This way the erq is free
63 to respond in an order different to those of the incoming
64 requests.
65
66 The messages send to the erq follow this symbolic format:
67
68 struct to_erq_msg {
69 int32 msglen;
70 int32 handle;
71 char request;
72 char data[0];
73 }
74
75 The 'request' denotes which service is requested from the erq,
76 the size and content of 'data' depends on the requested
77 service.
78
79 The answer message from the erq to the driver (if there is one
80 at all) may have two forms:
81
82 struct from_erq_msg {
83 int32 msglen;
84 int32 handle;
85 char data[0];
86 }
87
88 struct from_erq_keep_msg {
89 int32 msglen;
90 const int32 keep = ERQ_KEEP_HANDLE;
91 int32 handle;
92 char data[0];
93 }
94
95 The replied data from the erq is stored in 'data', which size
96 and content depends on the request answered. The answer is
97 identified by 'header.handle'. Normally, one request results
98 in just one response sent by the erq using struct from_erq_msg,
99 so the handle is recycled after this response.
100 Shall the erq send several responses (or break one response
101 into several parts), the struct from_erq_keep_msg has to be
102 used for all but the last response - this message with its
103 included special handle keeps the real handle alive.
104
105
106 Mudlib generated erq-calls specify the 'request' and the
107 'data' to be sent, and receive the 'data' replied. When
108 dealing with spawned programs, the first byte of the returned
109 'data' determines the content type of the received message.
110 The actual 'data' which the lpc programs get to see is sent
111 and retrieved as arrays of byte integers (integers in the
112 range of 0..255).
113
114
115 The actual interface between erq demon and driver is limited
116 to the general message formats and the hostname lookup
117 mechanism. The driver is meant to withstand erq demon failures
118 at least in a garbage-in garbage-out fashion. You could add
119 new requests to the erq demon, or write your own from scratch,
120 without changing the driver.
121
122
123 Currently five services are predefined in the supplied
124 erq-demon (util/erq.c in the driver source archive): looking
125 up a hostname, execution, forking or spawning an external
126 program, authentification of a connection, and handling of
127 external UDP/TCP connections. As mentioned above, only the
128 hostname-lookup is a true must.
129
130 For a program to be executable for erq, it must be placed in
131 or below ERQ_DIR (defined in config.h). On most unix systems,
132 it is possible to use a symlink instead of the whole program
133 if you want a standard binary. You could even symlink entire
134 directories like /usr/sbin, but chances are you make a big
135 security hole this way :-)
136
137
138 Hostname lookup:
139
140 request : ERQ_RLOOKUP
141 data sent: struct in_addr.s_addr addr // the address to resolve
142 data recv: struct in_addr.s_addr addr // the resolved address
143 char[] name // the hostname (if any)
144
145 If the sent address can't be resolved, just the address is
146 to be returned. The string need not be 0-terminated.
147
148
149 Hostname lookup:
150
151 request : ERQ_LOOKUP
152 data sent: char[] name // the name to resolve
153 data recv: struct in_addr.s_addr addr // the resolved address
154
155 If the sent address can't be resolved, no data is returned (the
156 driver will get a message with just the header).
157
158
159 Hostname lookup - IPv6:
160
161 request : ERQ_RLOOKUPV6
162 data sent: char[] addr // the address to resolve
163 data recv: char[] data // the resolved name
164
165 If the address could be resolved, the returned data is a string,
166 with exactly one space, in the form "<addr> <name>". <addr> is
167 the address passed to the erq, <name> is the hostname of the
168 address or, if there is no reverse-IPv6 entry for <addr>, the
169 IPv6 address which may or may not be different from <addr>.
170
171 If the address can not be resolved, the returned data is
172 an error message without a space (currently, just "invalid-format"
173 and "out-of-memory" are returned).
174
175
176 Execute/Fork program:
177
178 request : ERQ_EXECUTE/ERQ_FORK
179 data sent: char[] command // the command to execute
180 data recv: char status = CHILD_FREE
181 char rc // the success/error code
182 char info // additional information
183
184 The erq executes the sent command using the execv().
185 The erq does the processing of the command line arguments
186 (which must not contain '\') and checks the validity of the
187 command (it must not start with '/' nor contain '..'), which
188 is interpreted relative to ERQ_DIR.
189 The external program is executed from a fork()ed instance of
190 the erq, however, with ERQ_EXECUTE the erq waits until the
191 external program finished before replying its response, with
192 ERQ_FORK the response is immediately sent back.
193
194 Possible return codes are:
195 ERQ_OK : Operation succeeded.
196 ERQ_E_ARGLENGTH: Too long command.
197 ERQ_E_ARGFORMAT: Illegal argument given (contains '\');
198 ERQ_E_ARGNUMBER: Too much arguments (>= 96).
199 ERQ_E_ILLEGAL : Command from outside ERQ_DIR requested.
200 ERQ_E_PATHLEN : Commandpath too long.
201 ERQ_E_FORKFAIL : Command could not be forked;
202 info holds the errno value.
203
204 ERQ_EXECUTE features some more return codes:
205 ERQ_OK : Operation succeeded, <info> holds the exit status.
206 ERQ_SIGNALED : Command terminated the signal <info>.
207 ERQ_E_NOTFOUND : No process found to wait() for.
208 ERQ_E_UNKNOWN : Unknown exit condition from wait().
209
210
211 Spawn program:
212
213 request : ERQ_SPAWN
214 data sent: char[] command // the command to execute
215 data recv: Spawn failed:
216 char rc // the error code (see ERQ_FORK)
217 char info // additional information
218 data recv: Spawn succeeded:
219 char rc = ERQ_OK
220 char[] ticket // the spawn ticket.
221
222 The erq executes the sent command as if given an ERQ_FORK
223 command, but returns additional information about the
224 started process to allow further communication.
225 In contrast to ERQ_FORK, ERQ_SPAWNED processes may be
226 controlled via ERQ_KILL, receive data from the mud via
227 ERQ_SEND on their stdin, and output from their stdout/stderr
228 is sent back to the mud.
229 The spawned process is identified by its <ticket> (don't
230 make any assumptions about its length or content), the transaction
231 itself by <handle>.
232
233
234 Send data to spawned program:
235
236 request : ERQ_SEND
237 data sent: char[] ticket // the addressed process ticket.
238 char[] text // the text to send.
239 data recv: char rc // the success/error code.
240 int32 info // opt: additional info.
241
242 The <text> is sent to the stdin of the spawned process
243 identified by <ticket>.
244
245 Possible return codes are:
246 ERQ_OK : Operation succeeded, no <info> is replied.
247 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
248 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
249 sent.
250 If a callback is specified, the erq will send
251 a ERQ_OK message once all data has been sent
252 (this may never happen).
253 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
254 happened while sending the text.
255 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
256 happened while sending the text.
257 ERQ_E_UNKNOWN : The error with code <info> happened
258 while sending the data.
259
260 Amylaar-erq doesn't try to re-send the remaining data after
261 a ERQ_E_INCOMPLETE, so there will never be an ERQ_OK.
262
263
264 Send a signal to a spawned program:
265
266 request : ERQ_KILL
267 data sent: char[] ticket // the addressed process ticket
268 int32 signal // the signal to send
269 data recv: char rc // the success/error code
270
271 The <signal> is sent to the spawned process identified by <ticket>.
272
273 Possible return codes are:
274 ERQ_OK : Operation succeeded, no <info> is replied.
275 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
276 ERQ_E_ILLEGAL : The given signal is illegal.
277
278
279 Data replies from spawned programs:
280
281 data recv: char out_or_err // type of text output
282 char[] text // text output by child process
283
284 The child process controlled by the erq did output <text>
285 on stdout (<out_or_err> == ERQ_STDOUT) resp. on stderr
286 (<out_or_err> == ERQ_STDERR).
287
288
289 Exit notifications from spawned programs:
290
291 data recv: char rc // the exit code
292 char info // additional information.
293
294 The child process controlled by the erq did terminate.
295 Possible exit codes are:
296 ERQ_EXITED : Process exited with status <info>.
297 ERQ_SIGNALED : Process terminated by signal <info>.
298 ERQ_E_UNKNOWN : Process terminated for unknown reason.
299
300
301 Authentificate connection (see rfc 931):
302
303 request : ERQ_AUTH
304 data sent: struct sockaddr_in remote // the address to check
305 int32 port // the mud port
306 or
307 data sent: int32 remote_ip // remote ip to check
308 int16 remote_port // remote port to check
309 int16 local_port // the mud port
310
311 data recv: char[] reply // the data received by authd
312
313 The erq attempts to connect the authd on the remote system
314 and to verify the connection between the remote port and the
315 mud port. The latter will normally be the port number of the
316 socket on besides of the gamedriver, retrieveable by
317 query_ip_number().
318
319 The answer from the authd (one line of text) if there is any
320 is returned as result.
321
322 The second form of the ERQ_AUTH command is recognized by
323 the xerq as alternative.
324
325
326 Open an UPD port:
327
328 request : ERQ_OPEN_UDP
329 data sent: char[2] port // the port number to open (network order)
330 data recv: Open failed:
331 char rc // the success/error code.
332 char info // opt: additional info.
333 data recv: Open succeeded:
334 char rc = ERQ_OK
335 char[] ticket // the connection ticket.
336
337 The erq opens an UDP-port on the host machine with the given
338 port number.
339 Possible exit codes are:
340 ERQ_OK : Operation succeeded.
341 ERQ_E_ARGLENGTH : The port number given does not consist
342 of two bytes.
343 ERQ_E_NSLOTS : The max number of child processes (given
344 in <info>) is exhausted.
345 ERQ_E_UNKNOWN : Error <info> occured in one of the system
346 calls done to open the port.
347
348 Once the port is open, it is treated as if is just another
349 spawned program.
350
351
352 Send data over an UDP port:
353
354 request : ERQ_SEND
355 data sent: char[] ticket // the addressed port's ticket.
356 struct in_addr.s_addr addr // address of receiver.
357 struct addr.sin_port port // port of receiver.
358 char[] text // the text to send.
359 data recv: char rc // the success/error code.
360 int32 info // opt: additional info.
361
362 The <text> is sent from our port <ticket> to the network
363 address <addr>, port <port>.
364
365 Possible return codes are:
366 ERQ_OK : Operation succeeded, no <info> is replied.
367 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
368 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
369 sent. The erq will send a ERQ_OK message
370 once all data has been sent.
371 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
372 happened while sending the text.
373 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
374 happened while sending the text.
375 ERQ_E_UNKNOWN : The error with code <info> happened
376 while sending the data.
377
378
379 Close an UDP port:
380
381 request : ERQ_KILL
382 data sent: char[] ticket // the addressed port's ticket
383 int32 signal // the signal to send (ignored)
384 data recv: char rc = ERQ_OK
385
386 The port <ticket> is closed. The <signal> must be sent, but
387 its value is ignored.
388
389
390 Data received over an UDP connection:
391
392 data recv: char out_or_err = ERQ_STDOUT
393 struct in_addr.s_addr addr // ip-address of sender
394 struct addr.sin_port port // port of sender
395 char[] text // data received
396
397 The UPD port controlled by the erq did receive <text> over
398 the network from the sender at <addr>, reply port number <port>.
399
400
401 Open an TCP to listen for connections:
402
403 request : ERQ_LISTEN
404 data sent: struct addr.sin_port port // the port number to open
405 data recv: Open failed:
406 char rc // the success/error code.
407 char info // opt: additional info.
408 data recv: Open succeeded:
409 char rc = ERQ_OK
410 char[] ticket // the connection ticket.
411
412 The erq opens an TCP-port on the host machine with the given
413 port number to listen for connections.
414 Possible exit codes are:
415 ERQ_OK : Operation succeeded.
416 ERQ_E_ARGLENGTH : The port number given does not consist
417 of two bytes.
418 ERQ_E_NSLOTS : The max number of child processes (given
419 in <info>) is exhausted.
420 ERQ_E_UNKNOWN : Error <info> occured in one of the system
421 calls done to open the port.
422
423 Once the port is open, it is treated as if is just another
424 spawned program.
425
426
427 Open an TCP port:
428
429 request : ERQ_OPEN_TCP
430 data sent: struct in_addr.s_addr ip // the ip to address
431 struct addr.sin_port port // the port to address
432 data recv: Open failed:
433 char rc // the success/error code.
434 char info // opt: additional info.
435 data recv: Open succeeded:
436 char rc = ERQ_OK
437 char[] ticket // the connection ticket.
438
439 The erq opens an TCP-port on the host machine and tries to connect
440 it to the address <ip>:<port>.
441 Possible exit codes are:
442 ERQ_OK : Operation succeeded.
443 ERQ_E_ARGLENGTH : The port number given does not consist
444 of two bytes.
445 ERQ_E_NSLOTS : The max number of child processes (given
446 in <info>) is exhausted.
447 ERQ_E_UNKNOWN : Error <info> occured in one of the system
448 calls done to open the port.
449
450 Once the port is open, it is treated as if is just another
451 spawned program.
452
453
454 Send data over a TCP connection:
455
456 request : ERQ_SEND
457 data sent: char[] ticket // the addressed process ticket.
458 char[] text // the text to send.
459 data recv: char rc // the success/error code.
460 int32 info // opt: additional info.
461
462 The <text> is sent to the stdin of the spawned process
463 identified by <ticket>.
464
465 Possible return codes are:
466 ERQ_OK : Operation succeeded, no <info> is replied.
467 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
468 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
469 sent. The erq will send a ERQ_OK message
470 once all data has been sent.
471 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
472 happened while sending the text.
473 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
474 happened while sending the text.
475 ERQ_E_UNKNOWN : The error with code <info> happened
476 while sending the data.
477
478
479 Data ready to read on TCP connection:
480
481 data recv: char out_or_err = ERQ_OK
482 char[] ticket // ticket of this connection
483
484 There is data available to read on the specified TCP connection.
485
486
487 Data received over a TCP connection:
488
489 data recv: char out_or_err = ERQ_STDOUT
490 char[] text // data received
491
492 The TCP port controlled by the erq did receive <text>.
493
494
495 TCP connection closes on error:
496
497 data recv: char out_or_err = ERQ_E_UNKNOWN
498 char errno // errno from socket operation
499
500 The TCP connection caused an error <errno> and has been closed.
501
502
503 TCP connection closed:
504
505 data recv: char out_or_err = ERQ_EXITED
506
507 The TCP connection closed regularily (End Of File).
508
509
510 Connection pending on TCP socket:
511
512 data recv: char out_or_err = ERQ_STDOUT
513
514 The TCP 'listen' port controlled by the erq received
515 a connection request.
516
517
518 Accept a pending connections:
519
520 request : ERQ_ACCEPT
521 data sent: char[] ticket // the ticket of this socket
522 data recv: Accept failed:
523 char rc // the success/error code.
524 char info // opt: additional info.
525 data recv: Accept succeeded:
526 char rc = ERQ_OK
527 struct in_addr.s_addr ip // remote side's ip
528 struct addr.sin_port port // remote side's port
529 char[] ticket // the new ticket.
530
531 The erq accepts a new connection on an accept-TCP-port, creates
532 an child and ticket for it and returns its ticket together with
533 the remote's side <ip>:<port> number (in network byte order).
534 Possible exit codes are:
535 ERQ_OK : Operation succeeded.
536 ERQ_E_ARGLENGTH : The port number given does not consist
537 of two bytes.
538 ERQ_E_NSLOTS : The max number of child processes (given
539 in <info>) is exhausted.
540 ERQ_E_TICKET : the ticket didn't match
541 ERQ_E_UNKNOWN : Error <info> occured in one of the system
542 calls done to open the port.
543
544 Once the port is open, it is treated as if is just another
545 spawned program.
546
547
548EXAMPLE
549 Assume you have a script 'welcome-mail' to send a welcome mail
550 to a new player. Put this script into the directory for the callable
551 executables, then you can use it like this:
552
553 void erq_response(mixed * data)
554 {
555 write_file( "WELCOMELOG"
556 , sprintf("rc %d, info %d\n", data[0], data[1]));
557 }
558
559 void send_mail(string player_name, string player_email)
560 {
561 send_erq( ERQ_EXECUTE
562 , "welcome-mail '"+player_name+"' '"+player_email+"'"
563 , #'erq_response);
564 }
565
566
567HISTORY
568 The erq was introduced with 3.2.1@61.
569 ERQ_AUTH was introduced with 3.2.1@81.
570 ERQ_SEND, ERQ_SPAWN, ERQ_KILL were introduced with 3.2.1@82.
571 ERQ_OPEN_UDP, ERQ_OPEN_TCP, ERQ_LIST were introduced with 3.2.1@98.
572 ERQ_RLOOKUPV6 was introduced in 3.2.8.
573 LDMud 3.2.9 added the '--execdir' argument to erq, and the ERQ_OK
574 after ERQ_E_INCOMPLETE protocol.
575
576SEE ALSO
577 attach_erq_demon(E), send_erq(E), stale_erq(M), rfc 931
578 query_ip_number(E)