/* osmo-cc-sip-endpoint main * * (C) 2020 by Andreas Eversberg * 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 . */ #include #include #include #include #include #include #include #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 *user_agent = "osmo-cc-sip-endpoint"; 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; int remote_nat_sip = 0; int remote_nat_rtp = 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 [@]
--remote [@]
[]\n", app); } static void print_help() { /* - - */ printf(" -h --help\n"); printf(" This help\n"); printf(" --config [~/]\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(" -D --sofia-debug \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 \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 [@]
\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 [@]
\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 \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 @
\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(" --remote-nat-sip\n"); printf(" Ignore the address+port from the SIP contact. Use the address+port from\n"); printf(" where the SIP massasge was sent.\n"); printf(" --remote-nat-rtp\n"); printf(" Ignore the RTP address from the SDP message. Use the RTP address from\n"); printf(" the remote peer. (untested!)\n"); printf(" -A --auth \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 \n"); printf(" If our local IP is changed by NAT, give the actual public IP.\n"); printf(" -S --stun-server
\n"); printf(" Instead of dynamic public IP, a STUN server can be given.\n"); printf(" --register-interval (default = %d seconds)\n", register_interval); printf(" --options-interval (default = %d seconds)\n", options_interval); printf(" --stun-interval (default = %d seconds)\n", stun_interval); printf(" --expires | 0 (default = %d seconds)\n", expires); printf(" Alter intervals, if needed.\n"); printf(" -U --user-endpoint \n"); printf(" Any string that is used as user agent. (default = '%s')\n", user_agent); printf(" -C --cc \"\" [--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_REMOTE_SIP 260 #define OPT_REMOTE_RTP 261 #define OPT_LOCAL_AUTH 262 #define OPT_REMOTE_AUTH 263 #define OPT_REG_INTER 264 #define OPT_OPT_INTER 265 #define OPT_STUN_INTER 266 #define OPT_EXPIRES 267 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(OPT_REMOTE_SIP, "remote-nat-sip", 0); option_add(OPT_REMOTE_RTP, "remote-nat-rtp", 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('U', "user-agent", 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 = options_strdup(argv[argi]); break; case 'l': if ((p = strchr(argv[argi], '@'))) { local_user = options_strdup(argv[argi]); *strchr(local_user, '@') = '\0'; local_peer = options_strdup(p + 1); } else local_peer = options_strdup(argv[argi]); break; case 'r': if ((p = strchr(argv[argi], '@'))) { remote_user = options_strdup(argv[argi]); *strchr(remote_user, '@') = '\0'; remote_peer = options_strdup(p + 1); } else remote_peer = options_strdup(argv[argi]); break; case 'a': asserted_id = options_strdup(argv[argi]); break; case 'R': if ((p = strchr(argv[argi], '@'))) { register_user = options_strdup(argv[argi]); *strchr(register_user, '@') = '\0'; register_peer = options_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 OPT_REMOTE_SIP: remote_nat_sip = 1; break; case OPT_REMOTE_RTP: remote_nat_rtp = 1; break; case 'A': auth_user = options_strdup(argv[argi]); auth_password = options_strdup(argv[argi + 1]); auth_realm = options_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 = options_strdup(argv[argi]); break; case 'S': stun_server = options_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 'U': user_agent = options_strdup(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++] = 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; } int main(int argc, char *argv[]) { int argi, rc; cc_argv[cc_argc++] = options_strdup("remote auto"); /* handle options / config file */ add_options(); rc = options_config_file(argc, argv, "~/.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"); goto error; } if (!remote_peer && !local_register) { PDEBUG(DSIP, DEBUG_ERROR, "You must specify remote SIP peer!\n"); goto error; } if (!auth_user && local_auth) { PDEBUG(DSIP, DEBUG_ERROR, "You must specify authentication parameters!\n"); goto error; } if (!cc_argc || !!strncasecmp(cc_argv[0], "help", 4)) { sip_ep = sip_endpoint_create(user_agent, 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, remote_nat_sip, remote_nat_rtp, 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(); options_free(); return 0; }