blob: 58e81529e3e6c526465474959c0014dec0ed0952 [file] [log] [blame]
Alexander Couzensc0d02cc2020-12-14 02:36:53 +01001
2#include <errno.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <getopt.h>
6#include <signal.h>
7
8#include <osmocom/core/select.h>
9#include <osmocom/core/application.h>
10#include <osmocom/core/stats.h>
11
12#include <osmocom/gprs/gprs_ns2.h>
13#include <osmocom/vty/vty.h>
14#include <osmocom/vty/telnet_interface.h>
15#include <osmocom/vty/command.h>
16#include <osmocom/vty/ports.h>
17#include <osmocom/vty/tdef_vty.h>
18#include <osmocom/vty/logging.h>
19#include <osmocom/vty/stats.h>
20#include <osmocom/vty/misc.h>
21
22#include "config.h"
23
24void *tall_nsdummy_ctx = NULL;
25static struct log_info log_info = {};
26static bool quit = false;
27static bool config_given = false;
28static bool daemonize = false;
29static int vty_port = 0;
30static char *config_file = NULL;
31
32static const char vty_copyright[] =
33 "Copyright (C) 2020 by by sysmocom - s.f.m.c. GmbH\r\n"
34 "Author: Alexander Couzens <lynxis@fe80.eu>\r\n"
35 "License GNU GPL version 2 or later\r\n"
36 "This is free software: you are free to change and redistribute it.\r\n"
37 "There is NO WARRANTY, to the extent permitted by law.\r\n";
38
39static struct vty_app_info vty_info = {
40 .name = "OsmoNSdummy",
41 .version = PACKAGE_VERSION,
42 .copyright = vty_copyright,
43};
44
45static void print_help()
46{
47 printf( "Some useful options:\n"
48 " -h --help This text\n"
49 " -c --config-file Specify the filename of the config file\n"
50 " -V --version Print version\n"
51 " -D --daemonize Fork the process into a background daemon\n"
52 " -p --vty-port PORT Set the vty port to listen on.\n"
53 "\nVTY reference generation:\n"
54 " --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
55 " --vty-ref-xml Generate the VTY reference XML output and exit.\n"
56 );
57}
58
59static void handle_long_options(const char *prog_name, const int long_option)
60{
61 static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
62
63 switch (long_option) {
64 case 1:
65 vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
66 if (vty_ref_mode < 0) {
67 fprintf(stderr, "%s: Unknown VTY reference generation "
68 "mode '%s'\n", prog_name, optarg);
69 exit(2);
70 }
71 break;
72 case 2:
73 fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
74 get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
75 get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
76 vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
77 exit(0);
78 default:
79 fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
80 exit(2);
81 }
82}
83
84static void handle_options(int argc, char **argv)
85{
86 while (1) {
87 int option_idx = 0, c;
88 static int long_option = 0;
89 static const struct option long_options[] = {
90 { "help", 0, 0, 'h' },
91 { "config-file", 1, 0, 'c' },
92 { "version", 0, 0, 'V' },
93 { "daemonize", 0, 0, 'D' },
94 { "vty-port", 1, 0, 'p' },
95 { "vty-ref-mode", 1, &long_option, 1 },
96 { "vty-ref-xml", 0, &long_option, 2 },
97 { 0, 0, 0, 0 }
98 };
99
100 c = getopt_long(argc, argv, "hc:p:VD",
101 long_options, &option_idx);
102 if (c == -1)
103 break;
104
105 switch (c) {
106 case 'h':
107 print_help();
108 exit(0);
109 break;
110 case 0:
111 handle_long_options(argv[0], long_option);
112 break;
113 case 'c':
114 if (config_file)
115 free(config_file);
116 config_file = optarg;
117 config_given = true;
118 break;
119 case 'p':
120 vty_port = atoi(optarg);
121 if (vty_port < 0 || vty_port > 65535) {
122 fprintf(stderr, "Invalid port %d given!\n", vty_port);
123 exit(1);
124 }
125 break;
126 case 'V':
127 print_version(1);
128 exit(0);
129 break;
130 case 'D':
131 daemonize = true;
132 break;
133 default:
134 fprintf(stderr, "Unknown option '%c'\n", c);
135 exit(0);
136 break;
137 }
138 }
139
140 if (!config_file)
141 config_file = "osmo-ns-dummy.cfg";
142 if (!vty_port) {
143 fprintf(stderr, "A vty port need to be specified (-p)\n");
144 exit(1);
145 }
146}
147
148void sighandler(int sigset)
149{
150 if (sigset == SIGPIPE)
151 return;
152
153 fprintf(stderr, "Signal %d received.\n", sigset);
154
155 switch (sigset) {
156 case SIGINT:
157 case SIGTERM:
158 /* If another signal is received afterwards, the program
159 * is terminated without finishing shutdown process.
160 */
161 signal(SIGINT, SIG_DFL);
162 signal(SIGTERM, SIG_DFL);
163 signal(SIGPIPE, SIG_DFL);
164 signal(SIGABRT, SIG_DFL);
165 signal(SIGUSR1, SIG_DFL);
166 signal(SIGUSR2, SIG_DFL);
167
168 quit = 1;
169 break;
170 case SIGABRT:
171 /* in case of abort, we want to obtain a talloc report and
172 * then run default SIGABRT handler, who will generate coredump
173 * and abort the process. abort() should do this for us after we
174 * return, but program wouldn't exit if an external SIGABRT is
175 * received.
176 */
177 talloc_report_full(tall_nsdummy_ctx, stderr);
178 signal(SIGABRT, SIG_DFL);
179 raise(SIGABRT);
180 break;
181 case SIGUSR1:
182 case SIGUSR2:
183 talloc_report_full(tall_nsdummy_ctx, stderr);
184 break;
185 }
186}
187
188/* called by the ns layer */
189int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
190{
Alexander Couzensfd96dc52021-01-18 13:43:44 +0100191 if (oph->msg)
192 msgb_free(oph->msg);
193
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100194 return 0;
195}
196
197int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
198{
199 return 0;
200}
201
202
203int main (int argc, char *argv[])
204{
205 void *ctx = tall_nsdummy_ctx = talloc_named_const(NULL, 0, "osmo-ns-dummy");
206 struct gprs_ns2_inst *nsi;
207 int rc = 0;
208
209 osmo_init_logging2(ctx, &log_info);
210 log_set_use_color(osmo_stderr_target, 0);
211 log_set_print_filename(osmo_stderr_target, 0);
212 log_set_print_filename(osmo_stderr_target, 0);
213 log_set_log_level(osmo_stderr_target, LOGL_INFO);
214 msgb_talloc_ctx_init(ctx, 0);
215 osmo_stats_init(ctx);
216 rate_ctr_init(ctx);
217
218 vty_info.tall_ctx = ctx;
219 vty_init(&vty_info);
220 logging_vty_add_cmds();
221 osmo_stats_vty_add_cmds();
222 osmo_talloc_vty_add_cmds();
223
224 handle_options(argc, argv);
225
226 nsi = gprs_ns2_instantiate(ctx, gprs_ns_prim_cb, NULL);
227 if (!nsi) {
228 LOGP(DLNS, LOGL_ERROR, "Failed to create NS instance\n");
229 exit(1);
230 }
231
Alexander Couzens03f88d92021-01-04 19:07:25 +0100232 gprs_ns2_dynamic_create_nse(nsi, true);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100233 gprs_ns2_vty2_init(nsi);
234 rc = vty_read_config_file(config_file, NULL);
235 if (rc < 0 && config_given) {
236 fprintf(stderr, "Failed to parse the config file: '%s'\n",
237 config_file);
238 exit(1);
239 }
240 if (rc < 0)
241 fprintf(stderr, "No config file: '%s' Using default config.\n",
242 config_file);
243
244 rc = telnet_init_dynif(ctx, NULL, vty_get_bind_addr(),
245 vty_port);
246 if (rc < 0) {
247 fprintf(stderr, "Error initializing telnet\n");
248 exit(1);
249 }
250
251 signal(SIGINT, sighandler);
252 signal(SIGTERM, sighandler);
253 signal(SIGPIPE, sighandler);
254 signal(SIGABRT, sighandler);
255 signal(SIGUSR1, sighandler);
256 signal(SIGUSR2, sighandler);
257 osmo_init_ignore_signals();
258
259 if (daemonize) {
260 rc = osmo_daemonize();
261 if (rc < 0) {
262 perror("Error during daemonize");
263 exit(1);
264 }
265 }
266
267 while (!quit) {
268 osmo_select_main(0);
269 }
270
271 telnet_exit();
272 gprs_ns2_free(nsi);
273
274 talloc_report_full(tall_nsdummy_ctx, stderr);
275 talloc_free(tall_nsdummy_ctx);
276
277 return 0;
278}