blob: 6790b4c346c06f7caaa339a7261b3d718f11e107 [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{
191 return 0;
192}
193
194int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
195{
196 return 0;
197}
198
199
200int main (int argc, char *argv[])
201{
202 void *ctx = tall_nsdummy_ctx = talloc_named_const(NULL, 0, "osmo-ns-dummy");
203 struct gprs_ns2_inst *nsi;
204 int rc = 0;
205
206 osmo_init_logging2(ctx, &log_info);
207 log_set_use_color(osmo_stderr_target, 0);
208 log_set_print_filename(osmo_stderr_target, 0);
209 log_set_print_filename(osmo_stderr_target, 0);
210 log_set_log_level(osmo_stderr_target, LOGL_INFO);
211 msgb_talloc_ctx_init(ctx, 0);
212 osmo_stats_init(ctx);
213 rate_ctr_init(ctx);
214
215 vty_info.tall_ctx = ctx;
216 vty_init(&vty_info);
217 logging_vty_add_cmds();
218 osmo_stats_vty_add_cmds();
219 osmo_talloc_vty_add_cmds();
220
221 handle_options(argc, argv);
222
223 nsi = gprs_ns2_instantiate(ctx, gprs_ns_prim_cb, NULL);
224 if (!nsi) {
225 LOGP(DLNS, LOGL_ERROR, "Failed to create NS instance\n");
226 exit(1);
227 }
228
229 gprs_ns2_vty2_init(nsi);
230 rc = vty_read_config_file(config_file, NULL);
231 if (rc < 0 && config_given) {
232 fprintf(stderr, "Failed to parse the config file: '%s'\n",
233 config_file);
234 exit(1);
235 }
236 if (rc < 0)
237 fprintf(stderr, "No config file: '%s' Using default config.\n",
238 config_file);
239
240 rc = telnet_init_dynif(ctx, NULL, vty_get_bind_addr(),
241 vty_port);
242 if (rc < 0) {
243 fprintf(stderr, "Error initializing telnet\n");
244 exit(1);
245 }
246
247 signal(SIGINT, sighandler);
248 signal(SIGTERM, sighandler);
249 signal(SIGPIPE, sighandler);
250 signal(SIGABRT, sighandler);
251 signal(SIGUSR1, sighandler);
252 signal(SIGUSR2, sighandler);
253 osmo_init_ignore_signals();
254
255 if (daemonize) {
256 rc = osmo_daemonize();
257 if (rc < 0) {
258 perror("Error during daemonize");
259 exit(1);
260 }
261 }
262
263 while (!quit) {
264 osmo_select_main(0);
265 }
266
267 telnet_exit();
268 gprs_ns2_free(nsi);
269
270 talloc_report_full(tall_nsdummy_ctx, stderr);
271 talloc_free(tall_nsdummy_ctx);
272
273 return 0;
274}