blob: 0b2ecce09f82a31fd293acd358cee79564b74f37 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The main method to drive it as a standalone process */
3
4/*
5 * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2011 by On-Waves
Harald Weltea896f9c2017-11-17 15:08:41 +01007 * (C) 2017 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02008 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <ctype.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#include <limits.h>
31#include <unistd.h>
32#include <errno.h>
33
34#include <sys/socket.h>
35
Philipp Maier87bd9be2017-08-22 16:35:41 +020036#include <osmocom/mgcp/mgcp.h>
37#include <osmocom/mgcp/mgcp_internal.h>
38#include <osmocom/mgcp/vty.h>
Philipp Maierc3413882017-10-27 12:26:54 +020039#include <osmocom/mgcp/debug.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010040#include <osmocom/mgcp/mgcp_endp.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020041
42#include <osmocom/core/application.h>
43#include <osmocom/core/msgb.h>
44#include <osmocom/core/talloc.h>
45#include <osmocom/core/select.h>
46#include <osmocom/core/stats.h>
47#include <osmocom/core/rate_ctr.h>
48#include <osmocom/core/logging.h>
Harald Welte8890dfa2017-11-17 15:09:30 +010049#include <osmocom/core/socket.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020050
51#include <osmocom/vty/telnet_interface.h>
52#include <osmocom/vty/logging.h>
53#include <osmocom/vty/ports.h>
54#include <osmocom/vty/command.h>
55#include <osmocom/vty/stats.h>
Neels Hofmeyr515e3412018-02-17 14:10:41 +010056#include <osmocom/vty/misc.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020057
58#include "../../bscconfig.h"
59
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020060#define _GNU_SOURCE
61#include <getopt.h>
62
Philipp Maier87bd9be2017-08-22 16:35:41 +020063/* FIXME: Make use of the rtp proxy code */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020064
65static struct mgcp_config *cfg;
66static struct mgcp_trunk_config *reset_trunk;
67static int reset_endpoints = 0;
68static int daemonize = 0;
69
Harald Welte839fc952017-11-17 20:52:44 +010070const char *osmomgw_copyright =
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020071 "Copyright (C) 2009-2010 Holger Freyther and On-Waves\r\n"
Philipp Maier87bd9be2017-08-22 16:35:41 +020072 "Copyright (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
Harald Welte839fc952017-11-17 20:52:44 +010073 "Contributions by Pablo Neira Ayuso, Jacob Erlbeck, Neels Hofmeyr\r\n"
74 "Philipp Maier\r\n\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020075 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
76 "This is free software: you are free to change and redistribute it.\r\n"
77 "There is NO WARRANTY, to the extent permitted by law.\r\n";
78
Harald Welted164b052017-11-17 15:10:52 +010079static char *config_file = "osmo-mgw.cfg";
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020080
81/* used by msgb and mgcp */
82void *tall_bsc_ctx = NULL;
83
84static void print_help()
85{
86 printf("Some useful help...\n");
87 printf(" -h --help is printing this text.\n");
88 printf(" -c --config-file filename The config file to use.\n");
89 printf(" -s --disable-color\n");
90 printf(" -D --daemonize Fork the process into a background daemon\n");
91 printf(" -V --version Print the version number\n");
92}
93
94static void handle_options(int argc, char **argv)
95{
96 while (1) {
97 int option_index = 0, c;
98 static struct option long_options[] = {
99 {"help", 0, 0, 'h'},
100 {"config-file", 1, 0, 'c'},
101 {"daemonize", 0, 0, 'D'},
102 {"version", 0, 0, 'V'},
103 {"disable-color", 0, 0, 's'},
104 {0, 0, 0, 0},
105 };
106
Neels Hofmeyrcc392182018-11-25 22:33:32 +0100107 c = getopt_long(argc, argv, "hc:sVD", long_options, &option_index);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200108
109 if (c == -1)
110 break;
111
112 switch(c) {
113 case 'h':
114 print_help();
115 exit(0);
116 break;
117 case 'c':
118 config_file = talloc_strdup(tall_bsc_ctx, optarg);
119 break;
120 case 's':
121 log_set_use_color(osmo_stderr_target, 0);
122 break;
123 case 'V':
124 print_version(1);
125 exit(0);
126 break;
127 case 'D':
128 daemonize = 1;
129 break;
130 default:
131 /* ignore */
132 break;
133 };
134 }
135}
136
Philipp Maier87bd9be2017-08-22 16:35:41 +0200137/* Callback function to be called when the RSIP ("Reset in Progress") mgcp
138 * command is received */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200139static int mgcp_rsip_cb(struct mgcp_trunk_config *tcfg)
140{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200141 /* Set flag so that, when read_call_agent() is called next time
142 * the reset can progress */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200143 reset_endpoints = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200144
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200145 reset_trunk = tcfg;
146
147 return 0;
148}
149
150static int read_call_agent(struct osmo_fd *fd, unsigned int what)
151{
152 struct sockaddr_in addr;
153 socklen_t slen = sizeof(addr);
154 struct msgb *msg;
155 struct msgb *resp;
156 int i;
157
158 msg = (struct msgb *) fd->data;
159
160 /* read one less so we can use it as a \0 */
161 int rc = recvfrom(cfg->gw_fd.bfd.fd, msg->data, msg->data_len - 1, 0,
162 (struct sockaddr *) &addr, &slen);
163 if (rc < 0) {
164 perror("Gateway failed to read");
165 return -1;
166 } else if (slen > sizeof(addr)) {
167 fprintf(stderr, "Gateway received message from outerspace: %zu %zu\n",
168 (size_t) slen, sizeof(addr));
169 return -1;
170 }
171
172 /* handle message now */
173 msg->l2h = msgb_put(msg, rc);
174 resp = mgcp_handle_message(cfg, msg);
175 msgb_reset(msg);
176
177 if (resp) {
178 sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
179 msgb_free(resp);
180 }
181
Philipp Maier87bd9be2017-08-22 16:35:41 +0200182 /* reset endpoints */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200183 if (reset_endpoints) {
184 LOGP(DLMGCP, LOGL_NOTICE,
185 "Asked to reset endpoints: %d/%d\n",
186 reset_trunk->trunk_nr, reset_trunk->trunk_type);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200187
188 /* reset flag */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200189 reset_endpoints = 0;
190
Philipp Maier87bd9be2017-08-22 16:35:41 +0200191 /* Walk over all endpoints and trigger a release, this will release all
192 * endpoints, possible open connections are forcefully dropped */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200193 for (i = 1; i < reset_trunk->number_endpoints; ++i)
Philipp Maier1355d7e2018-02-01 14:30:06 +0100194 mgcp_endp_release(&reset_trunk->endpoints[i]);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200195 }
196
197 return 0;
198}
199
200int mgcp_vty_is_config_node(struct vty *vty, int node)
201{
Harald Welte9bf7c532017-11-17 14:14:31 +0100202 switch (node) {
203 case CONFIG_NODE:
204 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200205
Harald Welte9bf7c532017-11-17 14:14:31 +0100206 default:
207 return 1;
208 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200209}
210
211int mgcp_vty_go_parent(struct vty *vty)
212{
Harald Welte9bf7c532017-11-17 14:14:31 +0100213 switch (vty->node) {
214 case TRUNK_NODE:
215 vty->node = MGCP_NODE;
216 vty->index = NULL;
217 break;
218 case MGCP_NODE:
219 default:
220 if (mgcp_vty_is_config_node(vty, vty->node))
221 vty->node = CONFIG_NODE;
222 else
223 vty->node = ENABLE_NODE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200224
Harald Welte9bf7c532017-11-17 14:14:31 +0100225 vty->index = NULL;
226 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200227
Harald Welte9bf7c532017-11-17 14:14:31 +0100228 return vty->node;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200229}
230
231
232static struct vty_app_info vty_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200233 .name = "OsmoMGW",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200234 .version = PACKAGE_VERSION,
235 .go_parent_cb = mgcp_vty_go_parent,
236 .is_config_node = mgcp_vty_is_config_node,
237};
238
239static const struct log_info_cat log_categories[] = {
240 /* DLMGCP is provided by the MGCP library */
Philipp Maierc3413882017-10-27 12:26:54 +0200241 [DRTP] = {
242 .name = "DRTP",
243 .description = "RTP stream handling",
244 .color = "\033[1;30m",
245 .enabled = 1,.loglevel = LOGL_NOTICE,
246 },
Neels Hofmeyr306dc092018-09-30 05:01:20 +0200247 [DIUUP] = {
248 .name = "DIUUP",
249 .description = "IuUP within RTP stream handling",
250 .color = "\033[1;31m",
251 .enabled = 1,.loglevel = LOGL_NOTICE,
252 },
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200253};
254
255const struct log_info log_info = {
Harald Welte9bf7c532017-11-17 14:14:31 +0100256 .cat = log_categories,
257 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200258};
259
260int main(int argc, char **argv)
261{
Harald Welte8890dfa2017-11-17 15:09:30 +0100262 unsigned int flags;
263 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200264
265 tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent");
Neels Hofmeyr515e3412018-02-17 14:10:41 +0100266 vty_info.tall_ctx = tall_bsc_ctx;
267
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200268 msgb_talloc_ctx_init(tall_bsc_ctx, 0);
269
270 osmo_init_ignore_signals();
Neels Hofmeyr60f8e312018-03-30 23:01:07 +0200271 osmo_init_logging2(tall_bsc_ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200272
273 cfg = mgcp_config_alloc();
274 if (!cfg)
275 return -1;
276
Harald Welte839fc952017-11-17 20:52:44 +0100277 vty_info.copyright = osmomgw_copyright;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200278 vty_init(&vty_info);
Pau Espin Pedrolf54eb962019-08-05 16:05:14 +0200279 logging_vty_add_cmds();
Neels Hofmeyr515e3412018-02-17 14:10:41 +0100280 osmo_talloc_vty_add_cmds();
Pau Espin Pedrolf54eb962019-08-05 16:05:14 +0200281 osmo_stats_vty_add_cmds();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200282 mgcp_vty_init();
283
284 handle_options(argc, argv);
285
286 rate_ctr_init(tall_bsc_ctx);
287 osmo_stats_init(tall_bsc_ctx);
288
289 rc = mgcp_parse_config(config_file, cfg, MGCP_BSC);
290 if (rc < 0)
291 return rc;
292
293 /* start telnet after reading config for vty_get_bind_addr() */
294 rc = telnet_init_dynif(tall_bsc_ctx, NULL,
Philipp Maier9a3543a2017-11-14 15:23:40 +0100295 vty_get_bind_addr(), OSMO_VTY_PORT_MGW);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200296 if (rc < 0)
297 return rc;
298
Philipp Maier87bd9be2017-08-22 16:35:41 +0200299 /* Set the reset callback function. This functions is called when the
300 * mgcp-command "RSIP" (Reset in Progress) is received */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200301 cfg->reset_cb = mgcp_rsip_cb;
302
Harald Welte9bf7c532017-11-17 14:14:31 +0100303 /* we need to bind a socket */
Harald Welte8890dfa2017-11-17 15:09:30 +0100304 flags = OSMO_SOCK_F_BIND;
305 if (cfg->call_agent_addr)
306 flags |= OSMO_SOCK_F_CONNECT;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200307
Harald Welte8890dfa2017-11-17 15:09:30 +0100308 rc = osmo_sock_init2_ofd(&cfg->gw_fd.bfd, AF_INET, SOCK_DGRAM, IPPROTO_UDP,
309 cfg->source_addr, cfg->source_port,
310 cfg->call_agent_addr, cfg->call_agent_addr ? 2727 : 0, flags);
311 if (rc < 0) {
312 perror("Gateway failed to bind");
313 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200314 }
315
Harald Welte8890dfa2017-11-17 15:09:30 +0100316 cfg->gw_fd.bfd.cb = read_call_agent;
317 cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
318 if (!cfg->gw_fd.bfd.data) {
319 fprintf(stderr, "Gateway memory error.\n");
320 return -1;
321 }
322
Philipp Maiereb0bde02018-01-18 16:27:29 +0100323 LOGP(DLMGCP, LOGL_NOTICE, "Configured for MGCP, listen on %s:%u\n",
324 cfg->source_addr, cfg->source_port);
Harald Welte8890dfa2017-11-17 15:09:30 +0100325
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200326 /* initialisation */
327 srand(time(NULL));
328
329 if (daemonize) {
330 rc = osmo_daemonize();
331 if (rc < 0) {
332 perror("Error during daemonize");
333 exit(1);
334 }
335 }
336
337 /* main loop */
338 while (1) {
339 osmo_select_main(0);
340 }
341
342
343 return 0;
344}