blob: 6dd316ace8b33f73f45f64618d69a4c7afe0d1e6 [file] [log] [blame]
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +02001/* GTP Hub main program */
2
3/* (C) 2015 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved
5 *
6 * Author: Neels Hofmeyr
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <unistd.h>
23#include <signal.h>
24#include <string.h>
25#include <errno.h>
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +010026#include <inttypes.h>
27#include <sys/stat.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020028
29#define _GNU_SOURCE
30#include <getopt.h>
31
32#include <osmocom/core/signal.h>
33#include <osmocom/core/application.h>
34#include <osmocom/core/logging.h>
35#include <osmocom/core/utils.h>
36#include <osmocom/core/rate_ctr.h>
37
38#include <osmocom/vty/logging.h>
39#include <osmocom/vty/telnet_interface.h>
40
41#include <openbsc/debug.h>
42#include <openbsc/gtphub.h>
43#include <openbsc/vty.h>
44
45#include "../../bscconfig.h"
46
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020047#ifndef OSMO_VTY_PORT_GTPHUB
48/* should come from libosmocore */
49#define OSMO_VTY_PORT_GTPHUB 4253
50#endif
51
52extern void *osmo_gtphub_ctx;
53
54
55const char *gtphub_copyright =
56 "Copyright (C) 2015 sysmocom s.f.m.c GmbH <info@sysmocom.de>\r\n"
57 "License AGPLv3+: GNU AGPL version 2 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
58 "This is free software: you are free to change and redistribute it.\r\n"
59 "There is NO WARRANTY, to the extent permitted by law.\r\n";
60
61static struct log_info_cat gtphub_categories[] = {
62 [DGTPHUB] = {
63 .name = "DGTPHUB",
64 .description = "GTP Hub",
65 .color = "\033[1;33m",
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010066 .enabled = 1,
67 .loglevel = LOGL_NOTICE,
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020068 },
69};
70
71int gtphub_log_filter_fn(const struct log_context *ctx,
72 struct log_target *tar)
73{
74 return 0;
75}
76
77static const struct log_info gtphub_log_info = {
78 .filter_fn = gtphub_log_filter_fn,
79 .cat = gtphub_categories,
80 .num_cat = ARRAY_SIZE(gtphub_categories),
81};
82
83void log_cfg(struct gtphub_cfg *cfg)
84{
85 struct gtphub_cfg_addr *a;
86 a = &cfg->to_sgsns[GTPH_PLANE_CTRL].bind;
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010087 LOGP(DGTPHUB, LOGL_NOTICE,
88 "to-SGSNs bind, Control: %s port %d\n",
89 a->addr_str, a->port);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020090 a = &cfg->to_sgsns[GTPH_PLANE_USER].bind;
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010091 LOGP(DGTPHUB, LOGL_NOTICE,
92 "to-SGSNs bind, User: %s port %d\n",
93 a->addr_str, a->port);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020094 a = &cfg->to_ggsns[GTPH_PLANE_CTRL].bind;
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010095 LOGP(DGTPHUB, LOGL_NOTICE,
96 "to-GGSNs bind, Control: %s port %d\n",
97 a->addr_str, a->port);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020098 a = &cfg->to_ggsns[GTPH_PLANE_USER].bind;
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010099 LOGP(DGTPHUB, LOGL_NOTICE,
100 "to-GGSNs bind, User: %s port %d\n",
101 a->addr_str, a->port);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200102}
103
104static void signal_handler(int signal)
105{
106 fprintf(stdout, "signal %u received\n", signal);
107
108 switch (signal) {
109 case SIGINT:
110 osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
111 sleep(1);
112 exit(0);
113 break;
114 case SIGABRT:
115 /* in case of abort, we want to obtain a talloc report
116 * and then return to the caller, who will abort the process */
117 case SIGUSR1:
118 case SIGUSR2:
119 talloc_report_full(osmo_gtphub_ctx, stderr);
120 break;
121 default:
122 break;
123 }
124}
125
126extern int bsc_vty_go_parent(struct vty *vty);
127
128static struct vty_app_info vty_info = {
129 .name = "OsmoGTPhub",
130 .version = PACKAGE_VERSION,
131 .go_parent_cb = bsc_vty_go_parent,
132 .is_config_node = bsc_vty_is_config_node,
133};
134
135struct cmdline_cfg {
136 const char *config_file;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100137 const char *restart_counter_file;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200138 int daemonize;
139};
140
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100141static uint8_t next_restart_count(const char *path)
142{
143 int umask_was = umask(022);
144
145 uint8_t counter = 0;
146
147 FILE *f = fopen(path, "r");
148 if (f) {
149 int rc = fscanf(f, "%hhu", &counter);
150
151 if (rc != 1)
152 goto failed_to_read;
153
154 char c;
155 while (fread(&c, 1, 1, f) > 0) {
156 switch (c) {
157 case ' ':
158 case '\t':
159 case '\n':
160 case '\r':
161 break;
162 default:
163 goto failed_to_read;
164 }
165 }
166 fclose(f);
167 }
168
169 counter ++;
170
171 f = fopen(path, "w");
172 if (!f)
173 goto failed_to_write;
174 if (fprintf(f, "%" PRIu8 "\n", counter) < 2)
175 goto failed_to_write;
176 if (fclose(f))
177 goto failed_to_write;
178
179 umask(umask_was);
180
181 LOGP(DGTPHUB, LOGL_NOTICE, "Restarted with counter %hhu\n", counter);
182 return counter;
183
184failed_to_read:
185 fclose(f);
186 umask(umask_was);
187 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be parsed:"
188 " %s\n", path);
189 exit(1);
190
191failed_to_write:
192 if (f)
193 fclose(f);
194 umask(umask_was);
195 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be written:"
196 " %s\n", path);
197 exit(1);
198}
199
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200200static void print_help(struct cmdline_cfg *ccfg)
201{
202 printf("gtphub commandline options\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100203 printf(" -h,--help This text.\n");
204 printf(" -D,--daemonize Fork the process into a background daemon.\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200205 printf(" -d,--debug <cat> Enable Debugging for this category.\n");
206 printf(" Pass '-d list' to get a category listing.\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100207 printf(" -s,--disable-color\n");
208 printf(" -c,--config-file <path> The config file to use [%s].\n",
209 ccfg->config_file);
210 printf(" -e,--log-level <nr> Set a global log level.\n");
211 printf(" -r,--restart-file <path> File for counting restarts [%s].\n",
212 ccfg->restart_counter_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200213}
214
215static void list_categories(void)
216{
217 printf("Avaliable debug categories:\n");
218 int i;
219 for (i = 0; i < gtphub_log_info.num_cat; ++i) {
220 if (!gtphub_log_info.cat[i].name)
221 continue;
222
223 printf("%s\n", gtphub_log_info.cat[i].name);
224 }
225}
226
227static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
228{
229 while (1) {
230 int option_index = 0, c;
231 static struct option long_options[] = {
232 {"help", 0, 0, 'h'},
233 {"debug", 1, 0, 'd'},
234 {"daemonize", 0, 0, 'D'},
235 {"config-file", 1, 0, 'c'},
236 {"disable-color", 0, 0, 's'},
237 {"timestamp", 0, 0, 'T'},
238 {"log-level", 1, 0, 'e'},
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100239 {"restart-file", 1, 0, 'r'},
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200240 {NULL, 0, 0, 0}
241 };
242
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100243 c = getopt_long(argc, argv, "hd:Dc:sTe:r:",
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200244 long_options, &option_index);
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100245 if (c == -1) {
246 if (optind < argc) {
247 LOGP(DGTPHUB, LOGL_FATAL,
248 "Excess commandline arguments ('%s').\n",
249 argv[optind]);
250 exit(2);
251 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200252 break;
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100253 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200254
255 switch (c) {
256 case 'h':
257 //print_usage();
258 print_help(ccfg);
259 exit(0);
260 case 's':
261 log_set_use_color(osmo_stderr_target, 0);
262 break;
263 case 'd':
264 if (strcmp("list", optarg) == 0) {
265 list_categories();
266 exit(0);
267 } else
268 log_parse_category_mask(osmo_stderr_target, optarg);
269 break;
270 case 'D':
271 ccfg->daemonize = 1;
272 break;
273 case 'c':
274 ccfg->config_file = optarg;
275 break;
276 case 'T':
277 log_set_print_timestamp(osmo_stderr_target, 1);
278 break;
279 case 'e':
280 log_set_log_level(osmo_stderr_target, atoi(optarg));
281 break;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100282 case 'r':
283 ccfg->restart_counter_file = optarg;
284 break;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200285 default:
286 /* ignore */
287 break;
288 }
289 }
290}
291
292int main(int argc, char **argv)
293{
294 int rc;
295
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100296 struct cmdline_cfg _ccfg;
297 struct cmdline_cfg *ccfg = &_ccfg;
298 memset(ccfg, '\0', sizeof(*ccfg));
299 ccfg->config_file = "./gtphub.conf";
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100300 ccfg->restart_counter_file = "./gtphub_restart_count";
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100301
302 struct gtphub_cfg _cfg;
303 struct gtphub_cfg *cfg = &_cfg;
304 memset(cfg, '\0', sizeof(*cfg));
305
306 struct gtphub _hub;
307 struct gtphub *hub = &_hub;
308
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200309 osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
310
311 signal(SIGINT, &signal_handler);
312 signal(SIGABRT, &signal_handler);
313 signal(SIGUSR1, &signal_handler);
314 signal(SIGUSR2, &signal_handler);
315 osmo_init_ignore_signals();
316
317 osmo_init_logging(&gtphub_log_info);
318
319 vty_info.copyright = gtphub_copyright;
320 vty_init(&vty_info);
321 logging_vty_add_cmds(&gtphub_log_info);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100322 gtphub_vty_init(hub, cfg);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200323
324 rate_ctr_init(osmo_gtphub_ctx);
325 rc = telnet_init(osmo_gtphub_ctx, 0, OSMO_VTY_PORT_GTPHUB);
326 if (rc < 0)
327 exit(1);
328
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200329 handle_options(ccfg, argc, argv);
330
331 rc = gtphub_cfg_read(cfg, ccfg->config_file);
332 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100333 LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n",
334 ccfg->config_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200335 exit(2);
336 }
337
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100338 if (gtphub_start(hub, cfg,
339 next_restart_count(ccfg->restart_counter_file))
340 != 0)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200341 return -1;
342
343 log_cfg(cfg);
344
345 if (ccfg->daemonize) {
346 rc = osmo_daemonize();
347 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100348 LOGP(DGTPHUB, LOGL_FATAL, "Error during daemonize");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200349 exit(1);
350 }
351 }
352
353 while (1) {
354 rc = osmo_select_main(0);
355 if (rc < 0)
356 exit(3);
357 }
358
359 /* not reached */
360 exit(0);
361}