summaryrefslogtreecommitdiffstats
path: root/src/sip/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sip/main.c')
-rw-r--r--src/sip/main.c371
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;
+}
+