diff --git a/Android.mk b/Android.mk index 4eb91ee9..90bed54e 100644 --- a/Android.mk +++ b/Android.mk @@ -12,6 +12,7 @@ SERVALD_SRC_FILES = \ serval-dna/overlay_mdp.c \ serval-dna/batman.c \ serval-dna/ciphers.c \ + serval-dna/cli.c \ serval-dna/client.c \ serval-dna/commandline.c \ serval-dna/conf.c \ @@ -53,6 +54,7 @@ SERVALD_SRC_FILES = \ serval-dna/fdqueue.c \ serval-dna/monitor.c \ serval-dna/monitor-cli.c \ + serval-dna/monitor-client.c \ serval-dna/codecs.c \ serval-dna/audiodevices.c \ serval-dna/audio_msm_g1.c \ diff --git a/Makefile.in b/Makefile.in index fa70bd0b..8c7d96d6 100755 --- a/Makefile.in +++ b/Makefile.in @@ -5,6 +5,7 @@ SRCS= \ audio_reflector.c \ batman.c \ ciphers.c \ + cli.c \ client.c \ codecs.c \ commandline.c \ @@ -24,6 +25,7 @@ SRCS= \ mdp_client.c \ mkdir.c \ monitor.c \ + monitor-client.c \ monitor-cli.c \ net.c \ overlay.c \ diff --git a/cli.c b/cli.c new file mode 100644 index 00000000..c9e5041b --- /dev/null +++ b/cli.c @@ -0,0 +1,164 @@ +#include +#include +#include "cli.h" +#include "log.h" +#include "serval.h" +#include "rhizome.h" + +int cli_usage(struct command_line_option *options) { + printf("Usage:\n"); + int i,j; + for(i=0;options[i].function;i++) { + for(j=0;options[i].words[j];j++) + printf(" %s",options[i].words[j]); + printf("\n %s\n",options[i].description); + } + return 0; +} + +int cli_execute(const char *argv0, int argc, const char *const *args, struct command_line_option *options, void *context){ + int ambiguous=0; + int cli_call=-1; + int i; + for(i=0;options[i].function;i++) + { + int j; + const char *word = NULL; + int optional = 0; + int mandatory = 0; + for (j = 0; (word = options[i].words[j]); ++j) { + int wordlen = strlen(word); + if (optional < 0) { + WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" not allowed after \"...\"", i, j, word); + break; + } + else if (!( (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>') + || (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']') + || (wordlen > 0) + )) { + WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" is malformed", i, j, word); + break; + } else if (word[0] == '<') { + ++mandatory; + if (optional) { + WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" should be optional", i, j, word); + break; + } + } else if (word[0] == '[') { + ++optional; + } else if (wordlen == 3 && word[0] == '.' && word[1] == '.' && word[2] == '.') { + optional = -1; + } else { + ++mandatory; + if (j < argc && strcasecmp(word, args[j])) // literal words don't match + break; + } + } + if (!word && argc >= mandatory && (optional < 0 || argc <= mandatory + optional)) { + /* A match! We got through the command definition with no internal errors and all literal + args matched and we have a proper number of args. If we have multiple matches, then note + that the call is ambiguous. */ + if (cli_call>=0) ambiguous++; + if (ambiguous==1) { + WHY("Ambiguous command line call:"); + WHY_argv(" ", argc, args); + WHY("Matches the following known command line calls:"); + WHY_argv(" ", argc, options[cli_call].words); + } + if (ambiguous) + WHY_argv(" ", argc, options[i].words); + cli_call=i; + } + } + + /* Don't process ambiguous calls */ + if (ambiguous) return -1; + /* Complain if we found no matching calls */ + if (cli_call<0) { + if (argc) { + WHY("Unknown command line call:"); + WHY_argv(" ", argc, args); + } + INFO("Use \"help\" command to see a list of valid commands"); + return -1; + } + + /* Otherwise, make call */ + return options[cli_call].function(argc, args, &options[cli_call], context); +} + +int cli_arg(int argc, const char *const *argv, struct command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue) +{ + int arglen = strlen(argname); + int i; + const char *word; + for(i = 0; (word = o->words[i]); ++i) { + int wordlen = strlen(word); + /* No need to check that the "<...>" and "[<...>]" are all intact in the command_line_option, + because that was already checked in parseCommandLine(). */ + if (i < argc + &&( (wordlen == arglen + 2 && word[0] == '<' && !strncasecmp(&word[1], argname, arglen)) + || (wordlen == arglen + 4 && word[0] == '[' && !strncasecmp(&word[2], argname, arglen))) + ) { + const char *value = argv[i]; + if (validator && !(*validator)(value)) + return WHYF("Invalid argument %d '%s': \"%s\"", i + 1, argname, value); + *dst = value; + return 0; + } + } + /* No matching valid argument was found, so return default value. It might seem that this should + never happen, but it can because more than one version of a command line option may exist, one + with a given argument and another without, and allowing a default value means we can have a + single function handle both in a fairly simple manner. */ + *dst = defaultvalue; + return 1; +} + +int cli_lookup_did(const char *text) +{ + return text[0] == '\0' || strcmp(text, "*") == 0 || str_is_did(text); +} + +int cli_absolute_path(const char *arg) +{ + return arg[0] == '/' && arg[1] != '\0'; +} + +int cli_optional_sid(const char *arg) +{ + return !arg[0] || str_is_subscriber_id(arg); +} + +int cli_optional_bundle_key(const char *arg) +{ + return !arg[0] || rhizome_str_is_bundle_key(arg); +} + +int cli_manifestid(const char *arg) +{ + return rhizome_str_is_manifest_id(arg); +} + +int cli_fileid(const char *arg) +{ + return rhizome_str_is_file_hash(arg); +} + +int cli_optional_bundle_crypt_key(const char *arg) +{ + return !arg[0] || rhizome_str_is_bundle_crypt_key(arg); +} + +int cli_uint(const char *arg) +{ + register const char *s = arg; + while (isdigit(*s++)) + ; + return s != arg && *s == '\0'; +} + +int cli_optional_did(const char *text) +{ + return text[0] == '\0' || str_is_did(text); +} diff --git a/cli.h b/cli.h new file mode 100644 index 00000000..2ac26f7a --- /dev/null +++ b/cli.h @@ -0,0 +1,30 @@ +#ifndef __SERVALD_CLI_H +#define __SERVALD_CLI_H + +typedef struct command_line_option { + int (*function)(int argc, const char *const *argv, struct command_line_option *o, void *context); + const char *words[32]; // 32 words should be plenty! + unsigned long long flags; +#define CLIFLAG_NONOVERLAY (1<<0) /* Uses a legacy IPv4 DNA call instead of overlay mnetwork */ +#define CLIFLAG_STANDALONE (1<<1) /* Cannot be issued to a running instance */ + const char *description; // describe this invocation +} command_line_option; + + +int cli_usage(command_line_option *options); +int cli_execute(const char *argv0, int argc, const char *const *args, command_line_option *options, void *context); +int cli_arg(int argc, const char *const *argv, command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue); + +int cli_lookup_did(const char *text); +int cli_absolute_path(const char *arg); +int cli_optional_sid(const char *arg); +int cli_optional_bundle_key(const char *arg); +int cli_manifestid(const char *arg); +int cli_fileid(const char *arg); +int cli_optional_bundle_crypt_key(const char *arg); +int cli_uint(const char *arg); +int cli_optional_did(const char *text); + + + +#endif \ No newline at end of file diff --git a/commandline.c b/commandline.c index e44b5453..fac152c9 100644 --- a/commandline.c +++ b/commandline.c @@ -38,17 +38,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "strbuf.h" #include "mdp_client.h" +#include "cli.h" -int cli_usage() { +extern struct command_line_option command_line_options[]; + +int commandline_usage(int argc, const char *const *argv, struct command_line_option *o, void *context){ printf("Serval Mesh version .\n"); - printf("Usage:\n"); - int i,j; - for(i=0;command_line_options[i].function;i++) { - for(j=0;command_line_options[i].words[j];j++) - printf(" %s",command_line_options[i].words[j]); - printf("\n %s\n",command_line_options[i].description); - } - return 0; + return cli_usage(command_line_options); } /* Data structures for accumulating output of a single JNI call. @@ -185,77 +181,11 @@ JNIEXPORT jint JNICALL Java_org_servalproject_servald_ServalD_rawCommand(JNIEnv */ int parseCommandLine(const char *argv0, int argc, const char *const *args) { - int ambiguous=0; - int cli_call=-1; fd_clearstats(); IN(); - int i; - for(i=0;command_line_options[i].function;i++) - { - int j; - const char *word = NULL; - int optional = 0; - int mandatory = 0; - for (j = 0; (word = command_line_options[i].words[j]); ++j) { - int wordlen = strlen(word); - if (optional < 0) { - WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" not allowed after \"...\"", i, j, word); - break; - } - else if (!( (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>') - || (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']') - || (wordlen > 0) - )) { - WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" is malformed", i, j, word); - break; - } else if (word[0] == '<') { - ++mandatory; - if (optional) { - WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" should be optional", i, j, word); - break; - } - } else if (word[0] == '[') { - ++optional; - } else if (wordlen == 3 && word[0] == '.' && word[1] == '.' && word[2] == '.') { - optional = -1; - } else { - ++mandatory; - if (j < argc && strcasecmp(word, args[j])) // literal words don't match - break; - } - } - if (!word && argc >= mandatory && (optional < 0 || argc <= mandatory + optional)) { - /* A match! We got through the command definition with no internal errors and all literal - args matched and we have a proper number of args. If we have multiple matches, then note - that the call is ambiguous. */ - if (cli_call>=0) ambiguous++; - if (ambiguous==1) { - WHY("Ambiguous command line call:"); - WHY_argv(" ", argc, args); - WHY("Matches the following known command line calls:"); - WHY_argv(" ", argc, command_line_options[cli_call].words); - } - if (ambiguous) - WHY_argv(" ", argc, command_line_options[i].words); - cli_call=i; - } - } - - /* Don't process ambiguous calls */ - if (ambiguous) return -1; - /* Complain if we found no matching calls */ - if (cli_call<0) { - if (argc) { - WHY("Unknown command line call:"); - WHY_argv(" ", argc, args); - } - INFO("Use \"help\" command to see a list of valid commands"); - return -1; - } - - /* Otherwise, make call */ confSetDebugFlags(); - int result=command_line_options[cli_call].function(argc, args, &command_line_options[cli_call]); + + int result = cli_execute(argv0, argc, args, command_line_options, NULL); /* clean up after ourselves */ overlay_mdp_client_done(); OUT(); @@ -265,34 +195,6 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args) return result; } -int cli_arg(int argc, const char *const *argv, command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue) -{ - int arglen = strlen(argname); - int i; - const char *word; - for(i = 0; (word = o->words[i]); ++i) { - int wordlen = strlen(word); - /* No need to check that the "<...>" and "[<...>]" are all intact in the command_line_option, - because that was already checked in parseCommandLine(). */ - if (i < argc - &&( (wordlen == arglen + 2 && word[0] == '<' && !strncasecmp(&word[1], argname, arglen)) - || (wordlen == arglen + 4 && word[0] == '[' && !strncasecmp(&word[2], argname, arglen))) - ) { - const char *value = argv[i]; - if (validator && !(*validator)(value)) - return WHYF("Invalid argument %d '%s': \"%s\"", i + 1, argname, value); - *dst = value; - return 0; - } - } - /* No matching valid argument was found, so return default value. It might seem that this should - never happen, but it can because more than one version of a command line option may exist, one - with a given argument and another without, and allowing a default value means we can have a - single function handle both in a fairly simple manner. */ - *dst = defaultvalue; - return 1; -} - /* Write a single character to output. If in a JNI call, then this appends the character to the current output field. Returns the character written cast to an unsigned char then to int, or EOF on error. @@ -392,7 +294,7 @@ int cli_delim(const char *opt) return 0; } -int app_echo(int argc, const char *const *argv, struct command_line_option *o) +int app_echo(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); int i; @@ -405,12 +307,7 @@ int app_echo(int argc, const char *const *argv, struct command_line_option *o) return 0; } -int cli_lookup_did(const char *text) -{ - return text[0] == '\0' || strcmp(text, "*") == 0 || str_is_did(text); -} - -int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o) +int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); int i; @@ -555,12 +452,7 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option return 0; } -int cli_absolute_path(const char *arg) -{ - return arg[0] == '/' && arg[1] != '\0'; -} - -int app_server_start(int argc, const char *const *argv, struct command_line_option *o) +int app_server_start(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); /* Process optional arguments */ @@ -711,7 +603,7 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti return ret; } -int app_server_stop(int argc, const char *const *argv, struct command_line_option *o) +int app_server_stop(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); int pid, tries, running; @@ -778,7 +670,7 @@ int app_server_stop(int argc, const char *const *argv, struct command_line_optio return 0; } -int app_server_status(int argc, const char *const *argv, struct command_line_option *o) +int app_server_status(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); int pid; @@ -810,7 +702,7 @@ int app_server_status(int argc, const char *const *argv, struct command_line_opt return pid > 0 ? 0 : 1; } -int app_mdp_ping(int argc, const char *const *argv, struct command_line_option *o) +int app_mdp_ping(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *sid, *count; @@ -952,7 +844,7 @@ int app_mdp_ping(int argc, const char *const *argv, struct command_line_option * return ret; } -int app_config_set(int argc, const char *const *argv, struct command_line_option *o) +int app_config_set(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *var, *val; @@ -964,7 +856,7 @@ int app_config_set(int argc, const char *const *argv, struct command_line_option return confValueSet(var, val) == -1 ? -1 : confWrite(); } -int app_config_del(int argc, const char *const *argv, struct command_line_option *o) +int app_config_del(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *var; @@ -975,7 +867,7 @@ int app_config_del(int argc, const char *const *argv, struct command_line_option return confValueSet(var, NULL) == -1 ? -1 : confWrite(); } -int app_config_get(int argc, const char *const *argv, struct command_line_option *o) +int app_config_get(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *var; @@ -1006,7 +898,7 @@ int app_config_get(int argc, const char *const *argv, struct command_line_option return 0; } -int app_rhizome_hash_file(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_hash_file(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); /* compute hash of file. We do this without a manifest, so it will necessarily @@ -1021,17 +913,7 @@ int app_rhizome_hash_file(int argc, const char *const *argv, struct command_line return 0; } -int cli_optional_sid(const char *arg) -{ - return !arg[0] || str_is_subscriber_id(arg); -} - -int cli_optional_bundle_key(const char *arg) -{ - return !arg[0] || rhizome_str_is_bundle_key(arg); -} - -int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *filepath, *manifestpath, *authorSidHex, *pin, *bskhex; @@ -1215,7 +1097,7 @@ int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_ return ret; } -int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *filepath, *manifestpath; @@ -1286,12 +1168,7 @@ int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_ return status; } -int cli_manifestid(const char *arg) -{ - return rhizome_str_is_manifest_id(arg); -} - -int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *manifestid, *manifestpath; @@ -1327,17 +1204,7 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, struct comma return ret; } -int cli_fileid(const char *arg) -{ - return rhizome_str_is_file_hash(arg); -} - -int cli_optional_bundle_crypt_key(const char *arg) -{ - return !arg[0] || rhizome_str_is_bundle_crypt_key(arg); -} - -int app_rhizome_extract_file(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_extract_file(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *fileid, *filepath, *keyhex; @@ -1367,15 +1234,7 @@ int app_rhizome_extract_file(int argc, const char *const *argv, struct command_l return ret; } -int cli_uint(const char *arg) -{ - register const char *s = arg; - while (isdigit(*s++)) - ; - return s != arg && *s == '\0'; -} - -int app_rhizome_list(int argc, const char *const *argv, struct command_line_option *o) +int app_rhizome_list(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *pin, *service, *sender_sid, *recipient_sid, *offset, *limit; @@ -1395,7 +1254,7 @@ int app_rhizome_list(int argc, const char *const *argv, struct command_line_opti return rhizome_list_manifests(service, sender_sid, recipient_sid, atoi(offset), atoi(limit)); } -int app_keyring_create(int argc, const char *const *argv, struct command_line_option *o) +int app_keyring_create(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *pin; @@ -1405,7 +1264,7 @@ int app_keyring_create(int argc, const char *const *argv, struct command_line_op return 0; } -int app_keyring_list(int argc, const char *const *argv, struct command_line_option *o) +int app_keyring_list(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *pin; @@ -1432,7 +1291,7 @@ int app_keyring_list(int argc, const char *const *argv, struct command_line_opti return 0; } -int app_keyring_add(int argc, const char *const *argv, struct command_line_option *o) +int app_keyring_add(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *pin; @@ -1477,12 +1336,7 @@ int app_keyring_add(int argc, const char *const *argv, struct command_line_optio return 0; } -int cli_optional_did(const char *text) -{ - return text[0] == '\0' || str_is_did(text); -} - -int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o) +int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *sid, *did, *pin, *name; @@ -1511,7 +1365,7 @@ int app_keyring_set_did(int argc, const char *const *argv, struct command_line_o return 0; } -int app_id_self(int argc, const char *const *argv, struct command_line_option *o) +int app_id_self(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); /* List my own identities */ @@ -1558,7 +1412,7 @@ int app_id_self(int argc, const char *const *argv, struct command_line_option *o return 0; } -int app_test_rfs(int argc, const char *const *argv, struct command_line_option *o) +int app_test_rfs(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); printf("Testing that RFS coder works properly.\n"); @@ -1574,7 +1428,7 @@ int app_test_rfs(int argc, const char *const *argv, struct command_line_option * return 0; } -int app_crypt_test(int argc, const char *const *argv, struct command_line_option *o) +int app_crypt_test(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES]; @@ -1601,7 +1455,7 @@ int app_crypt_test(int argc, const char *const *argv, struct command_line_option return 0; } -int app_node_info(int argc, const char *const *argv, struct command_line_option *o) +int app_node_info(int argc, const char *const *argv, struct command_line_option *o, void *context) { if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv); const char *sid; @@ -1764,10 +1618,10 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option Keep this list alphabetically sorted for user convenience. */ -command_line_option command_line_options[]={ +struct command_line_option command_line_options[]={ {app_dna_lookup,{"dna","lookup","","[]",NULL},0, "Lookup the SIP/MDP address of the supplied telephone number (DID)."}, - {cli_usage,{"help",NULL},0, + {commandline_usage,{"help",NULL},0, "Display command usage."}, {app_echo,{"echo","...",NULL},CLIFLAG_STANDALONE, "Output the supplied string."}, @@ -1827,8 +1681,8 @@ command_line_option command_line_options[]={ "Return information about SID, and optionally ask for DID resolution via network"}, {app_test_rfs,{"test","rfs",NULL},0, "Test RFS field calculation"}, - {app_monitor_cli,{"monitor","[]",NULL},0, - "Interactive servald monitor interface. Specify SID to auto-dial that peer and insert dummy audio data"}, + {app_monitor_cli,{"monitor",NULL},0, + "Interactive servald monitor interface."}, {app_crypt_test,{"crypt","test",NULL},0, "Run cryptography speed test"}, #ifdef HAVE_VOIPTEST diff --git a/monitor-cli.c b/monitor-cli.c index ba1d73f9..b90aaa41 100644 --- a/monitor-cli.c +++ b/monitor-cli.c @@ -25,282 +25,68 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" +#include "cli.h" +#include "monitor-client.h" -static char cmd[1024]; -static int cmdLen=0; -static int cmdOfs=0; -static int dataBytesExpected=0; -static unsigned char data[65536]; -static int dataBytes=0; +int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){ + int i; + printf("%s",cmd); + for (i=0;iname:NULL; - if (!name) { - WHY("Could not detect any audio device. Will not pipe audio."); - pipeAudio=0; - } - } - - struct pollfd fds[128]; - int fdcount=0; - - fds[fdcount].fd=fd; - fds[fdcount].events=POLLIN; - fdcount++; - if (interactiveP) { - fds[fdcount].fd=STDIN_FILENO; - fds[fdcount].events=POLLIN; - fdcount++; - } - - write_str(fd, "monitor vomp\n"); - write_str(fd, "monitor rhizome\n"); - - if (sid!=NULL&&sid[0]) { - char msg[1024]; - snprintf(msg,1024,"call %s 5551 5552\n",argv[1]); - write_str(fd, msg); - } - - char line[1024]; - /* Allow for up to one second of audio read from the microphone - to be buffered. This is probably more than we will ever need. - The primary purpose of the buffer is in fact to handle the fact - that we are unlikely to ever read exaclty the number of samples - we need, so we need to keep any left over ones from the previous - read. */ - int audioRecordBufferBytes=0; - int audioRecordBufferSize=8000*2; - unsigned char audioRecordBuffer[8000*2]; - - int base_fd_count=fdcount; - while(1) { - fdcount=base_fd_count; - if (audev&&audev->poll_fds) fdcount+=audev->poll_fds(&fds[fdcount],128-fdcount); - poll(fds,fdcount,1000); - - set_nonblock(fd); - if (interactiveP) - set_nonblock(STDIN_FILENO); - - int bytes; - int i; - line[0]=0; - bytes=read(fd,line,1024); - if (bytes>0) - for(i=0;i0) { - line[bytes]=0; - printf("< %s",line); - write(fd,line,bytes); + struct pollfd fds[2]; + struct monitor_state *state; + + int monitor_client_fd = monitor_client_open(&state); + + set_nonblock(STDIN_FILENO); + set_nonblock(monitor_client_fd); + + fds[0].fd = STDIN_FILENO; + fds[0].events = POLLIN; + fds[1].fd = monitor_client_fd; + fds[1].events = POLLIN; + + while(1){ + int r = poll(fds, 2, 100); + if (r>0){ + + if (fds[0].revents & POLLIN){ + char buff[256]; + int bytes = read(STDIN_FILENO, buff, sizeof(buff)); + set_block(monitor_client_fd); + write(monitor_client_fd, buff, bytes); + set_nonblock(monitor_client_fd); } - } - - if (audev&&audev->read) - { - WHY("about to read"); - int bytesRead=audev->read(&audioRecordBuffer[audioRecordBufferBytes], - audioRecordBufferSize-audioRecordBufferBytes); - WHY("read"); - if (bytesRead>0) audioRecordBufferBytes+=bytesRead; - - /* 8KHz 16 bit samples = 16000 bytes per second. - Thus one 1ms of audio = 16 bytes. */ - int audioRecordBufferOffset=0; - while ((audioRecordBufferBytes-audioRecordBufferOffset) - >recordCodecTimespan*16) { - /* encode and deliver audio block to servald via monitor interface */ - encodeAndDispatchRecordedAudio(fd,callSessionToken,recordCodec, - &audioRecordBuffer[audioRecordBufferOffset], - recordCodecTimespan*16); - WHY("sample block sent"); - /* skip over the samples we have already processed */ - audioRecordBufferOffset+=recordCodecTimespan*16; + + if (fds[1].revents & POLLIN){ + if (monitor_client_read(monitor_client_fd, state, monitor_handlers, + sizeof(monitor_handlers)/sizeof(struct monitor_command_handler))<0){ + break; } - /* copy the remaining buffered bytes down and correct buffer length */ - if (audioRecordBufferOffset<0) audioRecordBufferOffset=0; - if (audioRecordBufferOffset>audioRecordBufferBytes) - audioRecordBufferOffset=audioRecordBufferBytes; - bcopy(&audioRecordBuffer[audioRecordBufferOffset], - &audioRecordBuffer[0], - audioRecordBufferBytes-audioRecordBufferOffset); - audioRecordBufferBytes-=audioRecordBufferOffset; } - - set_block(fd); - if (interactiveP) - set_block(STDIN_FILENO); + + if (fds[0].revents & (POLLHUP | POLLERR)) + break; + } } + monitor_client_close(monitor_client_fd, state); + monitor_client_fd=-1; + return 0; } -int counter=0; -int callState=0; -int processLine(char *cmd,unsigned char *data,int dataLen) -{ - int l_id,r_id,l_state,r_state,codec; - time_ms_t start_time, end_time; - if (showReceived) { - printf("> %s\n",cmd); - if (data) { - int i,j; - for(i=0;i=0x20&&data[i+j]<0x7e) - printf("%c",data[i+j]); else printf("."); - } - printf("\n"); - } - } - } - if (sscanf(cmd,"AUDIOPACKET:%x:%x:%d:%d:%d:%lld:%lld", - &l_id,&r_id,&l_state,&r_state, &codec, &start_time, &end_time)==7) - { - if (pipeAudio&&audev&&fast_audio) { - bufferAudioForPlayback(codec, start_time, end_time, data, dataLen); - } - } - char msg[1024]; - if (sscanf(cmd,"CALLSTATUS:%x:%x:%d:%d:%d", - &l_id,&r_id,&l_state,&r_state,&fast_audio)==5) - { - if (l_state<5&&l_id&&pipeAudio) { - // Take control of audio for this call, and let the java side know - snprintf(msg,1024,"FASTAUDIO:%x:1\n",l_id); - write_str(fd, msg); - } - if (l_state==4&&autoAnswerP) { - // We are ringing, so pickup - sprintf(msg,"pickup %x\n",l_id); - write_str(fd, msg); - } - if (l_state==5) { - if (fast_audio) { - startAudio(); - } - callSessionToken=l_id; - } else { - stopAudio(); - callSessionToken=0; - } - callState=l_state; - } - if (sscanf(cmd,"KEEPALIVE:%x",&l_id)==1) { - if (callState==5&&syntheticAudio) { - /* Send synthetic audio packet */ - char buffer[1024]; - sprintf(buffer,"*320:AUDIO:%x:8\n" - "%08d pasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456" - "qwertyuiopasdfghjklzxcvbnm123456",l_id,counter++); - write_str(fd, buffer); - printf("< *320:AUDIO:%x:8\\n<320 bytes>\n",l_id); - } - } - cmd[0]=0; - cmdLen=0; - dataBytes=0; - dataBytesExpected=0; - state=STATE_CMD; - return 0; -} - -int processChar(int c) -{ - switch(state) { - case STATE_CMD: - if (c!='\n') { - if (cmdLen<1000) { - cmd[cmdLen++]=c; - } - } else { - if (!cmdLen) return 0; - cmd[cmdLen]=0; - if (sscanf(cmd,"*%d:%n",&dataBytesExpected,&cmdOfs)==1) { - if (dataBytesExpected<0) dataBytesExpected=0; - if (dataBytesExpected>65535) dataBytesExpected=65535; - state=STATE_DATA; - } else { - processLine(cmd,NULL,0); - cmdLen=0; - } - } - break; - case STATE_DATA: - if (dataBytes=dataBytesExpected) { - processLine(&cmd[cmdOfs],data,dataBytes); - cmdLen=0; - } - } - return 0; -} diff --git a/monitor-client.c b/monitor-client.c index 89cc8c2c..e1e9a86c 100644 --- a/monitor-client.c +++ b/monitor-client.c @@ -65,7 +65,6 @@ struct monitor_state { int bufferBytes; }; -// FIX ME, COPY-PASTA from monitor.c int monitor_socket_name(struct sockaddr_un *name){ int len; #ifdef linux diff --git a/monitor-client.h b/monitor-client.h index f7bb602d..810058a1 100644 --- a/monitor-client.h +++ b/monitor-client.h @@ -32,5 +32,6 @@ int monitor_client_writeline(int fd,char *fmt, ...); int monitor_client_writeline_and_data(int fd,unsigned char *data,int bytes,char *fmt,...); int monitor_client_read(int fd, struct monitor_state *res, struct monitor_command_handler *handlers, int handler_count); int monitor_client_close(int fd, struct monitor_state *res); +int monitor_socket_name(struct sockaddr_un *name); #endif \ No newline at end of file diff --git a/monitor.c b/monitor.c index 7129682d..7fc5f447 100644 --- a/monitor.c +++ b/monitor.c @@ -23,9 +23,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. data structures (except for a binary extent for an audio sample block). */ +#include #include "serval.h" #include "rhizome.h" -#include +#include "cli.h" +#include "str.h" +#include "overlay_address.h" +#include "monitor-client.h" #if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED) #define SO_PEERCRED LOCAL_PEERCRED @@ -44,8 +48,6 @@ struct monitor_context { unsigned char buffer[MONITOR_DATA_SIZE]; int data_expected; int data_offset; - int sample_codec; - int sample_call_session_token; }; #define MAX_MONITOR_SOCKETS 8 @@ -60,28 +62,6 @@ struct sched_ent named_socket; struct profile_total named_stats; struct profile_total client_stats; -int monitor_socket_name(struct sockaddr_un *name){ - int len; -#ifdef linux - /* Use abstract namespace as Android has no writable FS which supports sockets. - Abstract namespace is just plain better, anyway, as no dead files end up - hanging around. */ - name->sun_path[0]=0; - /* XXX: 104 comes from OSX sys/un.h - no #define (note Linux has UNIX_PATH_MAX and it's 108(!)) */ - snprintf(&name->sun_path[1],104-2, - confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME)); - /* Doesn't include trailing nul */ - len = 1+strlen(&name->sun_path[1]) + sizeof(name->sun_family); -#else - snprintf(name->sun_path,104-1,"%s/%s", - serval_instancepath(), - confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME)); - /* Includes trailing nul */ - len = 1+strlen(name->sun_path) + sizeof(name->sun_family); -#endif - return len; -} - int monitor_setup_sockets() { struct sockaddr_un name; @@ -136,6 +116,13 @@ int monitor_setup_sockets() return -1; } +int monitor_write_error(struct monitor_context *c, const char *error){ + char msg[256]; + snprintf(msg, sizeof(msg), "\nERROR:%s\n", error); + write_str(c->alarm.poll.fd, msg); + return -1; +} + void monitor_poll(struct sched_ent *alarm) { int s; @@ -165,7 +152,7 @@ void monitor_poll(struct sched_ent *alarm) } } -void monitor_client_close(struct monitor_context *c){ +static void monitor_close(struct monitor_context *c){ struct monitor_context *last; INFO("Tearing down monitor client"); @@ -197,11 +184,10 @@ void monitor_client_poll(struct sched_ent *alarm) bytes = 1; while(bytes == 1) { if (c->line_length >= MONITOR_LINE_LENGTH) { - /* line too long */ - c->line[MONITOR_LINE_LENGTH-1] = 0; - monitor_process_command(c); - bytes = -1; - break; + c->line_length=0; + monitor_write_error(c,"Command too long"); + monitor_close(c); + return; } bytes = read(c->alarm.poll.fd, &c->line[c->line_length], 1); if (bytes < 1) { @@ -216,54 +202,80 @@ void monitor_client_poll(struct sched_ent *alarm) default: WHY_perror("read"); /* all other errors; close socket */ - monitor_client_close(c); + monitor_close(c); return; } } - if (bytes > 0 && (c->line[c->line_length] != '\r')) { - c->line_length += bytes; - if (c->line[c->line_length-1] == '\n') { - /* got command */ - c->line[c->line_length-1] = 0; /* trim new line for easier parsing */ - monitor_process_command(c); - break; - } - } - } - break; - case MONITOR_STATE_DATA: - bytes = read(c->alarm.poll.fd, - &c->buffer[c->data_offset], - c->data_expected-c->data_offset); - if (bytes < 1) { - switch(errno) { - case EAGAIN: case EINTR: - /* transient errors */ + + // silently skip all \r characters + if (c->line[c->line_length] == '\r') + continue; + + // parse data length as soon as we see the : delimiter, + // so we can read the rest of the line into the start of the buffer + if (c->data_expected==0 && c->line[0]=='*' && c->line[c->line_length]==':'){ + c->line[c->line_length]=0; + c->data_expected=atoi(c->line +1); + c->line_length=0; + continue; + } + + if (c->line[c->line_length] == '\n') { + /* got whole command line, start reading data if required */ + c->line[c->line_length]=0; + c->state=MONITOR_STATE_DATA; + c->data_offset=0; break; - default: - /* all other errors; close socket */ - WHYF("Tearing down monitor client due to errno=%d", - errno); - monitor_client_close(c); - return; } - } else { - c->data_offset += bytes; - if (c->data_offset >= c->data_expected) - { - /* we have the binary data we were expecting. */ - monitor_process_data(c); - c->state = MONITOR_STATE_COMMAND; - } + + c->line_length += bytes; } - break; + + if (c->state!=MONITOR_STATE_DATA) + break; + + // else fall through + case MONITOR_STATE_DATA: + + if (c->data_expected - c->data_offset >0){ + bytes = read(c->alarm.poll.fd, + &c->buffer[c->data_offset], + c->data_expected - c->data_offset); + if (bytes < 1) { + switch(errno) { + case EAGAIN: case EINTR: + /* transient errors */ + break; + default: + /* all other errors; close socket */ + WHYF("Tearing down monitor client due to errno=%d", + errno); + monitor_close(c); + return; + } + } + + c->data_offset += bytes; + } + + if (c->data_offset < c->data_expected) + break; + + /* we have the next command and all of the binary data we were expecting. Now we can process it */ + monitor_process_command(c); + + // fall through default: + // reset parsing state c->state = MONITOR_STATE_COMMAND; - WHY("fixed monitor connection state"); + c->data_expected = 0; + c->data_offset = 0; + c->line_length = 0; } } + if (alarm->poll.revents & (POLLHUP | POLLERR)) { - monitor_client_close(c); + monitor_close(c); } return; } @@ -334,148 +346,181 @@ static void monitor_new_client(int s) { return; } -int monitor_send_lookup_response(const char *sid, const int port, const char *ext, const char *name){ +static int monitor_set(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + if (strcase_startswith((char *)argv[1],"vomp",NULL)) + c->flags|=MONITOR_VOMP; + else if (strcase_startswith((char *)argv[1],"rhizome", NULL)) + c->flags|=MONITOR_RHIZOME; + else if (strcase_startswith((char *)argv[1],"peers", NULL)) + c->flags|=MONITOR_PEERS; + else if (strcase_startswith((char *)argv[1],"dnahelper", NULL)) + c->flags|=MONITOR_DNAHELPER; + else + return monitor_write_error(c,"Unknown monitor type"); + + char msg[1024]; + snprintf(msg,sizeof(msg),"\nMONITORSTATUS:%d\n",c->flags); + write_str(c->alarm.poll.fd,msg); + + return 0; +} + +static int monitor_clear(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + if (strcase_startswith((char *)argv[1],"vomp",NULL)) + c->flags&=~MONITOR_VOMP; + else if (strcase_startswith((char *)argv[1],"rhizome", NULL)) + c->flags&=~MONITOR_RHIZOME; + else if (strcase_startswith((char *)argv[1],"peers", NULL)) + c->flags&=~MONITOR_PEERS; + else if (strcase_startswith((char *)argv[1],"dnahelper", NULL)) + c->flags&=~MONITOR_DNAHELPER; + else + return monitor_write_error(c,"Unknown monitor type"); + + char msg[1024]; + snprintf(msg,sizeof(msg),"\nMONITORSTATUS:%d\n",c->flags); + write_str(c->alarm.poll.fd,msg); + + return 0; +} + +static int monitor_lookup_match(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + const char *sid=argv[2]; + const char *ext=argv[4]; + const char *name=argv[5]; + + if (!my_subscriber) + return monitor_write_error(c,"I don't know who I am"); + struct sockaddr_mdp addr={ - .port = port + .port = atoi(argv[3]), }; if (stowSid((unsigned char *)&addr.sid, 0, sid)==-1) - return WHYF("Invalid SID %s", sid); + return monitor_write_error(c,"Invalid SID"); - int cn=0, in=0, kp=0; - if (!keyring_next_identity(keyring, &cn, &in, &kp)) - WHY("No local identity, cannot send DNA LOOKUP reply"); - else{ - char uri[256]; - snprintf(uri, sizeof(uri), "sid://%s/external/%s", alloca_tohex_sid(keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key), ext); - DEBUGF("Sending response to %s for %s", sid, uri); - overlay_mdp_dnalookup_reply(&addr, keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key, uri, ext, name); + char uri[256]; + snprintf(uri, sizeof(uri), "sid://%s/external/%s", alloca_tohex_sid(my_subscriber->sid), ext); + DEBUGF("Sending response to %s for %s", sid, uri); + overlay_mdp_dnalookup_reply(&addr, my_subscriber->sid, uri, ext, name); + return 0; +} + +static int monitor_call(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + unsigned char sid[SID_SIZE]; + if (stowSid(sid, 0, argv[1]) == -1) + return monitor_write_error(c,"invalid SID, so cannot place call"); + + if (!my_subscriber) + return monitor_write_error(c,"I don't know who I am"); + + vomp_dial(my_subscriber->sid, sid, argv[2], argv[3]); + return 0; +} + +static int monitor_call_ring(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16)); + if (!call) + return monitor_write_error(c,"Invalid call token"); + vomp_ringing(call); + return 0; +} + +static int monitor_call_pickup(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16)); + if (!call) + return monitor_write_error(c,"Invalid call token"); + vomp_pickup(call); + return 0; +} + +static int monitor_call_audio(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16)); + if (!call) + return monitor_write_error(c,"Invalid call token"); + vomp_received_audio(call, atoi(argv[2]), c->buffer, c->data_expected); + return 0; +} + +static int monitor_call_hangup(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16)); + if (!call) + return monitor_write_error(c,"Invalid call token"); + vomp_hangup(call); + return 0; +} + +static int monitor_call_dtmf(int argc, const char *const *argv, struct command_line_option *o, void *context){ + struct monitor_context *c=context; + struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16)); + if (!call) + return monitor_write_error(c,"Invalid call token"); + const char *digits = argv[2]; + + int i; + for(i=0;i",NULL},0,""}, + {monitor_clear,{"ignore","",NULL},0,""}, + {monitor_lookup_match,{"lookup","match","","","","",NULL},0,""}, + {monitor_call, {"call","","","",NULL},0,""}, + {monitor_call_ring, {"ringing","",NULL},0,""}, + {monitor_call_pickup, {"pickup","",NULL},0,""}, + {monitor_call_audio,{"audio","","","[]",NULL},0,""}, + {monitor_call_hangup, {"hangup","",NULL},0,""}, + {monitor_call_dtmf, {"dtmf","","",NULL},0,""}, +}; + +static int parse_argv(char *cmdline, char delim, char **argv, int max_argv){ + int argc=0; - char *cmd = c->line; - IN(); + if (*cmdline && argcline_length=0; - - if (strlen(cmd)>MONITOR_LINE_LENGTH) { - write_str(c->alarm.poll.fd,"\nERROR:Command too long\n"); - RETURN(-1); - } - - char msg[1024]; - - if (cmd[0]=='*') { - /* command with content */ - int ofs=0; - if (sscanf(cmd,"*%d:%n",&bytes,&ofs)==1) { - /* work out rest of command */ - cmd=&cmd[ofs]; - c->state=MONITOR_STATE_DATA; - c->data_expected=bytes; - c->data_offset=0; - c->sample_codec=-1; - - if (sscanf(cmd,"AUDIO %x %d", - &callSessionToken,&sampleType)==2) - { - /* Start getting sample */ - c->sample_call_session_token=callSessionToken; - c->sample_codec=sampleType; - RETURN(0); - } + // TODO quoted argument handling? + + while(*cmdline){ + if (*cmdline==delim){ + *cmdline=0; + if (cmdline[1] && argcflags|=MONITOR_VOMP; - else if (strcase_startswith(cmd,"ignore vomp",NULL)) - c->flags&=~MONITOR_VOMP; - else if (strcase_startswith(cmd,"monitor rhizome", NULL)) - c->flags|=MONITOR_RHIZOME; - else if (strcase_startswith(cmd,"ignore rhizome", NULL)) - c->flags&=~MONITOR_RHIZOME; - else if (strcase_startswith(cmd,"monitor peers", NULL)) - c->flags|=MONITOR_PEERS; - else if (strcase_startswith(cmd,"ignore peers", NULL)) - c->flags&=~MONITOR_PEERS; - else if (strcase_startswith(cmd,"monitor dnahelper", NULL)) - c->flags|=MONITOR_DNAHELPER; - else if (strcase_startswith(cmd,"ignore dnahelper", NULL)) - c->flags&=~MONITOR_DNAHELPER; - else if (sscanf(cmd,"lookup match %s %d %s %s",sid,&port,localDid,remoteDid)>=3) { - monitor_send_lookup_response(sid,port,localDid,remoteDid); - }else if (sscanf(cmd,"call %s %s %s",sid,localDid,remoteDid)==3) { - // pack the binary representation of the sid into the same buffer. - if (stowSid((unsigned char*)sid, 0, sid) == -1) - write_str(c->alarm.poll.fd,"\nERROR:invalid SID, so cannot place call\n"); - else { - int cn=0, in=0, kp=0; - if (!keyring_next_identity(keyring, &cn, &in, &kp)) - write_str(c->alarm.poll.fd,"\nERROR:no local identity, so cannot place call\n"); - else { - vomp_dial(keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key, (unsigned char *)sid, localDid, remoteDid); - } - } - } else if (sscanf(cmd,"ringing %x",&callSessionToken)==1) { - struct vomp_call_state *call=vomp_find_call_by_session(callSessionToken); - vomp_ringing(call); - } else if (sscanf(cmd,"pickup %x",&callSessionToken)==1) { - struct vomp_call_state *call=vomp_find_call_by_session(callSessionToken); - vomp_pickup(call); - } - else if (sscanf(cmd,"hangup %x",&callSessionToken)==1) { - struct vomp_call_state *call=vomp_find_call_by_session(callSessionToken); - vomp_hangup(call); - } else if (sscanf(cmd,"dtmf %x %s",&callSessionToken,digits)==2) { - struct vomp_call_state *call=vomp_find_call_by_session(callSessionToken); - if (call){ - int i; - for(i=0;ialarm.poll.fd,msg); - } - /* 80ms standard tone duration, so that it is a multiple - of the majority of codec time units (70ms is the nominal - DTMF tone length for most systems). */ - unsigned char code = digit <<4; - vomp_received_audio(call, VOMP_CODEC_DTMF, &code, 1); - } - } - } - - snprintf(msg,1024,"\nMONITORSTATUS:%d\n",c->flags); - write_str(c->alarm.poll.fd,msg); - - RETURN(0); + return argc; } -int monitor_process_data(struct monitor_context *c) +int monitor_process_command(struct monitor_context *c) { - IN(); - /* Called when we have received an entire data sample */ - c->state=MONITOR_STATE_COMMAND; - - struct vomp_call_state *call=vomp_find_call_by_session(c->sample_call_session_token); - if (!call) { - write_str(c->alarm.poll.fd,"\nERROR:No such call\n"); - RETURN(-1); - } - - vomp_received_audio(call, c->sample_codec, &c->buffer[0], vomp_sample_size(c->sample_codec)); - - RETURN(0); + char *argv[16]={NULL,}; + int argc = parse_argv(c->line, ' ', argv, 16); + + if (cli_execute(NULL, argc, (const char *const*)argv, monitor_options, c)) + return monitor_write_error(c, "Invalid command"); + return 0; } int monitor_announce_bundle(rhizome_manifest *m) @@ -501,7 +546,7 @@ int monitor_announce_bundle(rhizome_manifest *m) || set_block(monitor_sockets[i].alarm.poll.fd) == -1 ) { INFO("Tearing down monitor client"); - monitor_client_close(&monitor_sockets[i]); + monitor_close(&monitor_sockets[i]); } } } @@ -540,7 +585,7 @@ int monitor_tell_clients(char *msg, int msglen, int mask) || set_block(monitor_sockets[i].alarm.poll.fd) == -1 ) { INFOF("Tearing down monitor client #%d", i); - monitor_client_close(&monitor_sockets[i]); + monitor_close(&monitor_sockets[i]); } } } diff --git a/rhizome.h b/rhizome.h index a172cea9..761a683d 100644 --- a/rhizome.h +++ b/rhizome.h @@ -172,8 +172,6 @@ int rhizome_str_is_file_hash(const char *text); #define alloca_tohex_bid(bid) alloca_tohex((bid), RHIZOME_MANIFEST_ID_BYTES) int http_header_complete(const char *buf, size_t len, size_t tail); -int str_startswith(char *str, const char *substring, char **afterp); -int strcase_startswith(char *str, const char *substring, char **afterp); typedef struct sqlite_retry_state { unsigned int limit; // do not retry once elapsed >= limit diff --git a/rhizome_bundle.c b/rhizome_bundle.c index f2c197ea..02230eef 100644 --- a/rhizome_bundle.c +++ b/rhizome_bundle.c @@ -17,9 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include "serval.h" #include "rhizome.h" -#include +#include "str.h" int rhizome_manifest_verify(rhizome_manifest *m) { diff --git a/rhizome_database.c b/rhizome_database.c index e703ce54..6046d3c5 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -18,11 +18,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #define __RHIZOME_INLINE +#include +#include #include "serval.h" #include "rhizome.h" #include "strbuf.h" -#include -#include +#include "str.h" long long rhizome_space=0; static const char *rhizome_thisdatastore_path = NULL; diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 861d98e9..f26845d7 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "serval.h" #include "rhizome.h" +#include "str.h" extern int sigPipeFlag; extern int sigIoFlag; diff --git a/serval.h b/serval.h index f4ea9235..38a35ee9 100644 --- a/serval.h +++ b/serval.h @@ -831,24 +831,12 @@ int vomp_tick_interval(); int vomp_sample_size(int c); int vomp_codec_timespan(int c); int vomp_parse_dtmf_digit(char c); -int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, char *local_did, char *remote_did); +int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, const char *local_did, const char *remote_did); int vomp_pickup(struct vomp_call_state *call); int vomp_hangup(struct vomp_call_state *call); int vomp_ringing(struct vomp_call_state *call); int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length); - -typedef struct command_line_option { - int (*function)(int argc, const char *const *argv, struct command_line_option *o); - const char *words[32]; // 32 words should be plenty! - unsigned long long flags; -#define CLIFLAG_NONOVERLAY (1<<0) /* Uses a legacy IPv4 DNA call instead of overlay mnetwork */ -#define CLIFLAG_STANDALONE (1<<1) /* Cannot be issued to a running instance */ - const char *description; // describe this invocation -} command_line_option; - -extern command_line_option command_line_options[]; -int cli_arg(int argc, const char *const *argv, command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue); int cli_putchar(char c); int cli_puts(const char *str); int cli_printf(const char *fmt, ...); @@ -869,10 +857,11 @@ overlay_interface * overlay_interface_find_name(const char *name); int directory_registration(); int directory_service_init(); +struct command_line_option; #ifdef HAVE_VOIPTEST -int app_pa_phone(int argc, const char *const *argv, struct command_line_option *o); +int app_pa_phone(int argc, const char *const *argv, struct command_line_option *o, void *context); #endif -int app_monitor_cli(int argc, const char *const *argv, struct command_line_option *o); +int app_monitor_cli(int argc, const char *const *argv, struct command_line_option *o, void *context); int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax); diff --git a/vomp.c b/vomp.c index b8b3b4e0..0e69e71d 100644 --- a/vomp.c +++ b/vomp.c @@ -658,7 +658,7 @@ int vomp_call_destroy(struct vomp_call_state *call) return 0; } -int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, char *local_did, char *remote_did) +int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, const char *local_did, const char *remote_did) { /* TODO use local_did and remote_did start putting the call together. These need to be passed to the node being called to provide caller id,