mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-19 05:07:56 +00:00
Reuse command line parsing framework with monitor interface
This commit is contained in:
parent
222cb80ce7
commit
ac3864ff20
@ -12,6 +12,7 @@ SERVALD_SRC_FILES = \
|
|||||||
serval-dna/overlay_mdp.c \
|
serval-dna/overlay_mdp.c \
|
||||||
serval-dna/batman.c \
|
serval-dna/batman.c \
|
||||||
serval-dna/ciphers.c \
|
serval-dna/ciphers.c \
|
||||||
|
serval-dna/cli.c \
|
||||||
serval-dna/client.c \
|
serval-dna/client.c \
|
||||||
serval-dna/commandline.c \
|
serval-dna/commandline.c \
|
||||||
serval-dna/conf.c \
|
serval-dna/conf.c \
|
||||||
@ -53,6 +54,7 @@ SERVALD_SRC_FILES = \
|
|||||||
serval-dna/fdqueue.c \
|
serval-dna/fdqueue.c \
|
||||||
serval-dna/monitor.c \
|
serval-dna/monitor.c \
|
||||||
serval-dna/monitor-cli.c \
|
serval-dna/monitor-cli.c \
|
||||||
|
serval-dna/monitor-client.c \
|
||||||
serval-dna/codecs.c \
|
serval-dna/codecs.c \
|
||||||
serval-dna/audiodevices.c \
|
serval-dna/audiodevices.c \
|
||||||
serval-dna/audio_msm_g1.c \
|
serval-dna/audio_msm_g1.c \
|
||||||
|
@ -5,6 +5,7 @@ SRCS= \
|
|||||||
audio_reflector.c \
|
audio_reflector.c \
|
||||||
batman.c \
|
batman.c \
|
||||||
ciphers.c \
|
ciphers.c \
|
||||||
|
cli.c \
|
||||||
client.c \
|
client.c \
|
||||||
codecs.c \
|
codecs.c \
|
||||||
commandline.c \
|
commandline.c \
|
||||||
@ -24,6 +25,7 @@ SRCS= \
|
|||||||
mdp_client.c \
|
mdp_client.c \
|
||||||
mkdir.c \
|
mkdir.c \
|
||||||
monitor.c \
|
monitor.c \
|
||||||
|
monitor-client.c \
|
||||||
monitor-cli.c \
|
monitor-cli.c \
|
||||||
net.c \
|
net.c \
|
||||||
overlay.c \
|
overlay.c \
|
||||||
|
164
cli.c
Normal file
164
cli.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#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);
|
||||||
|
}
|
30
cli.h
Normal file
30
cli.h
Normal file
@ -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
|
214
commandline.c
214
commandline.c
@ -38,17 +38,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
#include "rhizome.h"
|
#include "rhizome.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "mdp_client.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 <version>.\n");
|
printf("Serval Mesh version <version>.\n");
|
||||||
printf("Usage:\n");
|
return cli_usage(command_line_options);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data structures for accumulating output of a single JNI call.
|
/* 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 parseCommandLine(const char *argv0, int argc, const char *const *args)
|
||||||
{
|
{
|
||||||
int ambiguous=0;
|
|
||||||
int cli_call=-1;
|
|
||||||
fd_clearstats();
|
fd_clearstats();
|
||||||
IN();
|
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();
|
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 */
|
/* clean up after ourselves */
|
||||||
overlay_mdp_client_done();
|
overlay_mdp_client_done();
|
||||||
OUT();
|
OUT();
|
||||||
@ -265,34 +195,6 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args)
|
|||||||
return result;
|
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
|
/* 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
|
current output field. Returns the character written cast to an unsigned char then to int, or EOF
|
||||||
on error.
|
on error.
|
||||||
@ -392,7 +294,7 @@ int cli_delim(const char *opt)
|
|||||||
return 0;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
int i;
|
int i;
|
||||||
@ -405,12 +307,7 @@ int app_echo(int argc, const char *const *argv, struct command_line_option *o)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_lookup_did(const char *text)
|
int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
int i;
|
int i;
|
||||||
@ -555,12 +452,7 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_absolute_path(const char *arg)
|
int app_server_start(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
return arg[0] == '/' && arg[1] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
int app_server_start(int argc, const char *const *argv, struct command_line_option *o)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
/* Process optional arguments */
|
/* Process optional arguments */
|
||||||
@ -711,7 +603,7 @@ int app_server_start(int argc, const char *const *argv, struct command_line_opti
|
|||||||
return ret;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
int pid, tries, running;
|
int pid, tries, running;
|
||||||
@ -778,7 +670,7 @@ int app_server_stop(int argc, const char *const *argv, struct command_line_optio
|
|||||||
return 0;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
int pid;
|
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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *sid, *count;
|
const char *sid, *count;
|
||||||
@ -952,7 +844,7 @@ int app_mdp_ping(int argc, const char *const *argv, struct command_line_option *
|
|||||||
return ret;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *var, *val;
|
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();
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *var;
|
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();
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *var;
|
const char *var;
|
||||||
@ -1006,7 +898,7 @@ int app_config_get(int argc, const char *const *argv, struct command_line_option
|
|||||||
return 0;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
/* compute hash of file. We do this without a manifest, so it will necessarily
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_optional_sid(const char *arg)
|
int app_rhizome_add_file(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *filepath, *manifestpath, *authorSidHex, *pin, *bskhex;
|
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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *filepath, *manifestpath;
|
const char *filepath, *manifestpath;
|
||||||
@ -1286,12 +1168,7 @@ int app_rhizome_import_bundle(int argc, const char *const *argv, struct command_
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_manifestid(const char *arg)
|
int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
return rhizome_str_is_manifest_id(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int app_rhizome_extract_manifest(int argc, const char *const *argv, struct command_line_option *o)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *manifestid, *manifestpath;
|
const char *manifestid, *manifestpath;
|
||||||
@ -1327,17 +1204,7 @@ int app_rhizome_extract_manifest(int argc, const char *const *argv, struct comma
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_fileid(const char *arg)
|
int app_rhizome_extract_file(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *fileid, *filepath, *keyhex;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_uint(const char *arg)
|
int app_rhizome_list(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *pin, *service, *sender_sid, *recipient_sid, *offset, *limit;
|
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));
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *pin;
|
const char *pin;
|
||||||
@ -1405,7 +1264,7 @@ int app_keyring_create(int argc, const char *const *argv, struct command_line_op
|
|||||||
return 0;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *pin;
|
const char *pin;
|
||||||
@ -1432,7 +1291,7 @@ int app_keyring_list(int argc, const char *const *argv, struct command_line_opti
|
|||||||
return 0;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *pin;
|
const char *pin;
|
||||||
@ -1477,12 +1336,7 @@ int app_keyring_add(int argc, const char *const *argv, struct command_line_optio
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_optional_did(const char *text)
|
int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
|
||||||
return text[0] == '\0' || str_is_did(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o)
|
|
||||||
{
|
{
|
||||||
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *sid, *did, *pin, *name;
|
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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
/* List my own identities */
|
/* 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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
printf("Testing that RFS coder works properly.\n");
|
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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
|
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;
|
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);
|
if (debug & DEBUG_VERBOSE) DEBUG_argv("command", argc, argv);
|
||||||
const char *sid;
|
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.
|
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","<did>","[<timeout>]",NULL},0,
|
{app_dna_lookup,{"dna","lookup","<did>","[<timeout>]",NULL},0,
|
||||||
"Lookup the SIP/MDP address of the supplied telephone number (DID)."},
|
"Lookup the SIP/MDP address of the supplied telephone number (DID)."},
|
||||||
{cli_usage,{"help",NULL},0,
|
{commandline_usage,{"help",NULL},0,
|
||||||
"Display command usage."},
|
"Display command usage."},
|
||||||
{app_echo,{"echo","...",NULL},CLIFLAG_STANDALONE,
|
{app_echo,{"echo","...",NULL},CLIFLAG_STANDALONE,
|
||||||
"Output the supplied string."},
|
"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"},
|
"Return information about SID, and optionally ask for DID resolution via network"},
|
||||||
{app_test_rfs,{"test","rfs",NULL},0,
|
{app_test_rfs,{"test","rfs",NULL},0,
|
||||||
"Test RFS field calculation"},
|
"Test RFS field calculation"},
|
||||||
{app_monitor_cli,{"monitor","[<sid>]",NULL},0,
|
{app_monitor_cli,{"monitor",NULL},0,
|
||||||
"Interactive servald monitor interface. Specify SID to auto-dial that peer and insert dummy audio data"},
|
"Interactive servald monitor interface."},
|
||||||
{app_crypt_test,{"crypt","test",NULL},0,
|
{app_crypt_test,{"crypt","test",NULL},0,
|
||||||
"Run cryptography speed test"},
|
"Run cryptography speed test"},
|
||||||
#ifdef HAVE_VOIPTEST
|
#ifdef HAVE_VOIPTEST
|
||||||
|
316
monitor-cli.c
316
monitor-cli.c
@ -25,282 +25,68 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
|
#include "cli.h"
|
||||||
|
#include "monitor-client.h"
|
||||||
|
|
||||||
static char cmd[1024];
|
int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||||
static int cmdLen=0;
|
|
||||||
static int cmdOfs=0;
|
|
||||||
static int dataBytesExpected=0;
|
|
||||||
static unsigned char data[65536];
|
|
||||||
static int dataBytes=0;
|
|
||||||
|
|
||||||
#define STATE_CMD 1
|
|
||||||
#define STATE_DATA 2
|
|
||||||
static int state=STATE_CMD;
|
|
||||||
|
|
||||||
static int fd;
|
|
||||||
|
|
||||||
static int processChar(int c);
|
|
||||||
|
|
||||||
static int autoAnswerP=1;
|
|
||||||
static int pipeAudio=1;
|
|
||||||
static int reflectAudio=0;
|
|
||||||
static int syntheticAudio=0;
|
|
||||||
static int showReceived=1;
|
|
||||||
static int interactiveP=1;
|
|
||||||
static int recordCodec=VOMP_CODEC_PCM;
|
|
||||||
static int recordCodecTimespan=20;
|
|
||||||
static int callSessionToken=0;
|
|
||||||
static int fast_audio=0;
|
|
||||||
|
|
||||||
int app_monitor_cli(int argc, const char *const *argv, struct command_line_option *o)
|
|
||||||
{
|
|
||||||
const char *sid=NULL;
|
|
||||||
cli_arg(argc, argv, o, "sid", &sid, NULL, "");
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
|
|
||||||
if (!strcasecmp(sid,"reflect")) {
|
|
||||||
pipeAudio=1; reflectAudio=1;
|
|
||||||
sid="";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
||||||
perror("socket");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
addr.sun_path[0]=0;
|
|
||||||
snprintf(&addr.sun_path[1],100,"%s",
|
|
||||||
confValueGet("monitor.socket",DEFAULT_MONITOR_SOCKET_NAME));
|
|
||||||
int len = 1+strlen(&addr.sun_path[1]) + sizeof(addr.sun_family);
|
|
||||||
char *p=(char *)&addr;
|
|
||||||
printf("last char='%c' %02x\n",p[len-1],p[len-1]);
|
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr*)&addr, len) == -1) {
|
|
||||||
perror("connect");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipeAudio) {
|
|
||||||
if (reflectAudio)
|
|
||||||
audev=audio_reflector_detect();
|
|
||||||
else
|
|
||||||
detectAudioDevice();
|
|
||||||
char *name=audev?audev->name: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;
|
int i;
|
||||||
line[0]=0;
|
printf("%s",cmd);
|
||||||
bytes=read(fd,line,1024);
|
for (i=0;i<argc;i++){
|
||||||
if (bytes>0)
|
printf(" %s",argv[i]);
|
||||||
for(i=0;i<bytes;i++) processChar(line[i]);
|
|
||||||
if (interactiveP) {
|
|
||||||
bytes=read(STDIN_FILENO,line,1024);
|
|
||||||
if (bytes>0) {
|
|
||||||
line[bytes]=0;
|
|
||||||
printf("< %s",line);
|
|
||||||
write(fd,line,bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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<dataLen;i+=16) {
|
|
||||||
printf(" %04x :",i);
|
|
||||||
for(j=0;j<16;j++)
|
|
||||||
if (i+j<dataLen) printf(" %02x",data[i+j]); else printf(" ");
|
|
||||||
printf(" ");
|
|
||||||
for(j=0;j<16;j++)
|
|
||||||
if (i+j<dataLen) {
|
|
||||||
if (data[i+j]>=0x20&&data[i+j]<0x7e)
|
|
||||||
printf("%c",data[i+j]); else printf(".");
|
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
if (dataLen){
|
||||||
|
dump(NULL,data,dataLen);
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (sscanf(cmd,"AUDIOPACKET:%x:%x:%d:%d:%d:%lld:%lld",
|
struct monitor_command_handler monitor_handlers[]={
|
||||||
&l_id,&r_id,&l_state,&r_state, &codec, &start_time, &end_time)==7)
|
{.command="", .handler=remote_print},
|
||||||
|
};
|
||||||
|
|
||||||
|
int app_monitor_cli(int argc, const char *const *argv, struct command_line_option *o, void *context)
|
||||||
{
|
{
|
||||||
if (pipeAudio&&audev&&fast_audio) {
|
struct pollfd fds[2];
|
||||||
bufferAudioForPlayback(codec, start_time, end_time, data, dataLen);
|
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 (fds[1].revents & POLLIN){
|
||||||
|
if (monitor_client_read(monitor_client_fd, state, monitor_handlers,
|
||||||
|
sizeof(monitor_handlers)/sizeof(struct monitor_command_handler))<0){
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char msg[1024];
|
|
||||||
if (sscanf(cmd,"CALLSTATUS:%x:%x:%d:%d:%d",
|
if (fds[0].revents & (POLLHUP | POLLERR))
|
||||||
&l_id,&r_id,&l_state,&r_state,&fast_audio)==5)
|
break;
|
||||||
{
|
|
||||||
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;
|
monitor_client_close(monitor_client_fd, state);
|
||||||
dataBytes=0;
|
monitor_client_fd=-1;
|
||||||
dataBytesExpected=0;
|
|
||||||
state=STATE_CMD;
|
|
||||||
return 0;
|
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)
|
|
||||||
data[dataBytes++]=c;
|
|
||||||
if (dataBytes>=dataBytesExpected) {
|
|
||||||
processLine(&cmd[cmdOfs],data,dataBytes);
|
|
||||||
cmdLen=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
@ -65,7 +65,6 @@ struct monitor_state {
|
|||||||
int bufferBytes;
|
int bufferBytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIX ME, COPY-PASTA from monitor.c
|
|
||||||
int monitor_socket_name(struct sockaddr_un *name){
|
int monitor_socket_name(struct sockaddr_un *name){
|
||||||
int len;
|
int len;
|
||||||
#ifdef linux
|
#ifdef linux
|
||||||
|
@ -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_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_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_client_close(int fd, struct monitor_state *res);
|
||||||
|
int monitor_socket_name(struct sockaddr_un *name);
|
||||||
|
|
||||||
#endif
|
#endif
|
373
monitor.c
373
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).
|
data structures (except for a binary extent for an audio sample block).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
#include "rhizome.h"
|
#include "rhizome.h"
|
||||||
#include <sys/stat.h>
|
#include "cli.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "overlay_address.h"
|
||||||
|
#include "monitor-client.h"
|
||||||
|
|
||||||
#if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED)
|
#if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED)
|
||||||
#define SO_PEERCRED LOCAL_PEERCRED
|
#define SO_PEERCRED LOCAL_PEERCRED
|
||||||
@ -44,8 +48,6 @@ struct monitor_context {
|
|||||||
unsigned char buffer[MONITOR_DATA_SIZE];
|
unsigned char buffer[MONITOR_DATA_SIZE];
|
||||||
int data_expected;
|
int data_expected;
|
||||||
int data_offset;
|
int data_offset;
|
||||||
int sample_codec;
|
|
||||||
int sample_call_session_token;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_MONITOR_SOCKETS 8
|
#define MAX_MONITOR_SOCKETS 8
|
||||||
@ -60,28 +62,6 @@ struct sched_ent named_socket;
|
|||||||
struct profile_total named_stats;
|
struct profile_total named_stats;
|
||||||
struct profile_total client_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()
|
int monitor_setup_sockets()
|
||||||
{
|
{
|
||||||
struct sockaddr_un name;
|
struct sockaddr_un name;
|
||||||
@ -136,6 +116,13 @@ int monitor_setup_sockets()
|
|||||||
return -1;
|
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)
|
void monitor_poll(struct sched_ent *alarm)
|
||||||
{
|
{
|
||||||
int s;
|
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;
|
struct monitor_context *last;
|
||||||
|
|
||||||
INFO("Tearing down monitor client");
|
INFO("Tearing down monitor client");
|
||||||
@ -197,11 +184,10 @@ void monitor_client_poll(struct sched_ent *alarm)
|
|||||||
bytes = 1;
|
bytes = 1;
|
||||||
while(bytes == 1) {
|
while(bytes == 1) {
|
||||||
if (c->line_length >= MONITOR_LINE_LENGTH) {
|
if (c->line_length >= MONITOR_LINE_LENGTH) {
|
||||||
/* line too long */
|
c->line_length=0;
|
||||||
c->line[MONITOR_LINE_LENGTH-1] = 0;
|
monitor_write_error(c,"Command too long");
|
||||||
monitor_process_command(c);
|
monitor_close(c);
|
||||||
bytes = -1;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
bytes = read(c->alarm.poll.fd, &c->line[c->line_length], 1);
|
bytes = read(c->alarm.poll.fd, &c->line[c->line_length], 1);
|
||||||
if (bytes < 1) {
|
if (bytes < 1) {
|
||||||
@ -216,22 +202,42 @@ void monitor_client_poll(struct sched_ent *alarm)
|
|||||||
default:
|
default:
|
||||||
WHY_perror("read");
|
WHY_perror("read");
|
||||||
/* all other errors; close socket */
|
/* all other errors; close socket */
|
||||||
monitor_client_close(c);
|
monitor_close(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bytes > 0 && (c->line[c->line_length] != '\r')) {
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
c->line_length += bytes;
|
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 */
|
if (c->state!=MONITOR_STATE_DATA)
|
||||||
monitor_process_command(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// else fall through
|
||||||
case MONITOR_STATE_DATA:
|
case MONITOR_STATE_DATA:
|
||||||
|
|
||||||
|
if (c->data_expected - c->data_offset >0){
|
||||||
bytes = read(c->alarm.poll.fd,
|
bytes = read(c->alarm.poll.fd,
|
||||||
&c->buffer[c->data_offset],
|
&c->buffer[c->data_offset],
|
||||||
c->data_expected - c->data_offset);
|
c->data_expected - c->data_offset);
|
||||||
@ -244,26 +250,32 @@ void monitor_client_poll(struct sched_ent *alarm)
|
|||||||
/* all other errors; close socket */
|
/* all other errors; close socket */
|
||||||
WHYF("Tearing down monitor client due to errno=%d",
|
WHYF("Tearing down monitor client due to errno=%d",
|
||||||
errno);
|
errno);
|
||||||
monitor_client_close(c);
|
monitor_close(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
c->data_offset += bytes;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->data_offset < c->data_expected)
|
||||||
break;
|
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:
|
default:
|
||||||
|
// reset parsing state
|
||||||
c->state = MONITOR_STATE_COMMAND;
|
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)) {
|
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
||||||
monitor_client_close(c);
|
monitor_close(c);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -334,118 +346,131 @@ static void monitor_new_client(int s) {
|
|||||||
return;
|
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 sockaddr_mdp addr={
|
struct monitor_context *c=context;
|
||||||
.port = port
|
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");
|
||||||
|
|
||||||
if (stowSid((unsigned char *)&addr.sid, 0, sid)==-1)
|
char msg[1024];
|
||||||
return WHYF("Invalid SID %s", sid);
|
snprintf(msg,sizeof(msg),"\nMONITORSTATUS:%d\n",c->flags);
|
||||||
|
write_str(c->alarm.poll.fd,msg);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int monitor_process_command(struct monitor_context *c)
|
static int monitor_clear(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||||
{
|
struct monitor_context *c=context;
|
||||||
int callSessionToken,sampleType,bytes;
|
if (strcase_startswith((char *)argv[1],"vomp",NULL))
|
||||||
char sid[MONITOR_LINE_LENGTH],localDid[MONITOR_LINE_LENGTH];
|
c->flags&=~MONITOR_VOMP;
|
||||||
char remoteDid[MONITOR_LINE_LENGTH],digits[MONITOR_LINE_LENGTH];
|
else if (strcase_startswith((char *)argv[1],"rhizome", NULL))
|
||||||
int port;
|
c->flags&=~MONITOR_RHIZOME;
|
||||||
|
else if (strcase_startswith((char *)argv[1],"peers", NULL))
|
||||||
char *cmd = c->line;
|
c->flags&=~MONITOR_PEERS;
|
||||||
IN();
|
else if (strcase_startswith((char *)argv[1],"dnahelper", NULL))
|
||||||
|
c->flags&=~MONITOR_DNAHELPER;
|
||||||
remoteDid[0]='\0';
|
else
|
||||||
c->line_length=0;
|
return monitor_write_error(c,"Unknown monitor type");
|
||||||
|
|
||||||
if (strlen(cmd)>MONITOR_LINE_LENGTH) {
|
|
||||||
write_str(c->alarm.poll.fd,"\nERROR:Command too long\n");
|
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
|
snprintf(msg,sizeof(msg),"\nMONITORSTATUS:%d\n",c->flags);
|
||||||
|
write_str(c->alarm.poll.fd,msg);
|
||||||
|
|
||||||
if (cmd[0]=='*') {
|
return 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",
|
static int monitor_lookup_match(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||||
&callSessionToken,&sampleType)==2)
|
struct monitor_context *c=context;
|
||||||
{
|
const char *sid=argv[2];
|
||||||
/* Start getting sample */
|
const char *ext=argv[4];
|
||||||
c->sample_call_session_token=callSessionToken;
|
const char *name=argv[5];
|
||||||
c->sample_codec=sampleType;
|
|
||||||
RETURN(0);
|
if (!my_subscriber)
|
||||||
|
return monitor_write_error(c,"I don't know who I am");
|
||||||
|
|
||||||
|
struct sockaddr_mdp addr={
|
||||||
|
.port = atoi(argv[3]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (stowSid((unsigned char *)&addr.sid, 0, sid)==-1)
|
||||||
|
return monitor_write_error(c,"Invalid SID");
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (strcase_startswith(cmd,"monitor vomp",NULL))
|
static int monitor_call_ring(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||||
// TODO add supported codec list argument
|
struct monitor_context *c=context;
|
||||||
c->flags|=MONITOR_VOMP;
|
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
|
||||||
else if (strcase_startswith(cmd,"ignore vomp",NULL))
|
if (!call)
|
||||||
c->flags&=~MONITOR_VOMP;
|
return monitor_write_error(c,"Invalid call token");
|
||||||
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);
|
vomp_ringing(call);
|
||||||
} else if (sscanf(cmd,"pickup %x",&callSessionToken)==1) {
|
return 0;
|
||||||
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);
|
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);
|
vomp_hangup(call);
|
||||||
} else if (sscanf(cmd,"dtmf %x %s",&callSessionToken,digits)==2) {
|
return 0;
|
||||||
struct vomp_call_state *call=vomp_find_call_by_session(callSessionToken);
|
}
|
||||||
if (call){
|
|
||||||
|
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;
|
int i;
|
||||||
for(i=0;i<strlen(digits);i++) {
|
for(i=0;i<strlen(digits);i++) {
|
||||||
int digit=vomp_parse_dtmf_digit(digits[i]);
|
int digit=vomp_parse_dtmf_digit(digits[i]);
|
||||||
if (digit<0) {
|
if (digit<0)
|
||||||
snprintf(msg,1024,"\nERROR: invalid DTMF digit 0x%02x\n",digit);
|
monitor_write_error(c,"Invalid DTMF digit");
|
||||||
write_str(c->alarm.poll.fd,msg);
|
else{
|
||||||
}
|
|
||||||
/* 80ms standard tone duration, so that it is a multiple
|
/* 80ms standard tone duration, so that it is a multiple
|
||||||
of the majority of codec time units (70ms is the nominal
|
of the majority of codec time units (70ms is the nominal
|
||||||
DTMF tone length for most systems). */
|
DTMF tone length for most systems). */
|
||||||
@ -453,29 +478,49 @@ int monitor_process_command(struct monitor_context *c)
|
|||||||
vomp_received_audio(call, VOMP_CODEC_DTMF, &code, 1);
|
vomp_received_audio(call, VOMP_CODEC_DTMF, &code, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(msg,1024,"\nMONITORSTATUS:%d\n",c->flags);
|
struct command_line_option monitor_options[]={
|
||||||
write_str(c->alarm.poll.fd,msg);
|
{monitor_set,{"monitor","<type>",NULL},0,""},
|
||||||
|
{monitor_clear,{"ignore","<type>",NULL},0,""},
|
||||||
|
{monitor_lookup_match,{"lookup","match","<sid>","<port>","<ext>","<name>",NULL},0,""},
|
||||||
|
{monitor_call, {"call","<sid>","<local_did>","<remote_did>",NULL},0,""},
|
||||||
|
{monitor_call_ring, {"ringing","<token>",NULL},0,""},
|
||||||
|
{monitor_call_pickup, {"pickup","<token>",NULL},0,""},
|
||||||
|
{monitor_call_audio,{"audio","<token>","<type>","[<offset>]",NULL},0,""},
|
||||||
|
{monitor_call_hangup, {"hangup","<token>",NULL},0,""},
|
||||||
|
{monitor_call_dtmf, {"dtmf","<token>","<digits>",NULL},0,""},
|
||||||
|
};
|
||||||
|
|
||||||
RETURN(0);
|
static int parse_argv(char *cmdline, char delim, char **argv, int max_argv){
|
||||||
|
int argc=0;
|
||||||
|
|
||||||
|
if (*cmdline && argc<max_argv){
|
||||||
|
argv[argc++]=cmdline;
|
||||||
}
|
}
|
||||||
|
|
||||||
int monitor_process_data(struct monitor_context *c)
|
// TODO quoted argument handling?
|
||||||
|
|
||||||
|
while(*cmdline){
|
||||||
|
if (*cmdline==delim){
|
||||||
|
*cmdline=0;
|
||||||
|
if (cmdline[1] && argc<max_argv)
|
||||||
|
argv[argc++]=cmdline+1;
|
||||||
|
}
|
||||||
|
cmdline++;
|
||||||
|
}
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int monitor_process_command(struct monitor_context *c)
|
||||||
{
|
{
|
||||||
IN();
|
char *argv[16]={NULL,};
|
||||||
/* Called when we have received an entire data sample */
|
int argc = parse_argv(c->line, ' ', argv, 16);
|
||||||
c->state=MONITOR_STATE_COMMAND;
|
|
||||||
|
|
||||||
struct vomp_call_state *call=vomp_find_call_by_session(c->sample_call_session_token);
|
if (cli_execute(NULL, argc, (const char *const*)argv, monitor_options, c))
|
||||||
if (!call) {
|
return monitor_write_error(c, "Invalid command");
|
||||||
write_str(c->alarm.poll.fd,"\nERROR:No such call\n");
|
return 0;
|
||||||
RETURN(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
vomp_received_audio(call, c->sample_codec, &c->buffer[0], vomp_sample_size(c->sample_codec));
|
|
||||||
|
|
||||||
RETURN(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int monitor_announce_bundle(rhizome_manifest *m)
|
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
|
|| set_block(monitor_sockets[i].alarm.poll.fd) == -1
|
||||||
) {
|
) {
|
||||||
INFO("Tearing down monitor client");
|
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
|
|| set_block(monitor_sockets[i].alarm.poll.fd) == -1
|
||||||
) {
|
) {
|
||||||
INFOF("Tearing down monitor client #%d", i);
|
INFOF("Tearing down monitor client #%d", i);
|
||||||
monitor_client_close(&monitor_sockets[i]);
|
monitor_close(&monitor_sockets[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
#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 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 {
|
typedef struct sqlite_retry_state {
|
||||||
unsigned int limit; // do not retry once elapsed >= limit
|
unsigned int limit; // do not retry once elapsed >= limit
|
||||||
|
@ -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.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
#include "rhizome.h"
|
#include "rhizome.h"
|
||||||
#include <stdlib.h>
|
#include "str.h"
|
||||||
|
|
||||||
int rhizome_manifest_verify(rhizome_manifest *m)
|
int rhizome_manifest_verify(rhizome_manifest *m)
|
||||||
{
|
{
|
||||||
|
@ -18,11 +18,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define __RHIZOME_INLINE
|
#define __RHIZOME_INLINE
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
#include "rhizome.h"
|
#include "rhizome.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include <stdlib.h>
|
#include "str.h"
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
long long rhizome_space=0;
|
long long rhizome_space=0;
|
||||||
static const char *rhizome_thisdatastore_path = NULL;
|
static const char *rhizome_thisdatastore_path = NULL;
|
||||||
|
@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "serval.h"
|
#include "serval.h"
|
||||||
#include "rhizome.h"
|
#include "rhizome.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
extern int sigPipeFlag;
|
extern int sigPipeFlag;
|
||||||
extern int sigIoFlag;
|
extern int sigIoFlag;
|
||||||
|
19
serval.h
19
serval.h
@ -831,24 +831,12 @@ int vomp_tick_interval();
|
|||||||
int vomp_sample_size(int c);
|
int vomp_sample_size(int c);
|
||||||
int vomp_codec_timespan(int c);
|
int vomp_codec_timespan(int c);
|
||||||
int vomp_parse_dtmf_digit(char 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_pickup(struct vomp_call_state *call);
|
||||||
int vomp_hangup(struct vomp_call_state *call);
|
int vomp_hangup(struct vomp_call_state *call);
|
||||||
int vomp_ringing(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);
|
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_putchar(char c);
|
||||||
int cli_puts(const char *str);
|
int cli_puts(const char *str);
|
||||||
int cli_printf(const char *fmt, ...);
|
int cli_printf(const char *fmt, ...);
|
||||||
@ -869,10 +857,11 @@ overlay_interface * overlay_interface_find_name(const char *name);
|
|||||||
int directory_registration();
|
int directory_registration();
|
||||||
int directory_service_init();
|
int directory_service_init();
|
||||||
|
|
||||||
|
struct command_line_option;
|
||||||
#ifdef HAVE_VOIPTEST
|
#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
|
#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);
|
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||||
|
|
||||||
|
2
vomp.c
2
vomp.c
@ -658,7 +658,7 @@ int vomp_call_destroy(struct vomp_call_state *call)
|
|||||||
return 0;
|
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.
|
/* 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,
|
These need to be passed to the node being called to provide caller id,
|
||||||
|
Loading…
Reference in New Issue
Block a user