summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2021-08-25 15:44:03 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2021-09-17 16:33:29 +0200
commit67d66e73d233e156aa7dddab2d56c0bb2211c02e (patch)
treef25123db95a5c2cc70f05f4e85d7c8902d3c50f8
parent42f4d661a999215166672fba9d3a182ae58babcc (diff)
Structured the commands and environment variablesHEADmaster
-rw-r--r--src/router/call.c785
-rw-r--r--src/router/call.h2
-rw-r--r--src/router/main.c19
-rw-r--r--src/router/routing.c261
-rw-r--r--src/router/routing.h4
5 files changed, 679 insertions, 392 deletions
diff --git a/src/router/call.c b/src/router/call.c
index 945c2ac..e74ae60 100644
--- a/src/router/call.c
+++ b/src/router/call.c
@@ -487,6 +487,7 @@ static void orig_info(call_t *call, osmo_cc_msg_t *old_msg)
uint8_t type, plan;
char number[256];
char keypad[256];
+ int complete = 0;
uint8_t duration_ms, pause_ms, dtmf_mode;
char dtmf[256];
char command[512];
@@ -515,6 +516,11 @@ static void orig_info(call_t *call, osmo_cc_msg_t *old_msg)
strcat(call->dialing_keypad, keypad);
}
+ /* indicate complete number to environment */
+ rc = osmo_cc_get_ie_complete(old_msg, 0);
+ if (rc)
+ complete = 1;
+
/* dtmf digits */
rc = osmo_cc_get_ie_dtmf(old_msg, 0, &duration_ms, &pause_ms, &dtmf_mode, dtmf, sizeof(dtmf));
if (rc < 0 || (dtmf_mode != OSMO_CC_DTMF_MODE_ON && dtmf_mode != OSMO_CC_DTMF_MODE_DIGITS))
@@ -535,7 +541,7 @@ static void orig_info(call_t *call, osmo_cc_msg_t *old_msg)
if (call->state == CALL_STATE_OVERLAP && !call->relation_list->next) {
if (!call->routing.routing) {
/* restart routing with new dial string */
- routing_env_dialing(&call->routing, call->dialing_number, call->dialing_keypad);
+ routing_env_dialing(&call->routing, call->dialing_number, call->dialing_keypad, complete);
routing_start(&call->routing, routing_script, routing_shell);
} else {
/* send digits to routing */
@@ -1130,26 +1136,57 @@ void cc_message(osmo_cc_endpoint_t *cc_ep, uint32_t callref, osmo_cc_msg_t *msg)
* process message from routing
*/
-static const char *value_of_param(char *arg, char *param, char **value_p)
-{
- if (!!strncmp(arg, param, strlen(param)))
- return NULL;
- arg += strlen(param);
+static struct param {
+ /* rtp-proxy */
+ struct osmo_cc_helper_audio_codecs orig_codecs[MAX_CODECS + 1];
+ struct osmo_cc_helper_audio_codecs term_codecs[MAX_CODECS + 1];
+ int orig_given, term_given;
- if (*arg == '\0') {
- if (value_p)
- *value_p = "";
- return "";
- }
+ /* play */
+ char *filename, *volume, *loop;
- if (*arg != '=')
- return NULL;
- arg++;
+ /* gain */
+ char *gain;
- if (value_p)
- *value_p = arg;
- return arg;
-}
+ /* call */
+ char *interface;
+ int bearer_coding, bearer_capability, bearer_mode;
+ char *calling;
+ int calling_type, calling_plan, calling_present, calling_screen, no_calling;
+ char *calling2;
+ int calling2_type, calling2_plan, calling2_present, calling2_screen, no_calling2;
+ char *redirecting;
+ int redirecting_type, redirecting_plan, redirecting_present, redirecting_screen, redirecting_reason, no_redirecting;
+ char *dialing;
+ int dialing_type, dialing_plan;
+ char *keypad;
+
+ /* disc/rel */
+ int isdn_cause, sip_cause;
+
+ /* error */
+ char *error;
+} param;
+
+struct param_def {
+ const char *n;
+ char **s;
+ int *i;
+ struct osmo_cc_helper_audio_codecs *o, *t;
+ const char *d;
+ int mandatory;
+ int no_value;
+ const char *(*value2name)(int value);
+ int (*name2value)(const char *name);
+ int num;
+};
+
+struct command_def {
+ const char *name;
+ void (*func)(call_t *call, int argc, char *argv[], struct command_def *command_def);
+ const char *description;
+ struct param_def *param_list;
+} command_def[];
static void add_codecs_by_names(struct osmo_cc_helper_audio_codecs *codecs, char *names)
{
@@ -1176,13 +1213,88 @@ static void add_codecs_by_names(struct osmo_cc_helper_audio_codecs *codecs, char
memset(&codecs[c], 0, sizeof(*codecs));
}
+static int parse_params(int argc, char *argv[], struct command_def *command_def)
+{
+ struct param_def *param_def = command_def->param_list;
+ int i, j;
+ char *arg;
+
+ /* clear parameter set */
+ memset(&param, 0, sizeof(param));
+
+ /* no parameter list given */
+ if (param_def == NULL)
+ return -EINVAL;
+
+ /* loop through all arguments and stop if there is a ':' */
+ for (i = 0; i < argc && argv[i][0] != ':'; i++) {
+ arg = argv[i];
+ /* loop through all possible parameter definitions */
+ for (j = 0; param_def[j].n; j++) {
+ /* stop if parameter has been found */
+ if (!strncasecmp(arg, param_def[j].n, strlen(param_def[j].n))) {
+ arg += strlen(param_def[j].n);
+ /* no value */
+ if (*arg == '\0') {
+ arg = "";
+ break;
+ }
+ /* has value */
+ if (*arg == '=') {
+ arg++;
+ break;
+ }
+ /* continue, if more digits given */
+ }
+ }
+ if (!param_def[j].n) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "Unknown '%s' parameter '%s' from routing.\n", command_def->name, argv[i]);
+ continue;
+ }
+
+ if (arg[0] && param_def[j].no_value) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "'%s' parameter '%s' has no value, ignoring.\n", command_def->name, argv[i]);
+ continue;
+ }
+
+ if (param_def[j].no_value)
+ arg = "1";
+
+ if (param_def[j].i) {
+ if (param_def[j].name2value) {
+ *param_def[j].i = param_def[j].name2value(arg);
+ if (*param_def[j].i < 0)
+ *param_def[j].i = atoi(arg);
+ } else
+ *param_def[j].i = atoi(arg);
+ }
+ if (param_def[j].s)
+ *param_def[j].s = arg;
+ if (param_def[j].o) {
+ PDEBUG(DROUTER, DEBUG_INFO, "Originating codecs given: '%s'.\n", arg);
+ add_codecs_by_names(param_def[j].o, arg);
+ param.orig_given = 1;
+ }
+ if (param_def[j].t) {
+ PDEBUG(DROUTER, DEBUG_INFO, "Terminating codecs given: '%s'.\n", arg);
+ add_codecs_by_names(param_def[j].t, arg);
+ param.term_given = 1;
+ }
+ }
+
+ return i;
+}
+
/* routing orders us to activate rtp proxy */
-static void routing_rtp_proxy(call_t *call, int argc, char *argv[])
+struct param_def param_rtp_proxy[] = {
+ { .n = "orig-codecs", .o = param.orig_codecs, .d = "Define allowed codecs to be accepted by originating endpoint." },
+ { .n = "term-codecs", .t = param.term_codecs, .d = "Define allowed codecs on terminating endpoint in order of preference." },
+ { .n = NULL }
+};
+
+static void routing_rtp_proxy(call_t *call, int argc, char *argv[], struct command_def *command_def)
{
call_relation_t *relation = call->relation_list;
- int orig_given = 0, term_given = 0;
- int i;
- char *value;
/* ignore, if already enabled */
if (relation->rtp_proxy) {
@@ -1190,36 +1302,24 @@ static void routing_rtp_proxy(call_t *call, int argc, char *argv[])
return;
}
- /* loop through all arguments and stop if there is a ':' */
- for (i = 0; i < argc ; i++) {
- if (value_of_param(argv[i], "orig-codecs", &value)) {
- PDEBUG(DROUTER, DEBUG_INFO, "Originating codecs given: '%s'.\n", value);
- add_codecs_by_names(relation->orig_codecs, value);
- if (relation->orig_codecs[0].payload_name)
- orig_given = 1;
- } else if (value_of_param(argv[i], "term-codecs", &value)) {
- PDEBUG(DROUTER, DEBUG_INFO, "Terminating codecs given: '%s'.\n", value);
- add_codecs_by_names(relation->term_codecs, value);
- if (relation->term_codecs[0].payload_name)
- term_given = 1;
- } else
- PDEBUG(DROUTER, DEBUG_ERROR, "Unknown 'rtp-proxy' parameter '%s' from routing.\n", argv[i]);
- }
-
- if (!orig_given) {
+ parse_params(argc, argv, command_def);
+
+ if (!param.orig_given) {
memcpy(&relation->orig_codecs[0], &codecs_def[0], sizeof(relation->orig_codecs[0]));
memcpy(&relation->orig_codecs[1], &codecs_def[1], sizeof(relation->orig_codecs[1]));
memcpy(&relation->orig_codecs[2], &codecs_def[2], sizeof(relation->orig_codecs[2]));
memset(&relation->orig_codecs[3], 0, sizeof(relation->orig_codecs[3]));
PDEBUG(DROUTER, DEBUG_INFO, "No originating codeds given, using default '%s' and '%s' and '%s'.\n", relation->orig_codecs[0].payload_name, relation->orig_codecs[1].payload_name, relation->orig_codecs[2].payload_name);
- }
+ } else
+ memcpy(relation->orig_codecs, param.orig_codecs, sizeof(param.orig_codecs));
- if (!term_given) {
+ if (!param.term_given) {
memcpy(&relation->term_codecs[0], &codecs_def[0], sizeof(relation->term_codecs[0]));
memcpy(&relation->term_codecs[1], &codecs_def[1], sizeof(relation->term_codecs[1]));
memset(&relation->term_codecs[2], 0, sizeof(relation->term_codecs[2]));
PDEBUG(DROUTER, DEBUG_INFO, "No terminating codeds given, using default '%s' and '%s'.\n", relation->term_codecs[0].payload_name, relation->term_codecs[1].payload_name);
- }
+ } else
+ memcpy(relation->term_codecs, param.term_codecs, sizeof(param.term_codecs));
/* error, if we already negotiated */
if (call->sdp_forwarded) {
@@ -1237,11 +1337,16 @@ static void routing_rtp_proxy(call_t *call, int argc, char *argv[])
}
/* routing orders us to play a wave file */
-static void routing_play(call_t *call, int argc, char *argv[])
+struct param_def param_play[] = {
+ { .n = "filename", .s = &param.filename, .d = "file name of audio file", .mandatory = 1 },
+ { .n = "volume", .s = &param.volume, .d = "speech level, which is '1.0'" },
+ { .n = "loop", .s = &param.loop, .d = "play in an endless loop", .no_value = 1 },
+ { .n = NULL }
+};
+
+static void routing_play(call_t *call, int argc, char *argv[], struct command_def *command_def)
{
call_relation_t *relation = call->relation_list;
- char *filename = NULL, *volume = "1.0", *loop = NULL;
- int i;
int samplerate = 8000, channels = 0;
double deviation;
int rc;
@@ -1253,29 +1358,21 @@ static void routing_play(call_t *call, int argc, char *argv[])
return;
}
- /* loop through all arguments and stop if there is a ':' */
- for (i = 0; i < argc ; i++) {
- if (value_of_param(argv[i], "volume", &volume));
- else if (value_of_param(argv[i], "loop", &loop));
- else {
- if (filename) {
- PDEBUG(DROUTER, DEBUG_ERROR, "'play' command reqires only one file name, you specified '%s' and '%s'.\n", filename, argv[i]);
- return;
- }
- filename = argv[i];
- }
- }
+ parse_params(argc, argv, command_def);
- if (!filename) {
+ if (!param.filename) {
PDEBUG(DROUTER, DEBUG_ERROR, "'play' command reqires a file name as parameter.\n");
return;
}
- deviation = 1.0 / SPEECH_LEVEL * atof(volume);
- rc = wave_create_playback(&relation->play, filename, &samplerate, &channels, deviation);
+ if (!param.volume)
+ param.volume = "1.0";
+
+ deviation = 1.0 / SPEECH_LEVEL * atof(param.volume);
+ rc = wave_create_playback(&relation->play, param.filename, &samplerate, &channels, deviation);
if (rc < 0)
return;
- strncpy(relation->play_filename, filename, sizeof(relation->play_filename) - 1);
+ strncpy(relation->play_filename, param.filename, sizeof(relation->play_filename) - 1);
relation->play_deviation = deviation;
@@ -1285,12 +1382,12 @@ static void routing_play(call_t *call, int argc, char *argv[])
return;
}
- if (loop)
+ if (param.loop)
relation->play_loop = 1;
}
/* routing orders us stop playing a wave file */
-static void routing_play_stop(call_t *call)
+static void routing_play_stop(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
@@ -1298,11 +1395,15 @@ static void routing_play_stop(call_t *call)
}
/* routing orders us to record a wave file */
-static void routing_record(call_t *call, int argc, char *argv[])
+struct param_def param_record[] = {
+ { .n = "filename", .s = &param.filename, .d = "file name of audio file", .mandatory = 1 },
+ { .n = "volume", .s = &param.volume, .d = "speech level, which is '1.0'" },
+ { .n = NULL }
+};
+
+static void routing_record(call_t *call, int argc, char *argv[], struct command_def *command_def)
{
call_relation_t *relation = call->relation_list;
- char *filename = NULL, *volume = "1.0";
- int i;
int samplerate = 8000, channels = 2;
int rc;
@@ -1313,30 +1414,23 @@ static void routing_record(call_t *call, int argc, char *argv[])
return;
}
- /* loop through all arguments and stop if there is a ':' */
- for (i = 0; i < argc ; i++) {
- if (value_of_param(argv[i], "volume", &volume));
- else {
- if (filename) {
- PDEBUG(DROUTER, DEBUG_ERROR, "'record' command reqires only one file name, you specified '%s' and '%s'.\n", filename, argv[i]);
- return;
- }
- filename = argv[i];
- }
- }
+ parse_params(argc, argv, command_def);
- if (!filename) {
+ if (!param.filename) {
PDEBUG(DROUTER, DEBUG_ERROR, "'record' command reqires a file name as parameter.\n");
return;
}
- rc = wave_create_record(&relation->rec, filename, samplerate, channels, 1.0 / SPEECH_LEVEL / atof(volume));
+ if (!param.volume)
+ param.volume = "1.0";
+
+ rc = wave_create_record(&relation->rec, param.filename, samplerate, channels, 1.0 / SPEECH_LEVEL / atof(param.volume));
if (rc < 0)
return;
}
/* routing orders us stop recording a wave file */
-static void routing_record_stop(call_t *call)
+static void routing_record_stop(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
@@ -1344,51 +1438,85 @@ static void routing_record_stop(call_t *call)
}
/* routing orders us to set local gain */
-static void routing_gain(call_t *call, int argc, char *argv[], int tx)
-{
- int i;
- char *gain = NULL;
+struct param_def param_gain[] = {
+ { .n = "gain", .s = &param.gain, .d = "gain in dB" },
+ { .n = NULL }
+};
+static void routing_tx_gain(call_t *call, int argc, char *argv[], struct command_def *command_def)
+{
if (!call->relation_list->rtp_proxy) {
PDEBUG(DROUTER, DEBUG_ERROR, "RTP-Proxy must be enabled to record a file!\n");
return;
}
- /* loop through all arguments and stop if there is a ':' */
- for (i = 0; i < argc ; i++) {
- if (gain) {
- PDEBUG(DROUTER, DEBUG_ERROR, "'%s-gain' command reqires only parameter, you specified '%s' and '%s'.\n", (tx) ? "tx" : "rx", gain, argv[i]);
- return;
- }
- gain = argv[i];
+ parse_params(argc, argv, command_def);
+
+ if (!param.gain) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "'tx-gain' command reqires a gain value as parameter.\n");
+ return;
}
- if (!gain) {
- PDEBUG(DROUTER, DEBUG_ERROR, "'%s-gain' command reqires a gain value as parameter.\n", (tx) ? "tx" : "rx");
+ call->tx_gain = atof(param.gain);
+}
+
+static void routing_rx_gain(call_t *call, int argc, char *argv[], struct command_def *command_def)
+{
+ if (!call->relation_list->rtp_proxy) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "RTP-Proxy must be enabled to record a file!\n");
return;
}
- if (tx)
- call->tx_gain = atof(gain);
- else
- call->rx_gain = atof(gain);
+ parse_params(argc, argv, command_def);
+
+ if (!param.gain) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "'rx-gain' command reqires a gain value as parameter.\n");
+ return;
+ }
+
+ call->rx_gain = atof(param.gain);
}
/* routing orders us to call remote end */
-static void routing_call(call_t *call, int argc, char *argv[])
+struct param_def param_call[] = {
+ { .n = "interface", .s = &param.interface, .d = "name of interface to route the call to", .mandatory = 1},
+ { .n = "bearer-coding", .i = &param.bearer_coding, .d = "coding of bearer capability", .name2value = osmo_cc_coding_name2value, .value2name = osmo_cc_coding_value2name, .num = OSMO_CC_CODING_NUM },
+ { .n = "bearer-capability", .i = &param.bearer_capability, .d = "bearer capability value", .name2value = osmo_cc_capability_name2value, .value2name = osmo_cc_capability_value2name, .num = OSMO_CC_CAPABILITY_NUM },
+ { .n = "bearer-mode", .i = &param.bearer_mode, .d = "bearer mode", .name2value = osmo_cc_mode_name2value, .value2name = osmo_cc_mode_value2name, .num = OSMO_CC_MODE_NUM },
+ { .n = "calling", .s = &param.calling, .d = "calling party number" },
+ { .n = "calling-type", .i = &param.calling_type, .d = "type of calling party number", .name2value = osmo_cc_type_name2value, .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM},
+ { .n = "calling-plan", .i = &param.calling_plan, .d = "numbering plan of calling party number", .name2value = osmo_cc_plan_name2value, .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "calling-present", .i = &param.calling_present, .d = "presentation of calling party number", .name2value = osmo_cc_present_name2value, .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "calling-screen", .i = &param.calling_screen, .d = "screening indicator of calling party number", .name2value = osmo_cc_screen_name2value, .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "no-calling", .i = &param.no_calling, .d = "disable calling party number", .no_value = 1},
+ { .n = "calling2", .s = &param.calling2, .d = "second calling party number" },
+ { .n = "calling2-type", .i = &param.calling2_type, .d = "type of second calling party number", .name2value = osmo_cc_type_name2value, .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM},
+ { .n = "calling2-plan", .i = &param.calling2_plan, .d = "numbering plan of second calling party number", .name2value = osmo_cc_plan_name2value, .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "calling2-present", .i = &param.calling2_present, .d = "presentation of second calling party number", .name2value = osmo_cc_present_name2value, .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "calling2-screen", .i = &param.calling2_screen, .d = "screening indicator of second calling party number", .name2value = osmo_cc_screen_name2value, .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "no-calling2", .i = &param.no_calling2, .d = "disable seconds calling party number", .no_value = 1 },
+ { .n = "redirecting", .s = &param.redirecting, .d = "redirecting number" },
+ { .n = "redirecting-type", .i = &param.redirecting_type, .d = "type of redirecting number", .name2value = osmo_cc_type_name2value, .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "redirecting-plan", .i = &param.redirecting_plan, .d = "numbering plan of redirecting number", .name2value = osmo_cc_plan_name2value, .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "redirecting-present", .i = &param.redirecting_present, .d = "presentation of redirecting number", .name2value = osmo_cc_present_name2value, .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "redirecting-screen", .i = &param.redirecting_screen, .d = "screening indicator of redirecting number", .name2value = osmo_cc_screen_name2value, .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "redirecting-reason", .i = &param.redirecting_reason, .d = "reason for redirecting the call", .name2value = osmo_cc_redir_reason_name2value, .value2name = osmo_cc_redir_reason_value2name, .num = OSMO_CC_REDIR_REASON_NUM },
+ { .n = "no-redirecting", .i = &param.no_redirecting, .d = "disable redirecting number", .no_value = 1 },
+ { .n = "dialing", .s = &param.dialing, .d = "alter dialed number" },
+ { .n = "dialing-type", .i = &param.dialing_type, .d = "type of dialed number", .name2value = osmo_cc_type_name2value, .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "dialing-plan", .i = &param.dialing_plan, .d = "numbering plan of dialed number", .name2value = osmo_cc_plan_name2value, .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "keypad", .s = &param.keypad, .d = "keypulse digit or digits (might be required by some ISDN applications)" },
+ { .n = NULL }
+};
+
+static void routing_call(call_t *call, int argc, char *argv[], struct command_def *command_def)
{
- char *interface;
- char *bearer_coding, *bearer_capability, *bearer_mode;
- char *calling, *calling_type, *calling_plan, *calling_present, *calling_screen, *no_calling;
- char *calling2, *calling2_type, *calling2_plan, *calling2_present, *calling2_screen, *no_calling2;
- char *redirecting, *redirecting_type, *redirecting_plan, *redirecting_present, *redirecting_screen, *redirecting_reason, *no_redirecting;
- char *dialing, *dialing_type, *dialing_plan;
- char *keypad;
+ osmo_cc_call_t *att = NULL;
uint8_t coding, capability, mode;
uint8_t type, plan, present, screen, reason;
char number[256];
- int i, rc, calls = 0;
+ int e, i, rc, calls = 0;
osmo_cc_msg_t *new_msg, *setup_msg;
/* if we have a call, we don't add more terminators */
@@ -1400,56 +1528,28 @@ static void routing_call(call_t *call, int argc, char *argv[])
setup_msg = call->setup_msg;
next_call:
- interface = NULL;
- bearer_coding = bearer_capability = bearer_mode = NULL;
- calling = calling_type = calling_plan = calling_present = calling_screen = no_calling = NULL;
- calling2 = calling2_type = calling2_plan = calling2_present = calling2_screen = no_calling2 = NULL;
- redirecting = redirecting_type = redirecting_plan = redirecting_present = redirecting_screen = redirecting_reason = no_redirecting = NULL;
- dialing = dialing_type = dialing_plan = NULL;
- keypad = NULL;
- /* loop through all arguments and stop if there is a ':' */
- for (i = 0; i < argc && argv[i][0] != ':'; i++) {
- if (value_of_param(argv[i], "interface", &interface));
- else if (value_of_param(argv[i], "bearer-coding", &bearer_coding));
- else if (value_of_param(argv[i], "bearer-capability", &bearer_capability));
- else if (value_of_param(argv[i], "bearer-mode", &bearer_mode));
- else if (value_of_param(argv[i], "calling", &calling));
- else if (value_of_param(argv[i], "calling-type", &calling_type));
- else if (value_of_param(argv[i], "calling-plan", &calling_plan));
- else if (value_of_param(argv[i], "calling-present", &calling_present));
- else if (value_of_param(argv[i], "calling-screen", &calling_screen));
- else if (value_of_param(argv[i], "no-calling", &no_calling));
- else if (value_of_param(argv[i], "calling2", &calling2));
- else if (value_of_param(argv[i], "calling2-type", &calling2_type));
- else if (value_of_param(argv[i], "calling2-plan", &calling2_plan));
- else if (value_of_param(argv[i], "calling2-present", &calling2_present));
- else if (value_of_param(argv[i], "calling2-screen", &calling2_screen));
- else if (value_of_param(argv[i], "no-calling2", &no_calling2));
- else if (value_of_param(argv[i], "redirecting", &redirecting));
- else if (value_of_param(argv[i], "redirecting-type", &redirecting_type));
- else if (value_of_param(argv[i], "redirecting-plan", &redirecting_plan));
- else if (value_of_param(argv[i], "redirecting-present", &redirecting_present));
- else if (value_of_param(argv[i], "redirecting-screen", &redirecting_screen));
- else if (value_of_param(argv[i], "redirecting-reason", &redirecting_reason));
- else if (value_of_param(argv[i], "no-redirecting", &no_redirecting));
- else if (value_of_param(argv[i], "dialing", &dialing));
- else if (value_of_param(argv[i], "dialing-type", &dialing_type));
- else if (value_of_param(argv[i], "dialing-plan", &dialing_plan));
- else if (value_of_param(argv[i], "keypad", &keypad));
- else
- PDEBUG(DROUTER, DEBUG_ERROR, "Unknown 'call' parameter '%s' from routing.\n", argv[i]);
- }
+ i = parse_params(argc, argv, command_def);
+
/* if more calls, then forward arguments behind colon, otherwise set argc to 0 */
- if (i < argc) {
+ if (i >= 0 && i < argc) {
argv += i + 1;
argc -= i + 1;
} else
argc = 0;
- if (!interface) {
+ if (!param.interface) {
PDEBUG(DROUTER, DEBUG_ERROR, "'call' command without 'interface' parameter.\n");
goto try_next;
}
+ for (e = 0; cc_ep_list[e]; e++) {
+ att = osmo_cc_get_attached_interface(cc_ep_list[e], param.interface);
+ if (att)
+ break;
+ }
+ if (!att) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "'call' command with 'interface' parameter '%s' which is not attached.\n", param.interface);
+ goto try_next;
+ }
calls++;
@@ -1472,11 +1572,11 @@ next_call:
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_SETUP_IND);
/* interface name */
- osmo_cc_add_ie_called_interface(new_msg, interface);
+ osmo_cc_add_ie_called_interface(new_msg, param.interface);
/* bearer capability */
rc = osmo_cc_get_ie_bearer(setup_msg, 0, &coding, &capability, &mode);
- if (rc >= 0 || bearer_coding || bearer_capability || bearer_mode) {
+ if (rc >= 0 || param.bearer_coding || param.bearer_capability || param.bearer_mode) {
/* if not preset, use default values */
if (rc < 0) {
coding = OSMO_CC_CODING_ITU_T;
@@ -1484,19 +1584,19 @@ next_call:
mode = OSMO_CC_MODE_CIRCUIT;
}
/* alter values */
- if (bearer_coding)
- coding = atoi(bearer_coding);
- if (bearer_capability)
- capability = atoi(bearer_capability);
- if (bearer_mode)
- mode = atoi(bearer_coding);
+ if (param.bearer_coding)
+ coding = param.bearer_coding;
+ if (param.bearer_capability)
+ capability = param.bearer_capability;
+ if (param.bearer_mode)
+ mode = param.bearer_coding;
osmo_cc_add_ie_bearer(new_msg, coding, capability, mode);
}
/* calling */
- if (!no_calling) {
+ if (!param.no_calling) {
rc = osmo_cc_get_ie_calling(setup_msg, 0, &type, &plan, &present, &screen, number, sizeof(number));
- if (rc >= 0 || calling_type || calling_plan || calling_present || calling_screen || calling) {
+ if (rc >= 0 || param.calling_type || param.calling_plan || param.calling_present || param.calling_screen || param.calling) {
/* if not preset, use default values */
if (rc < 0) {
type = OSMO_CC_TYPE_UNKNOWN;
@@ -1506,22 +1606,22 @@ next_call:
number[0] = '\0';
}
/* alter values */
- if (calling_type)
- type = atoi(calling_type);
- if (calling_plan)
- plan = atoi(calling_plan);
- if (calling_present)
- present = atoi(calling_present);
- if (calling_screen)
- screen = atoi(calling_screen);
- if (!calling)
- calling = number;
- osmo_cc_add_ie_calling(new_msg, type, plan, present, screen, calling);
+ if (param.calling_type)
+ type = param.calling_type;
+ if (param.calling_plan)
+ plan = param.calling_plan;
+ if (param.calling_present)
+ present = param.calling_present;
+ if (param.calling_screen)
+ screen = param.calling_screen;
+ if (!param.calling)
+ param.calling = number;
+ osmo_cc_add_ie_calling(new_msg, type, plan, present, screen, param.calling);
}
}
- if (!no_calling && !no_calling2) {
+ if (!param.no_calling && !param.no_calling2) {
rc = osmo_cc_get_ie_calling(setup_msg, 1, &type, &plan, &present, &screen, number, sizeof(number));
- if (rc >= 0 || calling2_type || calling2_plan || calling2_present || calling2_screen || calling2) {
+ if (rc >= 0 || param.calling2_type || param.calling2_plan || param.calling2_present || param.calling2_screen || param.calling2) {
/* if not preset, use default values */
if (rc < 0) {
type = OSMO_CC_TYPE_UNKNOWN;
@@ -1531,24 +1631,24 @@ next_call:
number[0] = '\0';
}
/* alter values */
- if (calling2_type)
- type = atoi(calling2_type);
- if (calling2_plan)
- plan = atoi(calling2_plan);
- if (calling2_present)
- present = atoi(calling2_present);
- if (calling2_screen)
- screen = atoi(calling2_screen);
- if (!calling2)
- calling2 = number;
- osmo_cc_add_ie_calling(new_msg, type, plan, present, screen, calling2);
+ if (param.calling2_type)
+ type = param.calling2_type;
+ if (param.calling2_plan)
+ plan = param.calling2_plan;
+ if (param.calling2_present)
+ present = param.calling2_present;
+ if (param.calling2_screen)
+ screen = param.calling2_screen;
+ if (!param.calling2)
+ param.calling2 = number;
+ osmo_cc_add_ie_calling(new_msg, type, plan, present, screen, param.calling2);
}
}
/* redirecting */
- if (!no_redirecting) {
+ if (!param.no_redirecting) {
rc = osmo_cc_get_ie_redir(setup_msg, 0, &type, &plan, &present, &screen, &reason, number, sizeof(number));
- if (rc >= 0 || redirecting_type || redirecting_plan || redirecting_present || redirecting_screen || redirecting) {
+ if (rc >= 0 || param.redirecting_type || param.redirecting_plan || param.redirecting_present || param.redirecting_screen || param.redirecting) {
/* if not preset, use default values */
if (rc < 0) {
type = OSMO_CC_TYPE_UNKNOWN;
@@ -1559,62 +1659,62 @@ next_call:
number[0] = '\0';
}
/* alter values */
- if (redirecting_type)
- type = atoi(redirecting_type);
- if (redirecting_plan)
- plan = atoi(redirecting_plan);
- if (redirecting_present)
- present = atoi(redirecting_present);
- if (redirecting_screen)
- screen = atoi(redirecting_screen);
- if (!redirecting)
- redirecting = number;
- osmo_cc_add_ie_redir(new_msg, type, plan, present, screen, reason, redirecting);
+ if (param.redirecting_type)
+ type = param.redirecting_type;
+ if (param.redirecting_plan)
+ plan = param.redirecting_plan;
+ if (param.redirecting_present)
+ present = param.redirecting_present;
+ if (param.redirecting_screen)
+ screen = param.redirecting_screen;
+ if (!param.redirecting)
+ param.redirecting = number;
+ osmo_cc_add_ie_redir(new_msg, type, plan, present, screen, reason, param.redirecting);
}
}
/* dialing */
rc = osmo_cc_get_ie_called(setup_msg, 0, &type, &plan, number, sizeof(number));
- if (rc >= 0 || dialing_type || dialing_plan || dialing) {
+ if (rc >= 0 || param.dialing_type || param.dialing_plan || param.dialing) {
/* if not preset, use default values */
if (rc < 0) {
type = OSMO_CC_TYPE_UNKNOWN;
plan = OSMO_CC_PLAN_TELEPHONY;
}
/* alter values */
- if (dialing_type)
- type = atoi(dialing_type);
- if (dialing_plan)
- plan = atoi(dialing_plan);
- if (!dialing)
- dialing = "";
- osmo_cc_add_ie_called(new_msg, type, plan, dialing);
+ if (param.dialing_type)
+ type = param.dialing_type;
+ if (param.dialing_plan)
+ plan = param.dialing_plan;
+ if (!param.dialing)
+ param.dialing = "";
+ osmo_cc_add_ie_called(new_msg, type, plan, param.dialing);
}
/* keypad */
- if (keypad) {
- if (keypad[0])
- osmo_cc_add_ie_keypad(new_msg, keypad);
+ if (param.keypad) {
+ if (param.keypad[0])
+ osmo_cc_add_ie_keypad(new_msg, param.keypad);
}
/* only if RTP-Proxy is used */
if (call->relation_list->rtp_proxy) {
PDEBUG(DROUTER, DEBUG_DEBUG, "Sending our codecs to the terminator.\n");
- relation->cc_session = osmo_cc_helper_audio_offer(relation, call->relation_list->term_codecs, receive_terminator, new_msg, 1);
+ relation->cc_session = osmo_cc_helper_audio_offer(&relation->cc_ep->session_config, relation, call->relation_list->term_codecs, receive_terminator, new_msg, 1);
} else
/* sdp from originator's setup message */
if (call->relation_list->sdp)
osmo_cc_add_ie_sdp(new_msg, call->relation_list->sdp);
/* send message to osmo-cc */
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
/* remember this, since we cannot do RTP-Proxy after */
call->sdp_forwarded = 1;
/* store peer info for status */
- strncpy(relation->interface, interface, sizeof(relation->interface) - 1);
- strncpy(relation->id, dialing, sizeof(relation->id) - 1);
+ strncpy(relation->interface, (param.interface) ? : "", sizeof(relation->interface) - 1);
+ strncpy(relation->id, (param.dialing) ? : "", sizeof(relation->id) - 1);
/* update call state for status display */
relation->state = CALL_STATE_SETUP;
@@ -1627,7 +1727,7 @@ try_next:
}
/* routing orders us to hangup all terminating calls */
-static void routing_call_stop(call_t *call)
+static void routing_call_stop(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation;
osmo_cc_msg_t *new_msg;
@@ -1637,14 +1737,14 @@ static void routing_call_stop(call_t *call)
relation = call->relation_list->next;
PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-REL-IND to terminator.\n", relation_name(relation));
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
- osmo_cc_add_ie_cause(new_msg, cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR, 0, 0);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR, 0, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
relation_destroy(relation);
}
}
/* routing orders us to set call into overlap state */
-static void routing_overlap(call_t *call)
+static void routing_overlap(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
osmo_cc_msg_t *new_msg;
@@ -1662,11 +1762,11 @@ static void routing_overlap(call_t *call)
/* send SDP answer */
proxy_send_sdp_answer(relation, new_msg);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
/* routing orders us to set call into proceeding state */
-static void routing_proceeding(call_t *call)
+static void routing_proceeding(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
osmo_cc_msg_t *new_msg;
@@ -1685,11 +1785,11 @@ static void routing_proceeding(call_t *call)
/* send SDP answer */
proxy_send_sdp_answer(relation, new_msg);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
/* routing orders us to set call into alerting state */
-static void routing_alerting(call_t *call)
+static void routing_alerting(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
osmo_cc_msg_t *new_msg;
@@ -1709,11 +1809,11 @@ static void routing_alerting(call_t *call)
/* send SDP answer */
proxy_send_sdp_answer(relation, new_msg);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
/* routing orders us to set call into answer state */
-static void routing_answer(call_t *call)
+static void routing_answer(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
osmo_cc_msg_t *new_msg;
@@ -1734,51 +1834,69 @@ static void routing_answer(call_t *call)
/* send SDP answer */
proxy_send_sdp_answer(relation, new_msg);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
/* routing orders us to dsiconnect/release the call */
-static void routing_disc_rel(call_t *call, int argc, char *argv[], int disconnect)
+struct param_def param_disc_rel[] = {
+ { .n = "isdn-cause", .i = &param.isdn_cause, .d = "ISDN cause number (Will be generated, if omitted.)" },
+ { .n = "sip-cause", .i = &param.sip_cause, .d = "SIP cause number (Will be generated, if omitted.)" },
+ { .n = NULL }
+};
+
+static void routing_disconnect(call_t *call, int argc, char *argv[], struct command_def *command_def)
{
call_relation_t *relation = call->relation_list;
- char *cause_str;
- uint8_t cause = 16;
osmo_cc_msg_t *new_msg;
- int i;
- /* get cause, if any */
- for (i = 0; i < argc; i++) {
- if (value_of_param(argv[i], "cause", &cause_str))
- cause = atoi(cause_str);
- else
- PDEBUG(DROUTER, DEBUG_ERROR, "Unknown 'disconnect' / 'release' parameter '%s' from routing.\n", argv[i]);
- }
+ parse_params(argc, argv, command_def);
- PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-%s-IND to originator.\n", relation_name(relation), (disconnect) ? "DISC" : "REL");
+ PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-DISC-IND to originator.\n", relation_name(relation));
/* send message to originator */
- new_msg = osmo_cc_new_msg((disconnect) ? OSMO_CC_MSG_DISC_IND : OSMO_CC_MSG_REL_IND);
- if (disconnect) {
- /* send SDP answer */
- proxy_send_sdp_answer(relation, new_msg);
- }
+ new_msg = osmo_cc_new_msg(OSMO_CC_MSG_DISC_IND);
+ /* send SDP answer */
+ proxy_send_sdp_answer(relation, new_msg);
/* add cause */
- osmo_cc_add_ie_cause(new_msg, cc_ep->serving_location, cause, 0, 0);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, param.isdn_cause, param.sip_cause, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
/* send message to all terminators, if any */
for (relation = relation->next; relation; relation = relation->next) {
PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-REL-IND to terminator.\n", relation_name(relation));
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
/* add cause */
- osmo_cc_add_ie_cause(new_msg, cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR, 0, 0);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR, 0, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
+}
- if (!disconnect) {
- /* destroy call */
- call_destroy(call);
+static void routing_release(call_t *call, int argc, char *argv[], struct command_def *command_def)
+{
+ call_relation_t *relation = call->relation_list;
+ osmo_cc_msg_t *new_msg;
+
+ parse_params(argc, argv, command_def);
+
+ PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-REL-IND to originator.\n", relation_name(relation));
+
+ /* send message to originator */
+ new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
+ /* add cause */
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, param.isdn_cause, param.sip_cause, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
+
+ /* send message to all terminators, if any */
+ for (relation = relation->next; relation; relation = relation->next) {
+ PDEBUG(DROUTER, DEBUG_DEBUG, "%s CC-REL-IND to terminator.\n", relation_name(relation));
+ new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
+ /* add cause */
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NORM_CALL_CLEAR, 0, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
+
+ /* destroy call */
+ call_destroy(call);
}
#define db2level(db) pow(10, (double)(db) / 20.0)
@@ -1796,7 +1914,7 @@ void recv_dtmf(void *priv, char digit, dtmf_meas_t __attribute__((unused)) *meas
}
/* routing orders us to enable DTMF decoding */
-static void routing_dtmf(call_t *call)
+static void routing_dtmf(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
@@ -1809,7 +1927,7 @@ static void routing_dtmf(call_t *call)
}
/* routing orders us to disable DTMF decoding */
-static void routing_dtmf_stop(call_t *call)
+static void routing_dtmf_stop(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
call_relation_t *relation = call->relation_list;
@@ -1819,43 +1937,66 @@ static void routing_dtmf_stop(call_t *call)
}
/* routing failed, release the call */
-static void routing_error(call_t *call, char *error)
+struct param_def param_error[] = {
+ { .n = "string", .s = &param.error, .d = "error string to be displayed", .mandatory = 1 },
+ { .n = NULL }
+};
+
+static void routing_error(call_t *call, int __attribute__((unused)) argc, char __attribute__((unused)) *argv[], struct command_def __attribute__((unused)) *command_def)
{
osmo_cc_msg_t *new_msg;
call_relation_t *relation;
- PDEBUG(DROUTER, DEBUG_ERROR, "Routing script error: '%s'\n", error);
+ parse_params(argc, argv, command_def);
+
+ if (!param.error) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "'error' command reqires an error string as parameter.\n");
+ return;
+ }
+
+ PDEBUG(DROUTER, DEBUG_ERROR, "Routing script error: '%s'\n", param.error);
/* send message to originator */
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
- osmo_cc_add_ie_cause(new_msg, cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NETWORK_OOO, 0, 0);
- osmo_cc_ll_msg(cc_ep, call->relation_list->cc_callref, new_msg);
+ osmo_cc_add_ie_cause(new_msg, call->relation_list->cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NETWORK_OOO, 0, 0);
+ osmo_cc_ll_msg(call->relation_list->cc_ep, call->relation_list->cc_callref, new_msg);
/* send message to all terminators, if any */
for (relation = call->relation_list->next; relation; relation = relation->next) {
new_msg = osmo_cc_new_msg(OSMO_CC_MSG_REL_IND);
- osmo_cc_add_ie_cause(new_msg, cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NETWORK_OOO, 0, 0);
- osmo_cc_ll_msg(cc_ep, relation->cc_callref, new_msg);
+ osmo_cc_add_ie_cause(new_msg, relation->cc_ep->serving_location, OSMO_CC_ISDN_CAUSE_NETWORK_OOO, 0, 0);
+ osmo_cc_ll_msg(relation->cc_ep, relation->cc_callref, new_msg);
}
}
-#if 0
-/* routing script says something */
-static void routing_say(call_t *call, char *error)
-{
- char text[1024] = "";
- fuer alle argv
- fuege text hinzu
- PDEBUG(DROUTER, DEBUG_NOTICE, "Routing script says: %s\n", text);
- das script anpassen
-}
-#endif
+struct command_def command_def[] = {
+ { "rtp-proxy", routing_rtp_proxy, "Turn on RTP proxy, so that audio processing is possible.", param_rtp_proxy },
+ { "play", routing_play, "Play given audio file.", param_play },
+ { "play-stop", routing_play_stop, "Stop playing audio file.", NULL },
+ { "record", routing_record, "Record to given audio file.", param_record },
+ { "record-stop", routing_record_stop, "Stop recording audio file.", NULL },
+ { "tx-gain", routing_tx_gain, "Set gain of audio sent interface.", param_gain },
+ { "rx-gain", routing_rx_gain, "Set gain of audio received from interface.", param_gain },
+ { "call", routing_call, "Make one or mulriple calls to given interface.", param_call },
+ { "call-stop", routing_call_stop, "Stop outgoing call(s).", NULL },
+ { "overlap", routing_overlap, "Set caller into overlap state, digit may be dialed.", NULL },
+ { "proceeding", routing_proceeding, "Set caller into proceeding state, no digits may be dialed.", NULL },
+ { "alerting", routing_alerting, "Set caller into alerting state.", NULL },
+ { "answer", routing_answer, "Answer call from caller.", NULL },
+ { "disconnect", routing_disconnect, "Disconnect call towards caller and release callee, if any.", param_disc_rel },
+ { "release", routing_release, "Release call towards caller and release callee, if any.", param_disc_rel },
+ { "dtmf", routing_dtmf, "Turn on DTMF detection.", NULL },
+ { "dtmf-stop", routing_dtmf_stop, "Turn off DTMF detection.", NULL },
+ { "error", routing_error, "Display error message.", param_error },
+ { NULL, NULL, NULL, NULL }
+};
void routing_receive_stdout(routing_t *routing, const char *string)
{
call_t *call = routing->call;
int argc = 0;
char *argv[256], *token;
+ int i;
/* convert string into tokens */
while ((token = osmo_cc_strtok_quotes(&string)))
@@ -1863,65 +2004,13 @@ void routing_receive_stdout(routing_t *routing, const char *string)
if (!argc)
return;
- if (!strcasecmp(argv[0], "rtp-proxy"))
- routing_rtp_proxy(call, argc - 1, argv + 1);
- else
- if (!strcasecmp(argv[0], "play"))
- routing_play(call, argc - 1, argv + 1);
- else
- if (!strcasecmp(argv[0], "play-stop"))
- routing_play_stop(call);
- else
- if (!strcasecmp(argv[0], "record"))
- routing_record(call, argc - 1, argv + 1);
- else
- if (!strcasecmp(argv[0], "record-stop"))
- routing_record_stop(call);
- else
- if (!strcasecmp(argv[0], "tx-gain"))
- routing_gain(call, argc - 1, argv + 1, 1);
- else
- if (!strcasecmp(argv[0], "rx-gain"))
- routing_gain(call, argc - 1, argv + 1, 0);
- else
- if (!strcasecmp(argv[0], "call"))
- routing_call(call, argc - 1, argv + 1);
- else
- if (!strcasecmp(argv[0], "call-stop"))
- routing_call_stop(call);
- else
- if (!strcasecmp(argv[0], "overlap"))
- routing_overlap(call);
- else
- if (!strcasecmp(argv[0], "proceeding"))
- routing_proceeding(call);
- else
- if (!strcasecmp(argv[0], "alerting"))
- routing_alerting(call);
- else
- if (!strcasecmp(argv[0], "answer"))
- routing_answer(call);
- else
- if (!strcasecmp(argv[0], "disconnect"))
- routing_disc_rel(call, argc - 1, argv + 1, 1);
- else
- if (!strcasecmp(argv[0], "release"))
- routing_disc_rel(call, argc - 1, argv + 1, 0);
- else
- if (!strcasecmp(argv[0], "dtmf"))
- routing_dtmf(call);
- else
- if (!strcasecmp(argv[0], "dtmf-stop"))
- routing_dtmf_stop(call);
- else
- if (!strcasecmp(argv[0], "error"))
- routing_error(call, (argc > 1) ? argv[1] : "<unknown>");
- else
-#if 0
- if (!strcasecmp(argv[0], "say"))
- routing_say(call, argc - 1, argv + 1, 0);
- else
-#endif
+ for (i = 0; command_def[i].name; i++) {
+ if (!strcasecmp(argv[0], command_def[i].name)) {
+ command_def[i].func(call, argc - 1, argv + 1, &command_def[i]);
+ break;
+ }
+ }
+ if (!command_def[i].name)
PDEBUG(DROUTER, DEBUG_ERROR, "Unknown command '%s' from routing.\n", argv[0]);
while (argc)
@@ -1996,6 +2085,58 @@ void telephone_event(call_relation_t *relation, struct telephone_event *te)
routing_send(&relation->call->routing, digit_string);
}
+void routing_help(const char *command)
+{
+ int i, j, k;
+
+ if (!command) {
+ printf("Available routing commands:\n\n");
+ for (i = 0; command_def[i].name; i++) {
+ printf("Command: %s\n", command_def[i].name);
+ printf(" Description: %s\n", command_def[i].description);
+ }
+ printf("\nUse '-h <command>' for detailled description of a command.\n");
+ return;
+ }
+
+ for (i = 0; command_def[i].name; i++) {
+ if (!strcasecmp(command, command_def[i].name))
+ break;
+ }
+ if (!command_def[i].name) {
+ printf("Given Command '%s' unknown!\n", command);
+ return;
+ }
+
+ printf("Command: %s\n", command_def[i].name);
+ printf("Description: %s\n", command_def[i].description);
+
+ struct param_def *param_def = command_def[i].param_list;
+
+ if (!param_def) {
+ printf("This command does not have any parameters.\n");
+ return;
+ }
+
+ for (j = 0; param_def[j].n; j++) {
+ printf("Parameter: %s%s\n", param_def[j].n, (param_def[j].mandatory) ? " (manatory)" : "");
+ printf(" Description: %s\n", param_def[j].d);
+ if (param_def[j].o || param_def[j].t) {
+ for (k = 0; codecs_def[k].payload_name; k++) {
+ printf(" Value: '%s'\n", codecs_def[k].payload_name);
+ }
+ } else if (param_def[j].no_value) {
+ printf(" No value\n");
+ } else if (param_def[j].i && param_def[j].value2name) {
+ for (k = 0; k < param_def[j].num; k++) {
+ const char *name = param_def[j].value2name(k);
+ if (name && name[0] != '<')
+ printf(" Value: '%d' or '%s'\n", k, name);
+ }
+ }
+ }
+}
+
#warning add progress, if terminating call sends sdp but call state already reached
#warning beim disc muss progress geprueft werden und damit entschieden ob wir audio mitsenden sollen
diff --git a/src/router/call.h b/src/router/call.h
index 255ee20..ac672ac 100644
--- a/src/router/call.h
+++ b/src/router/call.h
@@ -96,3 +96,5 @@ int call_handle(void);
void cc_message(osmo_cc_endpoint_t *ep, uint32_t callref, osmo_cc_msg_t *msg);
void telephone_event(call_relation_t *relation, struct telephone_event *te);
+void routing_help(const char *command);
+
diff --git a/src/router/main.c b/src/router/main.c
index 82eeee3..eaf2d95 100644
--- a/src/router/main.c
+++ b/src/router/main.c
@@ -32,6 +32,7 @@
#include "audio.h"
#include "display.h"
+int show_help = 0;
int num_kanal = 1;
static osmo_cc_endpoint_t *cc_ep1 = NULL, *cc_ep2 = NULL;
@@ -85,9 +86,8 @@ static int handle_options(int short_option, int argi, char **argv)
switch (short_option) {
case 'h':
- print_usage(argv[0]);
- print_help();
- return 0;
+ show_help = 1;
+ break;
case 'v':
if (!strcasecmp(argv[argi], "list")) {
debug_list_cat();
@@ -182,6 +182,19 @@ int main(int argc, char *argv[])
argi = options_command_line(argc, argv, handle_options);
if (argi <= 0)
return argi;
+ if (show_help) {
+ if (argi < argc) {
+ routing_help(argv[argi]);
+ return 0;
+ }
+ print_usage(argv[0]);
+ print_help();
+ printf("\n");
+ env_help();
+ printf("\n");
+ routing_help(NULL);
+ return 0;
+ }
/* init osmo-cc endpoint */
cc_ep1 = calloc(1, sizeof(*cc_ep1));
diff --git a/src/router/routing.c b/src/router/routing.c
index b49f6d4..8d5485c 100644
--- a/src/router/routing.c
+++ b/src/router/routing.c
@@ -34,141 +34,270 @@
extern char **environ;
-static const char *env_int(const char *name, int value)
+static struct env {
+ int coding, capability, mode;
+
+ int type, plan, present, screen, reason;
+ char *number;
+
+ int network_type;
+ char *network_id;
+
+ int complete;
+} env;
+
+struct env_def {
+ const char *n;
+ char **s;
+ int *i;
+ const char *d;
+ const char *(*value2name)(int value);
+ int num;
+} env_def[] = {
+ { .n = "BEARER_CODING", .i = &env.coding, .d = "coding of bearer capability", .value2name = osmo_cc_coding_value2name, .num = OSMO_CC_CODING_NUM },
+ { .n = "BEARER_CAPABILITY", .i = &env.capability, .d = "bearer capability", .value2name = osmo_cc_capability_value2name, .num = OSMO_CC_CAPABILITY_NUM },
+ { .n = "BEARER_MODE", .i = &env.mode, .d = "mode of bearer", .value2name = osmo_cc_mode_value2name, .num = OSMO_CC_MODE_NUM },
+
+ { .n = "CALLING_TYPE", .i = &env.type, .d = "type of calling number", .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "CALLING_PLAN", .i = &env.plan, .d = "numbering plan of calling number", .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "CALLING_PRESENT", .i = &env.present, .d = "presentation of calling number", .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "CALLING_SCREEN", .i = &env.screen, .d = "screen of calling number", .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "CALLING", .s = &env.number, .d = "calling number" },
+ { .n = "CALLING_INTERFACE", .s = &env.number, .d = "calling interface name" },
+
+ { .n = "CALLING2_TYPE", .i = &env.type, .d = "type of second calling number", .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "CALLING2_PLAN", .i = &env.plan, .d = "numbering plan of awxons calling number", .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM},
+ { .n = "CALLING2_PRESENT", .i = &env.present, .d = "presentation of second calling number", .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "CALLING2_SCREEN", .i = &env.screen, .d = "screen of second calling number", .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "CALLING2", .s = &env.number, .d = "second calling number" },
+
+ { .n = "NETWORK_TYPE", .i = &env.network_type, .d = "type of calling network" },
+ { .n = "NETWORK_ID", .s = &env.network_id, .d = "id of subscriber at calling network" },
+
+ { .n = "REDIRECTING_TYPE", .i = &env.type, .d = "type of redirecting number", .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "REDIRECTING_PLAN", .i = &env.plan, .d = "numbering plan of redirecting number", .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "REDIRECTING_PRESENT", .i = &env.present, .d = "presentation of redirecting number", .value2name = osmo_cc_present_value2name, .num = OSMO_CC_PRESENT_NUM },
+ { .n = "REDIRECTING_SCREEN", .i = &env.screen, .d = "screen of redirecting number", .value2name = osmo_cc_screen_value2name, .num = OSMO_CC_SCREEN_NUM },
+ { .n = "REDIRECTING_REASON", .i = &env.reason, .d = "reason for redirecting", .value2name = osmo_cc_redir_reason_value2name, .num = OSMO_CC_REDIR_REASON_NUM },
+ { .n = "REDIRECTING", .s = &env.number, .d = "redirecting number" },
+
+ { .n = "DIALING_TYPE", .i = &env.type, .d = "type of dialing number", .value2name = osmo_cc_type_value2name, .num = OSMO_CC_TYPE_NUM },
+ { .n = "DIALING_PLAN", .i = &env.plan, .d = "numbering plan of dialing number", .value2name = osmo_cc_plan_value2name, .num = OSMO_CC_PLAN_NUM },
+ { .n = "DIALING", .s = &env.number, .d = "dialing number" },
+ { .n = "KEYPAD", .s = &env.number, .d = "keypad dialing (May be uses for special ISDN applications.)" },
+
+ { .n = "COMPLETE", .i = &env.complete, .d = "set to '1' if dialing is a complete number" },
+
+ { .n = NULL }
+};
+
+static int env_set(routing_t *routing, const char *name, int index)
{
- char *string = malloc(strlen(name) + 20);
+ int i;
- sprintf(string, "CC_%s=%d", name, value);
-
- return string;
-}
+ for (i = 0; env_def[i].n; i++) {
+ if (!strcmp(env_def[i].n, name))
+ break;
+ }
+ if (!env_def[i].n) {
+ PDEBUG(DROUTER, DEBUG_ERROR, "Software error: Environment variable '%s' does not exist in definition, please fix!\n", name);
+ return index;
+ }
-static const char *env_string(const char *name, const char *value)
-{
- char *string = malloc(strlen(name) + strlen(value) + 8);
+ if (env_def[i].s) {
+ char *string = malloc(strlen(name) + strlen(*env_def[i].s) + 8);
+ sprintf(string, "CC_%s=%s", name, *env_def[i].s);
+ routing->envp[index++] = string;
+ }
- sprintf(string, "CC_%s=%s", name, value);
+ if (env_def[i].i) {
+ char *string = malloc(strlen(name) + 30);
+ sprintf(string, "CC_%s=%d", name, *env_def[i].i);
+ routing->envp[index++] = string;
+ if (env_def[i].value2name && env_def[i].value2name(*env_def[i].i)[0] != '<') {
+ char *string = malloc(strlen(name) + strlen(env_def[i].value2name(*env_def[i].i)) + 16);
+ sprintf(string, "CC_%s_NAME=%s", name, env_def[i].value2name(*env_def[i].i));
+ routing->envp[index++] = string;
+ }
+ }
- return string;
+ return index;
}
-static void enqueue_string(struct string_queue **queue_p, const char *string, const char *suffix)
+static void env_add(routing_t *routing, const char *name)
{
- struct string_queue *queue;
-
- queue = calloc(1, sizeof(*queue));
- queue->string = malloc(strlen(string) + strlen(suffix) + 1);
- strcpy(queue->string, string);
- strcat(queue->string, suffix);
-
- while (*queue_p)
- queue_p = &((*queue_p)->next);
- *queue_p = queue;
+ routing->envc = env_set(routing, name, routing->envc);
}
-static char *dequeue_string(struct string_queue **queue_p)
+void env_help(void)
{
- struct string_queue *queue = *queue_p;
- char *string;
-
- if (!queue)
- return NULL;
-
- string = queue->string;
- *queue_p = queue->next;
- free(queue);
-
- return string;
+ int i;
+
+ printf("Available environment variables:\n\n");
+ for (i = 0; env_def[i].n; i++) {
+ printf("Variable: CC_%s\n", env_def[i].n);
+ printf(" Description: %s\n", env_def[i].d);
+ if (env_def[i].value2name) {
+ printf(" Additional variable: CC_%s_NAME\n", env_def[i].n);
+ }
+ }
}
/* prepare environment with setup info */
void routing_env_msg(routing_t *routing, osmo_cc_msg_t *msg)
{
+ int rc, i;
uint8_t coding, capability, mode;
uint8_t type, plan, present, screen, reason;
+ char number[256];
uint8_t network_type;
- char number[256], network_id[256];
- int rc, i;
+ char network_id[256];
for (i = 0; environ[i]; i++) {
routing->envp[routing->envc++] = strdup(environ[i]);
}
+ memset(&env, 0, sizeof(env));
+
rc = osmo_cc_get_ie_bearer(msg, 0, &coding, &capability, &mode);
if (rc >= 0) {
- routing->envp[routing->envc++] = env_int("BEARER_CODING", coding);
- routing->envp[routing->envc++] = env_int("BEARER_CAPABILITY", capability);
- routing->envp[routing->envc++] = env_int("BEARER_MODE", mode);
+ env.coding = coding;
+ env.capability = capability;
+ env.mode = mode;
+ env_add(routing, "BEARER_CODING");
+ env_add(routing, "BEARER_CAPABILITY");
+ env_add(routing, "BEARER_MODE");
}
rc = osmo_cc_get_ie_calling(msg, 0, &type, &plan, &present, &screen, number, sizeof(number));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_int("CALLING_TYPE", type);
- routing->envp[routing->envc++] = env_int("CALLING_PLAN", plan);
- routing->envp[routing->envc++] = env_int("CALLING_PRESENT", present);
- routing->envp[routing->envc++] = env_int("CALLING_SCREEN", screen);
- routing->envp[routing->envc++] = env_string("CALLING", number);
+ env.type = type;
+ env.plan = plan;
+ env.present = present;
+ env.screen = screen;
+ env.number = number;
+ env_add(routing, "CALLING_TYPE");
+ env_add(routing, "CALLING_PLAN");
+ env_add(routing, "CALLING_PRESENT");
+ env_add(routing, "CALLING_SCREEN");
+ env_add(routing, "CALLING");
}
rc = osmo_cc_get_ie_calling_interface(msg, 0, number, sizeof(number));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_string("CALLING_INTERFACE", number);
+ env.number = number;
+ env_add(routing, "CALLING_INTERFACE");
}
rc = osmo_cc_get_ie_calling(msg, 1, &type, &plan, &present, &screen, number, sizeof(number));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_int("CALLING2_TYPE", type);
- routing->envp[routing->envc++] = env_int("CALLING2_PLAN", plan);
- routing->envp[routing->envc++] = env_int("CALLING2_PRESENT", present);
- routing->envp[routing->envc++] = env_int("CALLING2_SCREEN", screen);
- routing->envp[routing->envc++] = env_string("CALLING2", number);
+ env.type = type;
+ env.plan = plan;
+ env.present = present;
+ env.screen = screen;
+ env.number = number;
+ env_add(routing, "CALLING2_TYPE");
+ env_add(routing, "CALLING2_PLAN");
+ env_add(routing, "CALLING2_PRESENT");
+ env_add(routing, "CALLING2_SCREEN");
+ env_add(routing, "CALLING2");
}
rc = osmo_cc_get_ie_calling_network(msg, 0, &network_type, network_id, sizeof(network_id));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_string("NETWORK_TYPE", osmo_cc_network_type_name(network_type));
- routing->envp[routing->envc++] = env_string("NETWORK_ID", network_id);
+ env.network_type = network_type;
+ env.network_id = network_id;
+ env_add(routing, "NETWORK_TYPE");
+ env_add(routing, "NETWORK_ID");
}
rc = osmo_cc_get_ie_redir(msg, 0, &type, &plan, &present, &screen, &reason, number, sizeof(number));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_int("REDIRECTING_TYPE", type);
- routing->envp[routing->envc++] = env_int("REDIRECTING_PLAN", plan);
- routing->envp[routing->envc++] = env_int("REDIRECTING_PRESENT", present);
- routing->envp[routing->envc++] = env_int("REDIRECTING_SCREEN", screen);
- routing->envp[routing->envc++] = env_int("REDIRECTING_REASON", reason);
- routing->envp[routing->envc++] = env_string("REDIRECTING", number);
+ env.type = type;
+ env.plan = plan;
+ env.present = present;
+ env.screen = screen;
+ env.reason = reason;
+ env.number = number;
+ env_add(routing, "REDIRECTING_TYPE");
+ env_add(routing, "REDIRECTING_PLAN");
+ env_add(routing, "REDIRECTING_PRESENT");
+ env_add(routing, "REDIRECTING_SCREEN");
+ env_add(routing, "REDIRECTING_REASON");
+ env_add(routing, "REDIRECTING");
}
rc = osmo_cc_get_ie_called(msg, 0, &type, &plan, number, sizeof(number));
if (rc >= 0) {
- routing->envp[routing->envc++] = env_int("DIALING_TYPE", type);
- routing->envp[routing->envc++] = env_int("DIALING_PLAN", plan);
+ env.type = type;
+ env.plan = plan;
+ env_add(routing, "DIALING_TYPE");
+ env_add(routing, "DIALING_PLAN");
} else
number[0] = 0;
/* variable must always be present, so it can be updated when overlap dialing */
routing->envc_dialing = routing->envc;
- routing->envp[routing->envc++] = env_string("DIALING", number);
+ env.number = number;
+ env_add(routing, "DIALING");
rc = osmo_cc_get_ie_keypad(msg, 0, number, sizeof(number));
if (rc < 0)
number[0] = 0;
/* variable must always be present, so it can be updated when overlap dialing */
routing->envc_keypad = routing->envc;
- routing->envp[routing->envc++] = env_string("KEYPAD", number);
+ env.number = number;
+ env_add(routing, "KEYPAD");
rc = osmo_cc_get_ie_complete(msg, 0);
if (rc >= 0)
- routing->envp[routing->envc++] = env_int("COMPLETE", 1);
+ env.complete = 1;
+ /* variable must always be present, so it can be updated when overlap dialing */
+ routing->envc_complete = routing->envc;
+ env_add(routing, "COMPLETE");
routing->envp[routing->envc++] = NULL;
}
/* update environment with info message */
-void routing_env_dialing(routing_t *routing, const char *number, const char *keypad)
+void routing_env_dialing(routing_t *routing, char *number, char *keypad, int complete)
{
free((char *)routing->envp[routing->envc_dialing]);
- routing->envp[routing->envc_dialing] = env_string("DIALING", number);
+ env.number = number;
+ env_set(routing, "DIALING", routing->envc_dialing);
free((char *)routing->envp[routing->envc_keypad]);
- routing->envp[routing->envc_keypad] = env_string("KEYPAD", keypad);
+ env.number = keypad;
+ env_set(routing, "KEYPAD", routing->envc_keypad);
+
+ free((char *)routing->envp[routing->envc_complete]);
+ env.complete = complete;
+ env_set(routing, "COMPLETE", routing->envc_complete);
+}
+
+static void enqueue_string(struct string_queue **queue_p, const char *string, const char *suffix)
+{
+ struct string_queue *queue;
+
+ queue = calloc(1, sizeof(*queue));
+ queue->string = malloc(strlen(string) + strlen(suffix) + 1);
+ strcpy(queue->string, string);
+ strcat(queue->string, suffix);
+
+ while (*queue_p)
+ queue_p = &((*queue_p)->next);
+ *queue_p = queue;
+}
+
+static char *dequeue_string(struct string_queue **queue_p)
+{
+ struct string_queue *queue = *queue_p;
+ char *string;
+
+ if (!queue)
+ return NULL;
+
+ string = queue->string;
+ *queue_p = queue->next;
+ free(queue);
+
+ return string;
}
void routing_env_free(routing_t *routing)
diff --git a/src/router/routing.h b/src/router/routing.h
index bab5502..d5e43ca 100644
--- a/src/router/routing.h
+++ b/src/router/routing.h
@@ -15,6 +15,7 @@ typedef struct routing {
const char *envp[256]; /* environment variables */
int envc_dialing; /* envc index for dialing number */
int envc_keypad; /* envc index for keypad */
+ int envc_complete; /* envc index for complete */
pid_t script_pid; /* pid of routing script */
int script_stdin; /* pipe to stdin */
@@ -32,8 +33,9 @@ typedef struct routing {
struct string_queue *stderr_queue; /* strings read from script */
} routing_t;
+void env_help(void);
void routing_env_msg(routing_t *routing, osmo_cc_msg_t *msg);
-void routing_env_dialing(routing_t *routing, const char *number, const char *keypad);
+void routing_env_dialing(routing_t *routing, char *number, char *keypad, int complete);
void routing_env_free(routing_t *routing);
void routing_start(routing_t *routing, const char *script, const char *shell);
void routing_stop(routing_t *routing);