diff options
Diffstat (limited to 'src/sip/main.c')
-rw-r--r-- | src/sip/main.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/sip/main.c b/src/sip/main.c new file mode 100644 index 0000000..f0a6e4d --- /dev/null +++ b/src/sip/main.c @@ -0,0 +1,371 @@ +/* osmo-cc-sip-endpoint 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 "../libdebug/debug.h" +#include "../liboptions/options.h" +#include "sip.h" + +sip_endpoint_t *sip_ep = NULL; +int num_kanal = 1; + +int sofia_debug = 0; +int send_no_ringing_after_progress = 0; +int receive_no_ringing_after_progress = 0; +const char *name = "sip"; +const char *local_user = NULL; +const char *local_peer = NULL; +const char *remote_user = NULL; +const char *remote_peer = NULL; +const char *asserted_id = NULL; +int local_register = 0; +int remote_register = 0; +const char *register_user = NULL; +const char *register_peer = NULL; +int local_auth = 0; +int remote_auth = 0; +const char *auth_user = NULL; +const char *auth_password = NULL; +const char *auth_realm = NULL; +const char *public_ip = NULL; +const char *stun_server = NULL; +int register_interval = 600; +int options_interval = 60; +int stun_interval = 60; +int expires = 0; +#define MAX_CC_ARGS 1024 +static int cc_argc = 0; +static const char *cc_argv[MAX_CC_ARGS]; + +static void print_usage(const char *app) +{ + printf("Usage: %s --local [<user>@]<address> --remote [<user>@]<address> [<options>]\n", app); +} + +static void print_help() +{ + /* - - */ + printf(" -h --help\n"); + printf(" This help\n"); + printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n"); + printf(" Use 'list' to get a list of all levels and categories\n"); + printf(" Verbose level: digit of debug level (default = '%d')\n", debuglevel); + printf(" Verbose level+category: level digit followed by one or more categories\n"); + printf(" -> If no category is specified, all categories are selected\n"); + printf(" -D --sofia-debug <level>\n"); + printf(" A level of 0 is off, a level of 9 is full debugging. (default = %d)\n", sofia_debug); + printf(" --send-ner\n"); + printf(" Do not send extra ringing response (180), after progress response (183)\n"); + printf(" was sent.\n"); + printf(" --receive-ner\n"); + printf(" Do not expect to receive extra ringing response (180), after progress\n"); + printf(" response (183) was received.\n"); + printf(" -n --name <interface name>\n"); + printf(" Give name of this interface. It will be sent in each call towards\n"); + printf(" remote interface. (default = '%s')\n", name); + printf(" -l --local [<user>@]<address>\n"); + printf(" Give local SIP peer. It will be used for local URI.\n"); + printf(" If user is not given, the caller ID is used as user.\n"); + printf(" -r --remote [<user>@]<address>\n"); + printf(" Give remote SIP peer. It will be used for remote URI.\n"); + printf(" If user is not given, the dialed number is used as user.\n"); + printf(" -a --asserted-id <user>\n"); + printf(" The asserted ID is used to idenitfy the actual SIP user, if the local\n"); + printf(" and remote user in their URI are replaced by caller ID and dialed\n"); + printf(" number. To send caller ID, you must not specify user at local SIP peer.\n"); + printf(" To send dialed number, you must not specify user at remote SIP peer.\n"); + printf(" -R --register <user>@<address>\n"); + printf(" Give user and address to register at a remote SIP registrar.\n"); + printf(" --local-register\n"); + printf(" Define, if the remote must register to us, so that we know the remote\n"); + printf(" address.\n"); + printf(" --remote-register\n"); + printf(" Define, if we must register to a registrar.\n"); + printf(" If '--register' was given, but not any of '--local-register' or\n"); + printf(" '--remote-register', remote registration automatically used.\n"); + printf(" -A --auth <user> <password> <realm>\n"); + printf(" Define, if we must perform authentication.\n"); + printf(" Realm can be set to anything. It is relevant for local authentication.\n"); + printf(" --local-auth\n"); + printf(" Define, if the remote must authenticate when calling (or registering)\n"); + printf(" to us.\n"); + printf(" --remote-auth\n"); + printf(" Define, if we must authenticate when calling (or registering) towards\n"); + printf(" remote.\n"); + printf(" If '--auth' was given, but not any of '--local-auth' or\n"); + printf(" '--remote-auth', remote authentication automatically used.\n"); + printf(" -P --public-ip <ip>\n"); + printf(" If our local IP is changed by NAT, give the actual public IP.\n"); + printf(" -S --stun-server <address>\n"); + printf(" Instead of dynamic public IP, a STUN server can be given.\n"); + printf(" --register-interval <seconds> (default = %d seconds)\n", register_interval); + printf(" --options-interval <seconds> (default = %d seconds)\n", options_interval); + printf(" --stun-interval <seconds> (default = %d seconds)\n", stun_interval); + printf(" --expires <seconds> | 0 (default = %d seconds)\n", expires); + printf(" Alter intervals, if needed.\n"); + printf(" -C --cc \"<osmo-cc arg>\" [--cc ...]\n"); + printf(" Pass arguments to Osmo-CC endpoint. Use '-cc help' for description.\n"); +} + +#define OPT_SEND_NER 256 +#define OPT_RECEIVE_NER 257 +#define OPT_LOCAL_REG 258 +#define OPT_REMOTE_REG 259 +#define OPT_LOCAL_AUTH 260 +#define OPT_REMOTE_AUTH 261 +#define OPT_REG_INTER 262 +#define OPT_OPT_INTER 263 +#define OPT_STUN_INTER 264 +#define OPT_EXPIRES 265 + +static void add_options(void) +{ + option_add('h', "help", 0); + option_add('v', "verbose", 1); + option_add('D', "sofia-debug", 1); + option_add(OPT_SEND_NER, "send-ner", 0); + option_add(OPT_RECEIVE_NER, "receive-ner", 0); + option_add('n', "name", 1); + option_add('l', "local", 1); + option_add('r', "remote", 1); + option_add('a', "asserted-id", 1); + option_add('R', "register", 1); + option_add(OPT_LOCAL_REG, "local-register", 0); + option_add(OPT_REMOTE_REG, "remote-register", 0); + option_add('A', "auth", 3); + option_add(OPT_LOCAL_AUTH, "local-auth", 0); + option_add(OPT_REMOTE_AUTH, "remote-auth", 0); + option_add('P', "public-ip", 1); + option_add('S', "stun-server", 1); + option_add(OPT_REG_INTER, "register-interval", 1); + option_add(OPT_OPT_INTER, "options-interval", 1); + option_add(OPT_STUN_INTER, "stun-interval", 1); + option_add(OPT_EXPIRES, "expires", 1); + option_add('C', "cc", 1); +} + +static int handle_options(int short_option, int argi, char **argv) +{ + const char *p; + int rc; + + switch (short_option) { + case 'h': + print_usage(argv[0]); + print_help(); + return 0; + 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 'D': + sofia_debug = atoi(argv[argi]); + break; + case OPT_SEND_NER: + send_no_ringing_after_progress = 1; + break; + case OPT_RECEIVE_NER: + receive_no_ringing_after_progress = 1; + break; + case 'n': + name = strdup(argv[argi]); + break; + case 'l': + if ((p = strchr(argv[argi], '@'))) { + local_user = strdup(argv[argi]); + *strchr(local_user, '@') = '\0'; + local_peer = strdup(p + 1); + } else + local_peer = strdup(argv[argi]); + break; + case 'r': + if ((p = strchr(argv[argi], '@'))) { + remote_user = strdup(argv[argi]); + *strchr(remote_user, '@') = '\0'; + remote_peer = strdup(p + 1); + } else + remote_peer = strdup(argv[argi]); + break; + case 'a': + asserted_id = strdup(argv[argi]); + break; + case 'R': + if ((p = strchr(argv[argi], '@'))) { + register_user = strdup(argv[argi]); + *strchr(register_user, '@') = '\0'; + register_peer = strdup(p + 1); + } else { + fprintf(stderr, "Missing '@' sign in given registrar!\n"); + return -EINVAL; + } + break; + case OPT_LOCAL_REG: + local_register = 1; + break; + case OPT_REMOTE_REG: + remote_register = 1; + break; + case 'A': + auth_user = strdup(argv[argi]); + auth_password = strdup(argv[argi + 1]); + auth_realm = strdup(argv[argi + 2]); + break; + case OPT_LOCAL_AUTH: + local_auth = 1; + break; + case OPT_REMOTE_AUTH: + remote_auth = 1; + break; + case 'P': + public_ip = strdup(argv[argi]); + break; + case 'S': + stun_server = strdup(argv[argi]); + break; + case OPT_REG_INTER: + register_interval = atoi(argv[argi]); + break; + case OPT_OPT_INTER: + options_interval = atoi(argv[argi]); + break; + case OPT_STUN_INTER: + stun_interval = atoi(argv[argi]); + break; + case OPT_EXPIRES: + expires = atoi(argv[argi]); + break; + case 'C': + if (!strcasecmp(argv[argi], "help")) { + osmo_cc_help(); + return 0; + } + if (cc_argc == MAX_CC_ARGS) { + fprintf(stderr, "Too many osmo-cc args!\n"); + break; + } + cc_argv[cc_argc++] = 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; +} + +int main(int argc, char *argv[]) +{ + int argi, rc; + + cc_argv[cc_argc++] = strdup("remote auto"); + + /* handle options / config file */ + add_options(); + rc = options_config_file("~/.osmocom/sip/sip.conf", handle_options); + if (rc < 0) + return 0; + argi = options_command_line(argc, argv, handle_options); + if (argi <= 0) + return argi; + + sip_init(sofia_debug); + + /* complete remote register and authentication flag */ + if (register_peer && !local_register && !remote_register) + remote_register = 1; + if (auth_user && !local_auth && !remote_auth) + remote_auth = 1; + + if (!local_peer) { + PDEBUG(DSIP, DEBUG_ERROR, "You must specify local SIP peer!\n"); + return -EINVAL; + } + + if (!remote_peer) { + PDEBUG(DSIP, DEBUG_ERROR, "You must specify remote SIP peer!\n"); + return -EINVAL; + } + + if (!cc_argc || !!strncasecmp(cc_argv[0], "help", 4)) { + sip_ep = sip_endpoint_create(send_no_ringing_after_progress, receive_no_ringing_after_progress, name, local_user, local_peer, remote_user, remote_peer, asserted_id, local_register, remote_register, register_user, register_peer, local_auth, remote_auth, auth_user, auth_password, auth_realm, public_ip, stun_server, register_interval, options_interval, stun_interval, expires); + if (!sip_ep) { + PDEBUG(DSIP, DEBUG_ERROR, "SIP initializing failed!\n"); + goto error; + } + } + + rc = osmo_cc_new(&sip_ep->cc_ep, OSMO_CC_VERSION, name, OSMO_CC_LOCATION_BEYOND_INTERWORKING, cc_message, NULL, sip_ep, cc_argc, cc_argv); + if (rc) + goto error; + + signal(SIGINT, sighandler); + signal(SIGHUP, sighandler); + signal(SIGTERM, sighandler); + signal(SIGPIPE, sighandler); + + while (!quit) { + int w; + process_timer(); + sip_handle(sip_ep); + do { + w = 0; + w |= osmo_cc_handle(); + } while (w); + usleep(1000); + } + + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + +error: + if (sip_ep) { + osmo_cc_delete(&sip_ep->cc_ep); + sip_endpoint_destroy(sip_ep); + } + + sip_exit(); + + return 0; +} + |