blob: 8db9216a59c59d8dda8533ce6c8f97c7d54c8a17 [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
Zesstra7ea4a032019-11-26 20:11:40 +01008 'indent' program to properly indent LPC files. In version
9 3.2.1@61 both functions were united in a generalized 'erq'
10 process, to which additional functions may be attached.
11 Unfortunately it was never documented by Amylaar, so the
12 information presented here had to be reverse engineered
MG Mud User88f12472016-06-24 23:31:02 +020013 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
Zesstra7ea4a032019-11-26 20:11:40 +010037 (which is now no longer is interactive) is then no longer
38 needed, but may continue to exist. The erq attached this way
39 of course has to use the sockets it opened to communicate
40 with the driver.
MG Mud User88f12472016-06-24 23:31:02 +020041
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.
Zesstra7ea4a032019-11-26 20:11:40 +0100100
MG Mud User88f12472016-06-24 23:31:02 +0200101 Shall the erq send several responses (or break one response
102 into several parts), the struct from_erq_keep_msg has to be
103 used for all but the last response - this message with its
104 included special handle keeps the real handle alive.
105
106
107 Mudlib generated erq-calls specify the 'request' and the
108 'data' to be sent, and receive the 'data' replied. When
109 dealing with spawned programs, the first byte of the returned
110 'data' determines the content type of the received message.
111 The actual 'data' which the lpc programs get to see is sent
112 and retrieved as arrays of byte integers (integers in the
113 range of 0..255).
114
115
116 The actual interface between erq demon and driver is limited
117 to the general message formats and the hostname lookup
118 mechanism. The driver is meant to withstand erq demon failures
119 at least in a garbage-in garbage-out fashion. You could add
120 new requests to the erq demon, or write your own from scratch,
121 without changing the driver.
122
123
124 Currently five services are predefined in the supplied
125 erq-demon (util/erq.c in the driver source archive): looking
126 up a hostname, execution, forking or spawning an external
127 program, authentification of a connection, and handling of
128 external UDP/TCP connections. As mentioned above, only the
129 hostname-lookup is a true must.
130
131 For a program to be executable for erq, it must be placed in
132 or below ERQ_DIR (defined in config.h). On most unix systems,
133 it is possible to use a symlink instead of the whole program
134 if you want a standard binary. You could even symlink entire
135 directories like /usr/sbin, but chances are you make a big
136 security hole this way :-)
137
138
139 Hostname lookup:
140
141 request : ERQ_RLOOKUP
142 data sent: struct in_addr.s_addr addr // the address to resolve
143 data recv: struct in_addr.s_addr addr // the resolved address
144 char[] name // the hostname (if any)
145
146 If the sent address can't be resolved, just the address is
147 to be returned. The string need not be 0-terminated.
148
149
150 Hostname lookup:
151
152 request : ERQ_LOOKUP
153 data sent: char[] name // the name to resolve
154 data recv: struct in_addr.s_addr addr // the resolved address
155
156 If the sent address can't be resolved, no data is returned (the
157 driver will get a message with just the header).
158
159
160 Hostname lookup - IPv6:
161
162 request : ERQ_RLOOKUPV6
163 data sent: char[] addr // the address to resolve
164 data recv: char[] data // the resolved name
165
166 If the address could be resolved, the returned data is a string,
167 with exactly one space, in the form "<addr> <name>". <addr> is
168 the address passed to the erq, <name> is the hostname of the
169 address or, if there is no reverse-IPv6 entry for <addr>, the
170 IPv6 address which may or may not be different from <addr>.
171
172 If the address can not be resolved, the returned data is
173 an error message without a space (currently, just "invalid-format"
174 and "out-of-memory" are returned).
175
176
177 Execute/Fork program:
178
179 request : ERQ_EXECUTE/ERQ_FORK
180 data sent: char[] command // the command to execute
181 data recv: char status = CHILD_FREE
182 char rc // the success/error code
183 char info // additional information
184
185 The erq executes the sent command using the execv().
186 The erq does the processing of the command line arguments
187 (which must not contain '\') and checks the validity of the
188 command (it must not start with '/' nor contain '..'), which
189 is interpreted relative to ERQ_DIR.
190 The external program is executed from a fork()ed instance of
191 the erq, however, with ERQ_EXECUTE the erq waits until the
192 external program finished before replying its response, with
193 ERQ_FORK the response is immediately sent back.
194
195 Possible return codes are:
196 ERQ_OK : Operation succeeded.
197 ERQ_E_ARGLENGTH: Too long command.
198 ERQ_E_ARGFORMAT: Illegal argument given (contains '\');
199 ERQ_E_ARGNUMBER: Too much arguments (>= 96).
200 ERQ_E_ILLEGAL : Command from outside ERQ_DIR requested.
201 ERQ_E_PATHLEN : Commandpath too long.
202 ERQ_E_FORKFAIL : Command could not be forked;
203 info holds the errno value.
204
205 ERQ_EXECUTE features some more return codes:
206 ERQ_OK : Operation succeeded, <info> holds the exit status.
207 ERQ_SIGNALED : Command terminated the signal <info>.
208 ERQ_E_NOTFOUND : No process found to wait() for.
209 ERQ_E_UNKNOWN : Unknown exit condition from wait().
210
211
212 Spawn program:
213
214 request : ERQ_SPAWN
215 data sent: char[] command // the command to execute
216 data recv: Spawn failed:
217 char rc // the error code (see ERQ_FORK)
218 char info // additional information
219 data recv: Spawn succeeded:
220 char rc = ERQ_OK
221 char[] ticket // the spawn ticket.
222
223 The erq executes the sent command as if given an ERQ_FORK
224 command, but returns additional information about the
225 started process to allow further communication.
226 In contrast to ERQ_FORK, ERQ_SPAWNED processes may be
227 controlled via ERQ_KILL, receive data from the mud via
228 ERQ_SEND on their stdin, and output from their stdout/stderr
229 is sent back to the mud.
230 The spawned process is identified by its <ticket> (don't
231 make any assumptions about its length or content), the transaction
232 itself by <handle>.
233
234
235 Send data to spawned program:
236
237 request : ERQ_SEND
238 data sent: char[] ticket // the addressed process ticket.
239 char[] text // the text to send.
240 data recv: char rc // the success/error code.
241 int32 info // opt: additional info.
242
243 The <text> is sent to the stdin of the spawned process
244 identified by <ticket>.
245
246 Possible return codes are:
247 ERQ_OK : Operation succeeded, no <info> is replied.
248 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
249 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
250 sent.
251 If a callback is specified, the erq will send
252 a ERQ_OK message once all data has been sent
253 (this may never happen).
254 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
255 happened while sending the text.
256 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
257 happened while sending the text.
258 ERQ_E_UNKNOWN : The error with code <info> happened
259 while sending the data.
260
261 Amylaar-erq doesn't try to re-send the remaining data after
262 a ERQ_E_INCOMPLETE, so there will never be an ERQ_OK.
263
264
265 Send a signal to a spawned program:
266
267 request : ERQ_KILL
268 data sent: char[] ticket // the addressed process ticket
269 int32 signal // the signal to send
270 data recv: char rc // the success/error code
271
272 The <signal> is sent to the spawned process identified by <ticket>.
273
274 Possible return codes are:
275 ERQ_OK : Operation succeeded, no <info> is replied.
276 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
277 ERQ_E_ILLEGAL : The given signal is illegal.
278
279
280 Data replies from spawned programs:
281
282 data recv: char out_or_err // type of text output
283 char[] text // text output by child process
284
285 The child process controlled by the erq did output <text>
286 on stdout (<out_or_err> == ERQ_STDOUT) resp. on stderr
287 (<out_or_err> == ERQ_STDERR).
288
289
290 Exit notifications from spawned programs:
291
292 data recv: char rc // the exit code
293 char info // additional information.
294
295 The child process controlled by the erq did terminate.
296 Possible exit codes are:
297 ERQ_EXITED : Process exited with status <info>.
298 ERQ_SIGNALED : Process terminated by signal <info>.
299 ERQ_E_UNKNOWN : Process terminated for unknown reason.
300
301
Zesstra7ea4a032019-11-26 20:11:40 +0100302 Authenticate connection (see rfc 931):
MG Mud User88f12472016-06-24 23:31:02 +0200303
304 request : ERQ_AUTH
305 data sent: struct sockaddr_in remote // the address to check
306 int32 port // the mud port
307 or
308 data sent: int32 remote_ip // remote ip to check
309 int16 remote_port // remote port to check
310 int16 local_port // the mud port
311
312 data recv: char[] reply // the data received by authd
313
314 The erq attempts to connect the authd on the remote system
315 and to verify the connection between the remote port and the
316 mud port. The latter will normally be the port number of the
Zesstra7ea4a032019-11-26 20:11:40 +0100317 socket on besides of the gamedriver, retrievable by
MG Mud User88f12472016-06-24 23:31:02 +0200318 query_ip_number().
319
320 The answer from the authd (one line of text) if there is any
321 is returned as result.
322
323 The second form of the ERQ_AUTH command is recognized by
324 the xerq as alternative.
325
326
Zesstra7ea4a032019-11-26 20:11:40 +0100327 Open an UDP port:
MG Mud User88f12472016-06-24 23:31:02 +0200328
329 request : ERQ_OPEN_UDP
330 data sent: char[2] port // the port number to open (network order)
331 data recv: Open failed:
332 char rc // the success/error code.
333 char info // opt: additional info.
334 data recv: Open succeeded:
335 char rc = ERQ_OK
336 char[] ticket // the connection ticket.
337
338 The erq opens an UDP-port on the host machine with the given
339 port number.
340 Possible exit codes are:
341 ERQ_OK : Operation succeeded.
342 ERQ_E_ARGLENGTH : The port number given does not consist
343 of two bytes.
344 ERQ_E_NSLOTS : The max number of child processes (given
345 in <info>) is exhausted.
Zesstra7ea4a032019-11-26 20:11:40 +0100346 ERQ_E_UNKNOWN : Error <info> occurred in one of the system
MG Mud User88f12472016-06-24 23:31:02 +0200347 calls done to open the port.
348
349 Once the port is open, it is treated as if is just another
350 spawned program.
351
352
353 Send data over an UDP port:
354
355 request : ERQ_SEND
356 data sent: char[] ticket // the addressed port's ticket.
357 struct in_addr.s_addr addr // address of receiver.
358 struct addr.sin_port port // port of receiver.
359 char[] text // the text to send.
360 data recv: char rc // the success/error code.
361 int32 info // opt: additional info.
362
363 The <text> is sent from our port <ticket> to the network
364 address <addr>, port <port>.
365
366 Possible return codes are:
367 ERQ_OK : Operation succeeded, no <info> is replied.
368 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
369 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
370 sent. The erq will send a ERQ_OK message
371 once all data has been sent.
372 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
373 happened while sending the text.
374 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
375 happened while sending the text.
376 ERQ_E_UNKNOWN : The error with code <info> happened
377 while sending the data.
378
379
380 Close an UDP port:
381
382 request : ERQ_KILL
383 data sent: char[] ticket // the addressed port's ticket
384 int32 signal // the signal to send (ignored)
385 data recv: char rc = ERQ_OK
386
387 The port <ticket> is closed. The <signal> must be sent, but
388 its value is ignored.
389
390
391 Data received over an UDP connection:
392
393 data recv: char out_or_err = ERQ_STDOUT
394 struct in_addr.s_addr addr // ip-address of sender
395 struct addr.sin_port port // port of sender
396 char[] text // data received
397
398 The UPD port controlled by the erq did receive <text> over
399 the network from the sender at <addr>, reply port number <port>.
400
401
Zesstra7ea4a032019-11-26 20:11:40 +0100402 Open a TCP port to listen for connections:
MG Mud User88f12472016-06-24 23:31:02 +0200403
404 request : ERQ_LISTEN
405 data sent: struct addr.sin_port port // the port number to open
406 data recv: Open failed:
407 char rc // the success/error code.
408 char info // opt: additional info.
409 data recv: Open succeeded:
410 char rc = ERQ_OK
411 char[] ticket // the connection ticket.
412
Zesstra7ea4a032019-11-26 20:11:40 +0100413 The erq opens a TCP-port on the host machine with the given
MG Mud User88f12472016-06-24 23:31:02 +0200414 port number to listen for connections.
415 Possible exit codes are:
416 ERQ_OK : Operation succeeded.
417 ERQ_E_ARGLENGTH : The port number given does not consist
418 of two bytes.
419 ERQ_E_NSLOTS : The max number of child processes (given
420 in <info>) is exhausted.
Zesstra7ea4a032019-11-26 20:11:40 +0100421 ERQ_E_UNKNOWN : Error <info> occurred in one of the system
MG Mud User88f12472016-06-24 23:31:02 +0200422 calls done to open the port.
423
424 Once the port is open, it is treated as if is just another
425 spawned program.
426
427
Zesstra7ea4a032019-11-26 20:11:40 +0100428 Open a TCP port:
MG Mud User88f12472016-06-24 23:31:02 +0200429
430 request : ERQ_OPEN_TCP
431 data sent: struct in_addr.s_addr ip // the ip to address
432 struct addr.sin_port port // the port to address
433 data recv: Open failed:
434 char rc // the success/error code.
435 char info // opt: additional info.
436 data recv: Open succeeded:
437 char rc = ERQ_OK
438 char[] ticket // the connection ticket.
439
Zesstra7ea4a032019-11-26 20:11:40 +0100440 The erq opens a TCP-port on the host machine and tries to connect
MG Mud User88f12472016-06-24 23:31:02 +0200441 it to the address <ip>:<port>.
442 Possible exit codes are:
443 ERQ_OK : Operation succeeded.
444 ERQ_E_ARGLENGTH : The port number given does not consist
445 of two bytes.
446 ERQ_E_NSLOTS : The max number of child processes (given
447 in <info>) is exhausted.
Zesstra7ea4a032019-11-26 20:11:40 +0100448 ERQ_E_UNKNOWN : Error <info> occurred in one of the system
MG Mud User88f12472016-06-24 23:31:02 +0200449 calls done to open the port.
450
451 Once the port is open, it is treated as if is just another
452 spawned program.
453
454
455 Send data over a TCP connection:
456
457 request : ERQ_SEND
458 data sent: char[] ticket // the addressed process ticket.
459 char[] text // the text to send.
460 data recv: char rc // the success/error code.
461 int32 info // opt: additional info.
462
463 The <text> is sent to the stdin of the spawned process
464 identified by <ticket>.
465
466 Possible return codes are:
467 ERQ_OK : Operation succeeded, no <info> is replied.
468 ERQ_E_TICKET : The given ticket is invalid, no <info> replied.
469 ERQ_E_INCOMPLETE: Only <info> chars of the text have been
470 sent. The erq will send a ERQ_OK message
471 once all data has been sent.
472 ERQ_E_WOULDBLOCK: Error E_WOULDBLOCK (also stored in <info>)
473 happened while sending the text.
474 ERQ_E_PIPE : Error E_PIPE (also stored in <info>)
475 happened while sending the text.
476 ERQ_E_UNKNOWN : The error with code <info> happened
477 while sending the data.
478
479
480 Data ready to read on TCP connection:
481
482 data recv: char out_or_err = ERQ_OK
483 char[] ticket // ticket of this connection
484
485 There is data available to read on the specified TCP connection.
486
487
488 Data received over a TCP connection:
489
490 data recv: char out_or_err = ERQ_STDOUT
491 char[] text // data received
492
493 The TCP port controlled by the erq did receive <text>.
494
495
496 TCP connection closes on error:
497
498 data recv: char out_or_err = ERQ_E_UNKNOWN
499 char errno // errno from socket operation
500
501 The TCP connection caused an error <errno> and has been closed.
502
503
504 TCP connection closed:
505
506 data recv: char out_or_err = ERQ_EXITED
507
508 The TCP connection closed regularily (End Of File).
509
510
511 Connection pending on TCP socket:
512
513 data recv: char out_or_err = ERQ_STDOUT
514
515 The TCP 'listen' port controlled by the erq received
516 a connection request.
517
518
519 Accept a pending connections:
520
521 request : ERQ_ACCEPT
522 data sent: char[] ticket // the ticket of this socket
523 data recv: Accept failed:
524 char rc // the success/error code.
525 char info // opt: additional info.
526 data recv: Accept succeeded:
527 char rc = ERQ_OK
528 struct in_addr.s_addr ip // remote side's ip
529 struct addr.sin_port port // remote side's port
530 char[] ticket // the new ticket.
531
532 The erq accepts a new connection on an accept-TCP-port, creates
Zesstra7ea4a032019-11-26 20:11:40 +0100533 a child and ticket for it, and returns its ticket together with
MG Mud User88f12472016-06-24 23:31:02 +0200534 the remote's side <ip>:<port> number (in network byte order).
535 Possible exit codes are:
536 ERQ_OK : Operation succeeded.
537 ERQ_E_ARGLENGTH : The port number given does not consist
538 of two bytes.
539 ERQ_E_NSLOTS : The max number of child processes (given
540 in <info>) is exhausted.
541 ERQ_E_TICKET : the ticket didn't match
Zesstra7ea4a032019-11-26 20:11:40 +0100542 ERQ_E_UNKNOWN : Error <info> occurred in one of the system
MG Mud User88f12472016-06-24 23:31:02 +0200543 calls done to open the port.
544
Zesstra7ea4a032019-11-26 20:11:40 +0100545 Once the port is open, it is treated as if it is just another
MG Mud User88f12472016-06-24 23:31:02 +0200546 spawned program.
547
MG Mud User88f12472016-06-24 23:31:02 +0200548EXAMPLE
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
MG Mud User88f12472016-06-24 23:31:02 +0200566HISTORY
567 The erq was introduced with 3.2.1@61.
568 ERQ_AUTH was introduced with 3.2.1@81.
569 ERQ_SEND, ERQ_SPAWN, ERQ_KILL were introduced with 3.2.1@82.
570 ERQ_OPEN_UDP, ERQ_OPEN_TCP, ERQ_LIST were introduced with 3.2.1@98.
571 ERQ_RLOOKUPV6 was introduced in 3.2.8.
572 LDMud 3.2.9 added the '--execdir' argument to erq, and the ERQ_OK
573 after ERQ_E_INCOMPLETE protocol.
574
575SEE ALSO
576 attach_erq_demon(E), send_erq(E), stale_erq(M), rfc 931
577 query_ip_number(E)