MT#55283 use string hashing for CLI parsing

Change-Id: I270deca0e5fc9f07be501f9a4c336244fc50be9b
pull/1907/head
Richard Fuchs 11 months ago
parent 8e50664fa1
commit 42c46f2d68

@ -50,8 +50,11 @@ flags = [
'-DHAVE_LIBURING',
'-D__csh_lookup(x)=str_hash(x)',
'-D__csh_lookup_n(n,x)=__csh_lookup(x)',
'-D__csh_lookup_section(n,x)=__csh_lookup(x)',
'-DCSH_LOOKUP(x)=' + csh_lookup_str,
'-DCSH_LOOKUP_N(n,x)=CSH_LOOKUP(x)',
'-DCSH_SECTION=0',
'-DCSH_NUM_LOOKUPS=0',
'-O2',
'-fstack-protector',
'--param=ssp-buffer-size=4',

@ -89,7 +89,7 @@ include ../lib/mqtt.Makefile
SRCS= main.c kernel.c helpers.c control_tcp.c call.c control_udp.c redis.c \
cookie_cache.c udp_listener.c control_ng_flags_parser.c control_ng.strhash.c sdp.strhash.c stun.c rtcp.c \
crypto.c rtp.c call_interfaces.strhash.c dtls.c log.c cli.c graphite.c ice.c \
crypto.c rtp.c call_interfaces.strhash.c dtls.c log.c cli.strhash.c graphite.c ice.c \
media_socket.c homer.c recording.c statistics.c cdr.c ssrc.c iptables.c tcp_listener.c \
codec.c load.c dtmf.c timerthread.c media_player.c jitter_buffer.c t38.c websocket.c \
mqtt.c janus.strhash.c audio_player.c arena.c

@ -34,12 +34,19 @@
#include "media_player.h"
typedef struct cli_handler_t cli_handler_t;
typedef struct cli_command_t cli_command_t;
typedef void (*cli_handler_func)(str *, struct cli_writer *, const cli_handler_t *);
struct cli_handler_t {
struct cli_command_t {
const char *cmd;
cli_handler_func handler;
const cli_handler_t *next;
};
struct cli_handler_t {
unsigned int section;
const cli_command_t *commands;
unsigned int num_commands;
};
static void cli_generic_handler(str *instr, struct cli_writer *cw, const cli_handler_t *);
static void cli_incoming_terminate(str *instr, struct cli_writer *cw, const cli_handler_t *);
@ -135,10 +142,10 @@ static void cli_incoming_media_evict_players(str *instr, struct cli_writer *cw,
#endif
#define HANDLER_START(n) static const cli_handler_t n[] = {
#define HANDLER_CMD(c, f) { .cmd = c, .handler = f, },
#define HANDLER_GENERIC(c, h) { .cmd = c, .handler = cli_generic_handler, .next = h, },
#define HANDLER_END { NULL, } };
#define HANDLER_START(n) static const cli_handler_t n = { .section = CSH_SECTION, .commands = (const struct cli_command_t []) {
#define HANDLER_CMD(c, f) [CSH_LOOKUP(c)] = { .cmd = c, .handler = f },
#define HANDLER_GENERIC(c, h) [CSH_LOOKUP(c)] = { .cmd = c, .handler = cli_generic_handler, .next = &h },
#define HANDLER_END }, .num_commands = CSH_NUM_LOOKUPS };
HANDLER_START(cli_set_handlers)
HANDLER_CMD("maxopenfiles", cli_incoming_set_maxopenfiles)
@ -274,40 +281,29 @@ static void cli_list_tag_info(struct cli_writer *cw, struct call_monologue *ml);
static void cli_handler_do(const cli_handler_t *handlers, str *instr,
static void cli_handler_do(const cli_handler_t *handler, str *instr,
struct cli_writer *cw)
{
const cli_handler_t *h;
if (!str_cmp(instr, "help")) {
cw->cw_printf(cw, "Available sub-commands at this level:\n");
for (h = handlers; h->cmd; h++)
cw->cw_printf(cw, "\t%s\n", h->cmd);
for (unsigned int i = 0; i < handler->num_commands; i++)
cw->cw_printf(cw, "\t%s\n", handler->commands[i].cmd);
return;
}
for (h = handlers; h->cmd; h++) {
if (str_shift_cmp(instr, h->cmd))
continue;
// check if followed by space or newline or end of line
if (instr->len) {
if (instr->s[0] == ' ') {
while (instr->len && instr->s[0] == ' ')
str_shift(instr, 1);
}
else if (instr->s[0] == '\n' || instr->s[0] == '\r')
instr->len = 0;
else {
// not a match. rewind and continue
str_unshift(instr, strlen(h->cmd));
continue;
}
}
h->handler(instr, cw, h);
str cmd;
if (!str_token_sep(&cmd, instr, ' ')) {
cw->cw_printf(cw, "Incomplete command: " STR_FORMAT "\n", STR_FMT(instr));
return;
}
int val = __csh_lookup_section(handler->section, &cmd);
if (val < 0 || val >= handler->num_commands) {
cw->cw_printf(cw, "Unknown command: " STR_FORMAT "\n", STR_FMT(&cmd));
return;
}
cw->cw_printf(cw, "Unknown or incomplete command: " STR_FORMAT "\n", STR_FMT(instr));
handler->commands[val].handler(instr, cw, handler->commands[val].next);
}
static void destroy_own_foreign_calls(bool foreign_call, unsigned int uint_keyspace_db) {
@ -1045,7 +1041,7 @@ static void cli_generic_handler(str *instr, struct cli_writer *cw, const cli_han
return;
}
cli_handler_do(handler->next, instr, cw);
cli_handler_do(handler, instr, cw);
}
static void cli_incoming_terminate(str *instr, struct cli_writer *cw, const cli_handler_t *handler) {
@ -1305,7 +1301,7 @@ static void cli_stream_readable(struct streambuf_stream *s) {
void cli_handle(str *instr, struct cli_writer *cw) {
ilogs(control, LOG_INFO, "Got CLI command: " STR_FORMAT_M, STR_FMT_M(instr));
cli_handler_do(cli_top_handlers, instr, cw);
cli_handler_do(&cli_top_handlers, instr, cw);
release_closed_sockets();
}
@ -1530,7 +1526,7 @@ static void cli_incoming_call(str *instr, struct cli_writer *cw, const cli_handl
return;
}
cli_handler_do(cli_call_handlers, instr, cw);
cli_handler_do(&cli_call_handlers, instr, cw);
if (cw->call) {
rwlock_unlock_w(&cw->call->master_lock);
@ -1590,7 +1586,7 @@ static void cli_incoming_call_tag(str *instr, struct cli_writer *cw, const cli_h
return;
}
cli_handler_do(cli_tag_handlers, instr, cw);
cli_handler_do(&cli_tag_handlers, instr, cw);
cw->ml = NULL;
}

@ -69,7 +69,7 @@ include ../lib/codec-chain.Makefile
SRCS= test-bitstr.c aes-crypt.c aead-aes-crypt.c test-const_str_hash.strhash.c aead-decrypt.c
LIBSRCS= loglib.c auxlib.c str.c rtplib.c ssllib.c mix_buffer.c bufferpool.c bencode.c
DAEMONSRCS= crypto.c ssrc.c helpers.c rtp.c
HASHSRCS=
HASHSRCS= cli.c
ifeq ($(with_transcoding),yes)
SRCS+= test-transcode.c test-dtmf-detect.c test-payload-tracker.c test-resample.c test-stats.c
@ -82,7 +82,7 @@ LIBSRCS+= codeclib.strhash.c resample.c socket.c streambuf.c dtmflib.c poller.c
DAEMONSRCS+= control_ng_flags_parser.c codec.c call.c ice.c kernel.c media_socket.c stun.c bencode.c \
dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c \
cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c timerthread.c \
media_player.c jitter_buffer.c t38.c tcp_listener.c mqtt.c websocket.c cli.c \
media_player.c jitter_buffer.c t38.c tcp_listener.c mqtt.c websocket.c \
audio_player.c arena.c
HASHSRCS+= call_interfaces.c control_ng.c sdp.c janus.c
LIBASM= mvr2s_x64_avx2.S mvr2s_x64_avx512.S mix_in_x64_avx2.S mix_in_x64_avx512bw.S mix_in_x64_sse2.S
@ -255,7 +255,7 @@ test-stats: test-stats.o $(COMMONOBJS) codeclib.strhash.o resample.o codec.o ssr
control_ng_flags_parser.o control_ng.strhash.o graphite.o \
streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o timerthread.o \
media_player.o jitter_buffer.o dtmflib.o t38.o tcp_listener.o mqtt.o janus.strhash.o \
websocket.o cli.o mvr2s_x64_avx2.o mvr2s_x64_avx512.o audio_player.o mix_buffer.o \
websocket.o cli.strhash.o mvr2s_x64_avx2.o mvr2s_x64_avx512.o audio_player.o mix_buffer.o \
mix_in_x64_avx2.o mix_in_x64_sse2.o mix_in_x64_avx512bw.o bufferpool.o uring.o arena.o
test-transcode: test-transcode.o $(COMMONOBJS) codeclib.strhash.o resample.o codec.o ssrc.o call.o ice.o helpers.o \
@ -264,7 +264,7 @@ test-transcode: test-transcode.o $(COMMONOBJS) codeclib.strhash.o resample.o cod
control_ng_flags_parser.o control_ng.strhash.o \
streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o timerthread.o \
media_player.o jitter_buffer.o dtmflib.o t38.o tcp_listener.o mqtt.o janus.strhash.o websocket.o \
cli.o mvr2s_x64_avx2.o mvr2s_x64_avx512.o audio_player.o mix_buffer.o \
cli.strhash.o mvr2s_x64_avx2.o mvr2s_x64_avx512.o audio_player.o mix_buffer.o \
mix_in_x64_avx2.o mix_in_x64_sse2.o mix_in_x64_avx512bw.o bufferpool.o uring.o arena.o
test-resample: test-resample.o $(COMMONOBJS) codeclib.strhash.o resample.o dtmflib.o mvr2s_x64_avx2.o \

@ -12,18 +12,59 @@ print("/******** GENERATED FILE ********/\n");
my $rewritten_input = '';
my @sections;
my @slots;
my (%defines_0, %defines_1, %defines_2);
# collect keywords and rewrite input file with in lookup keys
sub def_sub {
my ($subs, @vals) = @_;
my $i = 0;
my $repl = $subs->[$i++];
for my $r (@vals) {
my $key = $subs->[$i++];
$repl =~ s/(\W|^)\Q$key\E(\W|$)/$1$r$2/g;
}
return $repl;
}
while (my $line = <STDIN>) {
my $num = scalar(@sections);
my $new_section;
if ($line =~ /CSH_SECTION|CSH_LOOKUP|CSH_NUM_LOOKUPS/
&& $line =~ /^#define\s+(\w+)(?:\s+(.*?)|\(\s*(\w+)\s*\)\s+(.*?)|\(\s*(\w+)\s*,\s*(\w+)\s*\)\s+(.*?))$/) {
if ($2) {
$defines_0{$1} = $2;
}
elsif ($3) {
$defines_1{$1} = [$4, $3];
}
elsif ($5) {
$defines_2{$1} = [$7, $5, $6];
}
$rewritten_input .= "\n";
next;
}
for my $def (keys(%defines_0)) {
my $sub = $defines_0{$def};
$line =~ s/(\W|^)\Q$def\E(\W|$)/$1$sub$2/g;
}
for my $def (keys(%defines_1)) {
my $subs = $defines_1{$def};
$line =~ s/(\W|^)\Q$def\E\(\s*(\S+|"[^"]*")\s*\)(\W|$)/$1 . def_sub($subs, $2) . $3/eg;
}
for my $def (keys(%defines_2)) {
my $subs = $defines_2{$def};
$line =~ s/(\W|^)\Q$def\E\(\s*(\S+|"[^"]*")\s*,\s*(\S+|"[^"]*")\s*\)(\W|$)/$1 . def_sub($subs, $2, $3) . $4/eg;
}
if (($line =~ s/(__csh_lookup)(\s*\()/$1_$num$2/)) {
$new_section = 0;
}
elsif (($line =~ s/(__csh_lookup)_n(\s*\()\s*(\d+)\s*,\s*/$1_$num$2/)) {
$new_section = $3;
}
elsif (($line =~ s/CSH_SECTION/$num/)) {
$new_section = 0;
}
if (defined($new_section)) {
$rewritten_input .= $line;
my $section = { keys => '', vals => {}, num => $num };
@ -31,6 +72,14 @@ while (my $line = <STDIN>) {
$slots[$new_section] = $num;
next;
}
if ($line =~ s/CSH_NUM_LOOKUPS/{}/) {
my $section = $sections[$slots[0]];
die unless $section;
my $n = values(%{$section->{vals}});
$line =~ s/{}/$n/;
$rewritten_input .= $line;
next;
}
my ($rewrite, $key);
if ($line =~ s/CSH_LOOKUP\(\s*"(.*?)"\s*\)/{}/) {
$rewrite = 0;
@ -99,6 +148,7 @@ for my $section (@sections) {
# add convenience function
print <<END;
#include "str.h"
#pragma GCC diagnostic ignored \"-Wunused-function\"
static int __csh_lookup_$num(const str *s) {
if (!s->s)
return -1;
@ -107,9 +157,30 @@ static int __csh_lookup_$num(const str *s) {
return -1;
return h->num;
}
#pragma GCC diagnostic pop
END
}
print("static const struct __csh_hash_lookup *(*__csh_lookup_funcs[])(const char *, long unsigned int) = {\n");
for my $section (@sections) {
print("\t__csh_lookup_raw_$section->{num},\n");
}
print <<END;
};
#pragma GCC diagnostic ignored \"-Wunused-function\"
static int __csh_lookup_section(unsigned int n, const str *s) {
if (n >= G_N_ELEMENTS(__csh_lookup_funcs))
return -1;
if (!s->s)
return -1;
const struct __csh_hash_lookup *h = __csh_lookup_funcs[n](s->s, s->len);
if (!h)
return -1;
return h->num;
}
#pragma GCC diagnostic pop
END
# adjust diagnostic line numbers and originating file
print $ARGV[0] ? "#line 1 \"$ARGV[0]\"\n" : "#line 1\n";
print $rewritten_input;

Loading…
Cancel
Save