Simplify handler logic in control_cmd.c

Now that the legacy handlers are gone, we can simplify the
structures and macros here.
This commit is contained in:
Nick Mathewson 2019-04-09 10:58:42 -04:00
parent ddd33d39c7
commit 88d22b898e

View File

@ -2171,16 +2171,18 @@ handle_control_del_onion(control_connection_t *conn,
return 0; return 0;
} }
static const control_cmd_syntax_t obsolete_syntax = {
.max_args = UINT_MAX
};
/** /**
* Called when we get an obsolete command: tell the controller that it is * Called when we get an obsolete command: tell the controller that it is
* obsolete. * obsolete.
*/ */
static int static int
handle_control_obsolete(control_connection_t *conn, handle_control_obsolete(control_connection_t *conn,
uint32_t arg_len, const control_cmd_args_t *args)
const char *args)
{ {
(void)arg_len;
(void)args; (void)args;
char *command = tor_strdup(conn->current_cmd); char *command = tor_strdup(conn->current_cmd);
tor_strupper(command); tor_strupper(command);
@ -2190,37 +2192,10 @@ handle_control_obsolete(control_connection_t *conn,
} }
/** /**
* Selects an API to a controller command. See handler_fn_t for the * Function pointer to a handler function for a controller command.
* possible types.
**/ **/
typedef enum handler_type_t { typedef int (*handler_fn_t) (control_connection_t *conn,
hnd_legacy, const control_cmd_args_t *args);
hnd_parsed,
} handler_type_t;
/**
* Union: a function pointer to a handler function for a controller command.
*
* This needs to be a union (rather than just a single pointer) since not
* all controller commands have the same type.
**/
typedef union handler_fn_t {
/**
* A "legacy" handler takes a command's arguments as a nul-terminated
* string, and their length. It may not change the contents of the
* arguments. If the command is a multiline one, then the arguments may
* extend across multiple lines.
*/
int (*legacy)(control_connection_t *conn,
uint32_t arg_len,
const char *args);
/**
* A "parsed" handler expects its arguments in a pre-parsed format, in
* an immutable control_cmd_args_t *object.
**/
int (*parsed)(control_connection_t *conn,
const control_cmd_args_t *args);
} handler_fn_t;
/** /**
* Definition for a controller command. * Definition for a controller command.
@ -2230,10 +2205,6 @@ typedef struct control_cmd_def_t {
* The name of the command. If the command is multiline, the name must * The name of the command. If the command is multiline, the name must
* begin with "+". This is not case-sensitive. */ * begin with "+". This is not case-sensitive. */
const char *name; const char *name;
/**
* Which API to use when calling the handler function.
*/
handler_type_t handler_type;
/** /**
* A function to execute the command. * A function to execute the command.
*/ */
@ -2254,54 +2225,37 @@ typedef struct control_cmd_def_t {
*/ */
#define CMD_FL_WIPE (1u<<0) #define CMD_FL_WIPE (1u<<0)
#define SYNTAX_IGNORE { 0, UINT_MAX, false }
/** Macro: declare a command with a one-line argument, a given set of flags, /** Macro: declare a command with a one-line argument, a given set of flags,
* and a syntax definition. * and a syntax definition.
**/ **/
#define ONE_LINE_(name, htype, flags, syntax) \ #define ONE_LINE(name, flags) \
{ #name, \ { \
hnd_ ##htype, \ #name, \
{ .htype = handle_control_ ##name }, \ handle_control_ ##name, \
flags, \ flags, \
syntax, \ &name##_syntax, \
} }
/** Macro: declare a parsed command with a one-line argument, a given set of
* flags, and a syntax definition.
**/
#define ONE_LINE(name, htype, flags) \
ONE_LINE_(name, htype, flags, NULL)
#define ONE_LINE_PARSED(name, flags) \
ONE_LINE_(name, parsed, flags, &name ##_syntax)
/** /**
* Macro: declare a command with a multi-line argument and a given set of * Macro: declare a command with a multi-line argument and a given set of
* flags. * flags.
**/ **/
#define MULTLINE_(name, htype, flags, syntax) \ #define MULTLINE(name, flags) \
{ "+"#name, \ { "+"#name, \
hnd_ ##htype, \ handle_control_ ##name, \
{ .htype = handle_control_ ##name }, \
flags, \ flags, \
syntax \ &name##_syntax \
} }
#define MULTLINE(name, htype, flags) \
MULTLINE_(name, htype, flags, NULL)
#define MULTLINE_PARSED(name, flags) \
MULTLINE_(name, parsed, flags, &name##_syntax)
/** /**
* Macro: declare an obsolete command. (Obsolete commands give a different * Macro: declare an obsolete command. (Obsolete commands give a different
* error than non-existent ones.) * error than non-existent ones.)
**/ **/
#define OBSOLETE(name) \ #define OBSOLETE(name) \
{ #name, \ { #name, \
hnd_legacy, \ handle_control_obsolete, \
{ .legacy = handle_control_obsolete }, \
0, \ 0, \
NULL, \ &obsolete_syntax, \
} }
/** /**
@ -2309,35 +2263,35 @@ typedef struct control_cmd_def_t {
**/ **/
static const control_cmd_def_t CONTROL_COMMANDS[] = static const control_cmd_def_t CONTROL_COMMANDS[] =
{ {
ONE_LINE_PARSED(setconf, 0), ONE_LINE(setconf, 0),
ONE_LINE_PARSED(resetconf, 0), ONE_LINE(resetconf, 0),
ONE_LINE_PARSED(getconf, 0), ONE_LINE(getconf, 0),
MULTLINE_PARSED(loadconf, 0), MULTLINE(loadconf, 0),
ONE_LINE_PARSED(setevents, 0), ONE_LINE(setevents, 0),
ONE_LINE_PARSED(authenticate, CMD_FL_WIPE), ONE_LINE(authenticate, CMD_FL_WIPE),
ONE_LINE_PARSED(saveconf, 0), ONE_LINE(saveconf, 0),
ONE_LINE_PARSED(signal, 0), ONE_LINE(signal, 0),
ONE_LINE_PARSED(takeownership, 0), ONE_LINE(takeownership, 0),
ONE_LINE_PARSED(dropownership, 0), ONE_LINE(dropownership, 0),
ONE_LINE_PARSED(mapaddress, 0), ONE_LINE(mapaddress, 0),
ONE_LINE_PARSED(getinfo, 0), ONE_LINE(getinfo, 0),
ONE_LINE_PARSED(extendcircuit, 0), ONE_LINE(extendcircuit, 0),
ONE_LINE_PARSED(setcircuitpurpose, 0), ONE_LINE(setcircuitpurpose, 0),
OBSOLETE(setrouterpurpose), OBSOLETE(setrouterpurpose),
ONE_LINE_PARSED(attachstream, 0), ONE_LINE(attachstream, 0),
MULTLINE_PARSED(postdescriptor, 0), MULTLINE(postdescriptor, 0),
ONE_LINE_PARSED(redirectstream, 0), ONE_LINE(redirectstream, 0),
ONE_LINE_PARSED(closestream, 0), ONE_LINE(closestream, 0),
ONE_LINE_PARSED(closecircuit, 0), ONE_LINE(closecircuit, 0),
ONE_LINE_PARSED(usefeature, 0), ONE_LINE(usefeature, 0),
ONE_LINE_PARSED(resolve, 0), ONE_LINE(resolve, 0),
ONE_LINE_PARSED(protocolinfo, 0), ONE_LINE(protocolinfo, 0),
ONE_LINE_PARSED(authchallenge, CMD_FL_WIPE), ONE_LINE(authchallenge, CMD_FL_WIPE),
ONE_LINE_PARSED(dropguards, 0), ONE_LINE(dropguards, 0),
ONE_LINE_PARSED(hsfetch, 0), ONE_LINE(hsfetch, 0),
MULTLINE_PARSED(hspost, 0), MULTLINE(hspost, 0),
ONE_LINE_PARSED(add_onion, CMD_FL_WIPE), ONE_LINE(add_onion, CMD_FL_WIPE),
ONE_LINE_PARSED(del_onion, CMD_FL_WIPE), ONE_LINE(del_onion, CMD_FL_WIPE),
}; };
/** /**
@ -2356,35 +2310,25 @@ handle_single_control_command(const control_cmd_def_t *def,
char *args) char *args)
{ {
int rv = 0; int rv = 0;
switch (def->handler_type) {
case hnd_legacy: control_cmd_args_t *parsed_args;
if (def->handler.legacy(conn, cmd_data_len, args)) char *err=NULL;
rv = -1; tor_assert(def->syntax);
break; parsed_args = control_cmd_parse_args(conn->current_cmd,
case hnd_parsed: { def->syntax,
control_cmd_args_t *parsed_args; cmd_data_len, args,
char *err=NULL; &err);
tor_assert(def->syntax); if (!parsed_args) {
parsed_args = control_cmd_parse_args(conn->current_cmd, connection_printf_to_buf(conn,
def->syntax, "512 Bad arguments to %s: %s\r\n",
cmd_data_len, args, conn->current_cmd, err?err:"");
&err); tor_free(err);
if (!parsed_args) { } else {
connection_printf_to_buf(conn, if (BUG(err))
"512 Bad arguments to %s: %s\r\n", tor_free(err);
conn->current_cmd, err?err:""); if (def->handler(conn, parsed_args))
tor_free(err); rv = 0;
} else { control_cmd_args_free(parsed_args);
if (BUG(err))
tor_free(err);
if (def->handler.parsed(conn, parsed_args))
rv = 0;
control_cmd_args_free(parsed_args);
}
break;
}
default:
tor_assert_unreached();
} }
if (def->flags & CMD_FL_WIPE) if (def->flags & CMD_FL_WIPE)