blob: 73a122c3189f7812d46ae0c3088f3a457c0448a8 [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>
Neels Hofmeyr03933a42016-02-23 13:26:02 +010040#include <osmocom/vty/ports.h>
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020041
42#include <openbsc/debug.h>
43#include <openbsc/gtphub.h>
44#include <openbsc/vty.h>
45
46#include "../../bscconfig.h"
47
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020048extern void *osmo_gtphub_ctx;
49
50
51const char *gtphub_copyright =
52 "Copyright (C) 2015 sysmocom s.f.m.c GmbH <info@sysmocom.de>\r\n"
53 "License AGPLv3+: GNU AGPL version 2 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
54 "This is free software: you are free to change and redistribute it.\r\n"
55 "There is NO WARRANTY, to the extent permitted by law.\r\n";
56
57static struct log_info_cat gtphub_categories[] = {
58 [DGTPHUB] = {
59 .name = "DGTPHUB",
60 .description = "GTP Hub",
61 .color = "\033[1;33m",
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +010062 .enabled = 1,
Neels Hofmeyr69da1d42016-02-23 13:28:04 +010063 .loglevel = LOGL_INFO,
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020064 },
65};
66
67int gtphub_log_filter_fn(const struct log_context *ctx,
68 struct log_target *tar)
69{
70 return 0;
71}
72
73static const struct log_info gtphub_log_info = {
74 .filter_fn = gtphub_log_filter_fn,
75 .cat = gtphub_categories,
76 .num_cat = ARRAY_SIZE(gtphub_categories),
77};
78
79void log_cfg(struct gtphub_cfg *cfg)
80{
Neels Hofmeyra9905a52015-11-29 23:49:48 +010081 int side_idx, plane_idx;
82 for_each_side_and_plane(side_idx, plane_idx) {
Neels Hofmeyr08550082015-11-30 12:19:50 +010083 struct gtphub_cfg_addr *a;
Neels Hofmeyra9905a52015-11-29 23:49:48 +010084 a = &cfg->to_gsns[side_idx][plane_idx].bind;
85 LOGP(DGTPHUB, LOGL_NOTICE,
86 "to-%ss bind, %s: %s port %d\n",
87 gtphub_side_idx_names[side_idx],
88 gtphub_plane_idx_names[plane_idx],
89 a->addr_str, a->port);
90 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020091}
92
93static void signal_handler(int signal)
94{
Neels Hofmeyr08550082015-11-30 12:19:50 +010095 fprintf(stdout, "signal %d received\n", signal);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +020096
97 switch (signal) {
98 case SIGINT:
99 osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
100 sleep(1);
101 exit(0);
102 break;
103 case SIGABRT:
104 /* in case of abort, we want to obtain a talloc report
105 * and then return to the caller, who will abort the process */
106 case SIGUSR1:
107 case SIGUSR2:
108 talloc_report_full(osmo_gtphub_ctx, stderr);
109 break;
110 default:
111 break;
112 }
113}
114
115extern int bsc_vty_go_parent(struct vty *vty);
116
117static struct vty_app_info vty_info = {
118 .name = "OsmoGTPhub",
119 .version = PACKAGE_VERSION,
120 .go_parent_cb = bsc_vty_go_parent,
121 .is_config_node = bsc_vty_is_config_node,
122};
123
124struct cmdline_cfg {
125 const char *config_file;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100126 const char *restart_counter_file;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200127 int daemonize;
128};
129
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100130static uint8_t next_restart_count(const char *path)
131{
132 int umask_was = umask(022);
133
134 uint8_t counter = 0;
135
136 FILE *f = fopen(path, "r");
137 if (f) {
138 int rc = fscanf(f, "%hhu", &counter);
139
140 if (rc != 1)
141 goto failed_to_read;
142
143 char c;
144 while (fread(&c, 1, 1, f) > 0) {
145 switch (c) {
146 case ' ':
147 case '\t':
148 case '\n':
149 case '\r':
150 break;
151 default:
152 goto failed_to_read;
153 }
154 }
155 fclose(f);
156 }
157
158 counter ++;
159
160 f = fopen(path, "w");
161 if (!f)
162 goto failed_to_write;
163 if (fprintf(f, "%" PRIu8 "\n", counter) < 2)
164 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100165 if (fclose(f)) {
166 f = NULL;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100167 goto failed_to_write;
Holger Hans Peter Freytherde766612016-01-23 10:28:09 +0100168 }
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100169
170 umask(umask_was);
171
172 LOGP(DGTPHUB, LOGL_NOTICE, "Restarted with counter %hhu\n", counter);
173 return counter;
174
175failed_to_read:
176 fclose(f);
177 umask(umask_was);
178 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be parsed:"
179 " %s\n", path);
180 exit(1);
181
182failed_to_write:
183 if (f)
184 fclose(f);
185 umask(umask_was);
186 LOGP(DGTPHUB, LOGL_FATAL, "Restart counter file cannot be written:"
187 " %s\n", path);
188 exit(1);
189}
190
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200191static void print_help(struct cmdline_cfg *ccfg)
192{
193 printf("gtphub commandline options\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100194 printf(" -h,--help This text.\n");
195 printf(" -D,--daemonize Fork the process into a background daemon.\n");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200196 printf(" -d,--debug <cat> Enable Debugging for this category.\n");
197 printf(" Pass '-d list' to get a category listing.\n");
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100198 printf(" -s,--disable-color\n");
199 printf(" -c,--config-file <path> The config file to use [%s].\n",
200 ccfg->config_file);
201 printf(" -e,--log-level <nr> Set a global log level.\n");
202 printf(" -r,--restart-file <path> File for counting restarts [%s].\n",
203 ccfg->restart_counter_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200204}
205
206static void list_categories(void)
207{
208 printf("Avaliable debug categories:\n");
209 int i;
210 for (i = 0; i < gtphub_log_info.num_cat; ++i) {
211 if (!gtphub_log_info.cat[i].name)
212 continue;
213
214 printf("%s\n", gtphub_log_info.cat[i].name);
215 }
216}
217
218static void handle_options(struct cmdline_cfg *ccfg, int argc, char **argv)
219{
220 while (1) {
221 int option_index = 0, c;
222 static struct option long_options[] = {
223 {"help", 0, 0, 'h'},
224 {"debug", 1, 0, 'd'},
225 {"daemonize", 0, 0, 'D'},
226 {"config-file", 1, 0, 'c'},
227 {"disable-color", 0, 0, 's'},
228 {"timestamp", 0, 0, 'T'},
229 {"log-level", 1, 0, 'e'},
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100230 {"restart-file", 1, 0, 'r'},
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200231 {NULL, 0, 0, 0}
232 };
233
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100234 c = getopt_long(argc, argv, "hd:Dc:sTe:r:",
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200235 long_options, &option_index);
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100236 if (c == -1) {
237 if (optind < argc) {
238 LOGP(DGTPHUB, LOGL_FATAL,
239 "Excess commandline arguments ('%s').\n",
240 argv[optind]);
241 exit(2);
242 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200243 break;
Neels Hofmeyr8d1ffbd2015-11-26 05:20:18 +0100244 }
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200245
246 switch (c) {
247 case 'h':
248 //print_usage();
249 print_help(ccfg);
250 exit(0);
251 case 's':
252 log_set_use_color(osmo_stderr_target, 0);
253 break;
254 case 'd':
255 if (strcmp("list", optarg) == 0) {
256 list_categories();
257 exit(0);
258 } else
259 log_parse_category_mask(osmo_stderr_target, optarg);
260 break;
261 case 'D':
262 ccfg->daemonize = 1;
263 break;
264 case 'c':
265 ccfg->config_file = optarg;
266 break;
267 case 'T':
268 log_set_print_timestamp(osmo_stderr_target, 1);
269 break;
270 case 'e':
271 log_set_log_level(osmo_stderr_target, atoi(optarg));
272 break;
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100273 case 'r':
274 ccfg->restart_counter_file = optarg;
275 break;
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200276 default:
Neels Hofmeyr956d8562015-12-06 16:40:24 +0100277 LOGP(DGTPHUB, LOGL_FATAL, "Invalid command line argument, abort.\n");
278 exit(1);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200279 break;
280 }
281 }
282}
283
284int main(int argc, char **argv)
285{
286 int rc;
287
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100288 struct cmdline_cfg _ccfg;
289 struct cmdline_cfg *ccfg = &_ccfg;
290 memset(ccfg, '\0', sizeof(*ccfg));
291 ccfg->config_file = "./gtphub.conf";
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100292 ccfg->restart_counter_file = "./gtphub_restart_count";
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100293
294 struct gtphub_cfg _cfg;
295 struct gtphub_cfg *cfg = &_cfg;
296 memset(cfg, '\0', sizeof(*cfg));
297
298 struct gtphub _hub;
299 struct gtphub *hub = &_hub;
300
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200301 osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
Neels Hofmeyr4c2d4ab2016-09-16 02:31:17 +0200302 msgb_talloc_ctx_init(osmo_gtphub_ctx, 0);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200303
304 signal(SIGINT, &signal_handler);
305 signal(SIGABRT, &signal_handler);
306 signal(SIGUSR1, &signal_handler);
307 signal(SIGUSR2, &signal_handler);
308 osmo_init_ignore_signals();
309
310 osmo_init_logging(&gtphub_log_info);
311
312 vty_info.copyright = gtphub_copyright;
313 vty_init(&vty_info);
Maxdb0e3802017-01-12 19:35:11 +0100314 logging_vty_add_cmds(NULL);
Neels Hofmeyr4b2cbda2015-11-20 03:16:19 +0100315 gtphub_vty_init(hub, cfg);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200316
317 rate_ctr_init(osmo_gtphub_ctx);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200318
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200319 handle_options(ccfg, argc, argv);
320
321 rc = gtphub_cfg_read(cfg, ccfg->config_file);
322 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100323 LOGP(DGTPHUB, LOGL_FATAL, "Cannot parse config file '%s'\n",
324 ccfg->config_file);
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200325 exit(2);
326 }
327
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100328 /* start telnet after reading config for vty_get_bind_addr() */
Neels Hofmeyrfa0f7152016-02-23 14:09:38 +0100329 rc = telnet_init_dynif(osmo_gtphub_ctx, 0, vty_get_bind_addr(),
330 OSMO_VTY_PORT_GTPHUB);
331 if (rc < 0)
332 exit(1);
333
Neels Hofmeyrba9e9f62015-11-26 22:19:22 +0100334 if (gtphub_start(hub, cfg,
335 next_restart_count(ccfg->restart_counter_file))
336 != 0)
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200337 return -1;
338
339 log_cfg(cfg);
340
341 if (ccfg->daemonize) {
342 rc = osmo_daemonize();
343 if (rc < 0) {
Neels Hofmeyrd9b1d492015-11-18 18:11:09 +0100344 LOGP(DGTPHUB, LOGL_FATAL, "Error during daemonize");
Neels Hofmeyrc8a614d2015-09-24 17:32:30 +0200345 exit(1);
346 }
347 }
348
349 while (1) {
350 rc = osmo_select_main(0);
351 if (rc < 0)
352 exit(3);
353 }
354
355 /* not reached */
356 exit(0);
357}