osmo-cc-router/src/router/main.c

308 lines
7.0 KiB
C

/* osmo-cc-router main
*
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <termios.h>
#include "../libdebug/debug.h"
#include "../liboptions/options.h"
#include "../libg711/g711.h"
#include "call.h"
#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;
static char *routing_script = "~/.osmocom/router/routing.sh";
static char *routing_shell = "bash";
#define MAX_CC_ARGS 1024
static int cc_argc1 = 0, cc_argc2 = 0;
static const char *cc_argv1[MAX_CC_ARGS], *cc_argv2[MAX_CC_ARGS];
static void print_usage(const char *app)
{
printf("Usage: %s [<options>]\n", app);
}
static void print_help()
{
/* - - */
printf(" -h --help\n");
printf(" This help\n");
printf(" --config [~/]<path to config file>\n");
printf(" Give a config file to use. If it starts with '~/', path is at home dir.\n");
printf(" Each line in config file is one option, '-' or '--' must not be given!\n");
debug_print_help();
printf(" -r --routing-script <script>\n");
printf(" Define the script/executable that is executed to perform routing\n");
printf(" decision for each call. (default = %s)\n", routing_script);
printf(" -s --routing-shell <>\n");
printf(" Define the shell to run the routing scrip. (default = %s)\n", routing_shell);
printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n");
printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n");
printf(" --cc2 \"<osmo-cc arg>\" [--cc2 ...]\n");
printf(" Pass arguments to Osmo-CC endpoint of second instance. (multistack).\n");
}
#define OPT_CC2 256
static void add_options(void)
{
option_add('h', "help", 0);
option_add('v', "verbose", 1);
option_add('r', "routing-script", 1);
option_add('s', "routing-shell", 1);
option_add('C', "cc", 1);
option_add(OPT_CC2, "cc2", 1);
}
static int handle_options(int short_option, int argi, char **argv)
{
int rc;
switch (short_option) {
case 'h':
show_help = 1;
break;
case 'v':
if (!strcasecmp(argv[argi], "list")) {
debug_list_cat();
return 0;
}
rc = parse_debug_opt(argv[argi]);
if (rc < 0) {
fprintf(stderr, "Failed to parse debug option, please use -h for help.\n");
return rc;
}
break;
case 'r':
routing_script = options_strdup(argv[argi]);
break;
case 's':
routing_shell = options_strdup(argv[argi]);
break;
case 'C':
if (!strcasecmp(argv[argi], "help")) {
osmo_cc_help();
return 0;
}
if (cc_argc1 == MAX_CC_ARGS) {
fprintf(stderr, "Too many osmo-cc args!\n");
break;
}
cc_argv1[cc_argc1++] = options_strdup(argv[argi]);
break;
case OPT_CC2:
if (!strcasecmp(argv[argi], "help")) {
osmo_cc_help();
return 0;
}
if (cc_argc2 == MAX_CC_ARGS) {
fprintf(stderr, "Too many osmo-cc args!\n");
break;
}
cc_argv2[cc_argc2++] = options_strdup(argv[argi]);
break;
default:
return -EINVAL;
}
return 1;
}
static int quit = 0;
void sighandler(int sigset)
{
if (sigset == SIGHUP || sigset == SIGPIPE)
return;
fprintf(stderr, "\nSignal %d received.\n", sigset);
quit = 1;
}
static int get_char()
{
struct timeval tv = {0, 0};
fd_set fds;
char c = 0;
int __attribute__((__unused__)) rc;
FD_ZERO(&fds);
FD_SET(0, &fds);
select(0+1, &fds, NULL, NULL, &tv);
if (FD_ISSET(0, &fds)) {
rc = read(0, &c, 1);
return c;
} else
return -1;
}
int main(int argc, char *argv[])
{
double last_time_call = 0, now;
int argi, rc;
struct termios term, term_orig;
int c;
/* init FM */
fm_init(0);
/* init codecs (for recording) */
g711_init();
/* handle options / config file */
add_options();
rc = options_config_file(argc, argv, "~/.osmocom/router/router.conf", handle_options);
if (rc < 0)
return 0;
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));
if (!cc_ep1)
goto error;
rc = osmo_cc_new(cc_ep1, OSMO_CC_VERSION, NULL, OSMO_CC_LOCATION_PRIV_SERV_LOC_USER, cc_message, NULL, NULL, cc_argc1, cc_argv1);
if (rc < 0)
goto error;
if (cc_argc2) {
/* init osmo-cc endpoint */
cc_ep2 = calloc(1, sizeof(*cc_ep2));
if (!cc_ep2)
goto error;
rc = osmo_cc_new(cc_ep2, OSMO_CC_VERSION, NULL, OSMO_CC_LOCATION_PRIV_SERV_LOC_USER, cc_message, NULL, NULL, cc_argc2, cc_argv2);
if (rc < 0)
goto error;
}
/* init call handling */
call_init(cc_ep1, cc_ep2, routing_script, routing_shell);
/* prepare terminal */
tcgetattr(0, &term_orig);
term = term_orig;
term.c_lflag &= ~(ISIG|ICANON|ECHO);
term.c_cc[VMIN]=1;
term.c_cc[VTIME]=2;
tcsetattr(0, TCSANOW, &term);
/* catch signals */
signal(SIGINT, sighandler);
signal(SIGHUP, sighandler);
signal(SIGTERM, sighandler);
signal(SIGPIPE, sighandler);
printf("\nRouter is ready to process calls.\n\n");
while (!quit) {
int w;
/* send clock calls to play/record audio files */
now = get_time();
if (now - last_time_call >= 0.1)
last_time_call = now;
if (now - last_time_call >= 0.020) {
last_time_call += 0.020;
/* call clock every 20ms */
call_clock(160);
}
process_timer();
call_media_handle();
do {
w = 0;
w |= osmo_cc_handle();
w |= call_handle();
} while (w);
usleep(1000);
/* process keyboard input */
next_char:
c = get_char();
switch (c) {
case 3:
printf("CTRL+c received, quitting!\n");
quit = 1;
goto next_char;
case 'c':
display_status_on(-1);
goto next_char;
}
}
/* reset signals */
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGPIPE, SIG_DFL);
/* reset terminal */
tcsetattr(0, TCSANOW, &term_orig);
error:
if (cc_ep1) {
/* exit call handling */
call_exit();
/* exit osmo-cc endpoint */
osmo_cc_delete(cc_ep1);
free(cc_ep1);
}
if (cc_ep2) {
/* exit call handling */
call_exit();
/* exit osmo-cc endpoint */
osmo_cc_delete(cc_ep2);
free(cc_ep2);
}
/* exit FM */
fm_exit();
options_free();
return 0;
}