Responding To Client Requests
Whenever the server processes a request from the client, it must generate an
appropriate, RFC-compliant response back to the client. There are two
main ways of generating these responses, usually done from within a command
handler.
Response Chains
The first, and prefered, method of transmitting numeric-plus-text message
responses back to clients is via the internal response chains. Using
these allows all handlers to add their own individual responses, which will then
all be sent en masse after the command successfully completes, or fails.
The engine maintains two such response chains, one chain for success
messages, and one for error messages. When all handlers for a given command
have been called, the engine evaluates the final condition of the command. If
it has failed (signaled by a handler returning one of the available
ERROR*
macros), all responses
pending in the error response chain are sent. If, on the other hand, the
command has successfully completed, the success response chain is sent. If a
command has neither completed successfully nor resulted in an error, it is
assumed to be an invalid command, and the client is informed approppriately.
In any case, once the "lifetime" of the command is over, and one
(or none) of the response chains has been sent, both chains are
destroyed.
The response chain method uses the following functions:
As you can see, with the response chain method, there are no multiline functions
for multiline replies, as there are with the second response method. This is
because the server automatically generates a multiline formated reply if it
detects that there are two or more responses with the same numeric waiting to
be sent to the client. In many cases, you may be writing a handler,
POST_CMD
for example, that neither specifically knows nor cares
what numerics other handlers are using during their responses. In this case,
you can use the special
R_DUP
response numeric,
which tells the server that your response should be assumed to be part
of a multiline response started by another handler.
For example, if the following
pr_response_add()
calls were made from different modules:
module A:
pr_response_add(R_200, "Command successfully completed");
module B:
pr_response_add(R_DUP, "Statistics for command '%s': none", cmd->argv[0]);
module C:
pr_response_add(R_DUP, "XFOO post_cmd handler ran");
The final output sent to the client, assuming the command was successfully handled, would be (assuming your command is named 'XFOO'):
200-Command successfully completed. Statistics for command 'XFOO': none. 200 XFOO post_cmd handler ran.
See include/ftp.h for the full listing of response numerics.
Responses to the client should be added using pr_response_add()
when the handler is going to return HANDLED
or
DECLINED
; pr_response_add_err()
should be used if
the handler is going to return ERROR
. At least one response
in the chain, either "normal" or error chain, should be present
in order to return an RFC-compliant response code to the client. This
is important; returning the wrong code for a command, or no code at all,
can hang the client. Note also that responses may be added to both
chains simultaneously, however only one chain of response will be flushed
back to the client.
Direct Response
The second way, a direct response method, is incompatible with other
handlers, and should be used only if the handler is about to terminate the
current connection, and thus kill the fork()
ed child server,
usually via
end_login()
.
This method must use one of the functions listed below, for the
"normal" response chains will never be processed by the core
engine.
The direct response method utilizes the following functions:
pr_response_send()
,
pr_response_send_async()
,
pr_response_send_ml()
pr_response_send_ml_end()
pr_response_send_ml_start()
Response handler macros
The following are some macros specific to response generation, both by
modules and by the core engine:
DECLINED
(cmd_rec *cmd)
POST_CMD
handlers will
not be called in this case.ERROR
(cmd_rec *cmd)
POST_CMD
handlers
are not called.ERROR_INT
(cmd_rec *cmd, int err_code)
ERROR
, except that the single integer numeric
error is indicated. This is used only by authentication/mapping handlers,
eg mod_ldap
and mod_auth_unix
.ERROR_MSG
(cmd_rec *cmd, int err_code, char *err_message)
ERROR
, except that a string composed of
err_code and err_message is sent to the client. In the case
of configuration directive handlers, the numeric argument is ignored,
the string message is displayed to the user or logged via
syslog
, and the forked process terminates.HANDLED
(cmd_rec *cmd)
HANDLED
,
POST_CMD
handlers will be called for the command.