blob: 333375d2813b51cc3c8a80100e341b04fad90ce0 [file] [log] [blame]
Harald Weltedf7a3062016-10-19 10:47:17 +02001#include <signal.h>
Harald Welte4dc14a72016-10-19 10:53:47 +02002#include <getopt.h>
Harald Welte2c5c0792019-12-04 11:35:14 +01003#include <errno.h>
Harald Weltedf7a3062016-10-19 10:47:17 +02004
Harald Welte39cfbf42016-07-28 09:04:11 +02005#include <osmocom/core/signal.h>
6#include <osmocom/core/logging.h>
7#include <osmocom/core/application.h>
8#include <osmocom/vty/vty.h>
9#include <osmocom/vty/telnet_interface.h>
Harald Welteb7e40232016-07-29 14:26:50 +020010#include <osmocom/vty/logging.h>
Harald Welte39cfbf42016-07-28 09:04:11 +020011
12#include <osmocom/abis/abis.h>
13#include <osmocom/abis/e1_input.h>
14
15#include "storage.h"
16#include "recorder.h"
17
Harald Welte06e31982019-12-03 22:06:17 +010018#include "config.h"
19
Harald Welte39cfbf42016-07-28 09:04:11 +020020static enum osmo_e1cap_capture_mode ts2cap_mode(struct e1inp_ts *ts)
21{
22 switch (ts->type) {
23 case E1INP_TS_TYPE_RAW:
24 return OSMO_E1CAP_MODE_RAW;
Harald Welte13351132016-10-17 22:13:36 +020025 case E1INP_TS_TYPE_HDLC:
Harald Welte39cfbf42016-07-28 09:04:11 +020026 return OSMO_E1CAP_MODE_HDLC;
27 case E1INP_TS_TYPE_TRAU:
28 return OSMO_E1CAP_MODE_TRAU;
29 default:
30 OSMO_ASSERT(0);
31 }
32}
33
Harald Welte84869382019-11-06 16:44:04 +010034static int sig_inp_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
35{
36 struct input_signal_data *isd = signal_data;
37 struct e1_recorder_line *rline;
38
39 OSMO_ASSERT(subsys == SS_L_INPUT);
40 OSMO_ASSERT(isd->line && isd->line->num < ARRAY_SIZE(g_recorder.line));
41
42 switch (signal) {
43 case S_L_INP_LINE_ALARM:
44 LOGP(DMAIN, LOGL_NOTICE, "Line %u: ALARM\n", isd->line->num);
45 rline = &g_recorder.line[isd->line->num];
46 rline->has_alarm = true;
47 break;
48 case S_L_INP_LINE_NOALARM:
49 LOGP(DMAIN, LOGL_NOTICE, "Line %u: NOALARM\n", isd->line->num);
50 rline = &g_recorder.line[isd->line->num];
51 rline->has_alarm = false;
52 break;
53 }
54 return 0;
55}
56
Harald Welte39cfbf42016-07-28 09:04:11 +020057/* receive a raw message frome the E1 timeslot */
58void e1ts_raw_recv(struct e1inp_ts *ts, struct msgb *msg)
59{
Harald Welte0e91aa12016-07-28 21:03:40 +020060 struct e1_recorder_line *rline = &g_recorder.line[ts->line->num];
Harald Welte39cfbf42016-07-28 09:04:11 +020061 enum osmo_e1cap_capture_mode cap_mode = ts2cap_mode(ts);
Harald Welte2ac78492016-10-19 10:47:41 +020062 int rc;
Harald Welte39cfbf42016-07-28 09:04:11 +020063
Harald Welte84869382019-11-06 16:44:04 +010064 if (rline->has_alarm) {
65 DEBUGP(DMAIN, "Skipping storage as line %u is in ALARM\n", ts->line->num);
66 return;
67 }
68
Harald Welte39cfbf42016-07-28 09:04:11 +020069 /* FIXME: special processing of TFP and PGSL */
70
Harald Welte2ac78492016-10-19 10:47:41 +020071 rc = e1frame_store(ts, msg, cap_mode);
72 if (rc < 0) {
73 LOGP(DMAIN, LOGL_FATAL, "Error writing E1/T1 frame to disk\n");
74 exit(1);
75 }
Harald Welte39cfbf42016-07-28 09:04:11 +020076
Harald Welte0e91aa12016-07-28 21:03:40 +020077 if (rline->mirror.enabled) {
Harald Welteb7e40232016-07-29 14:26:50 +020078 struct e1inp_line *other_line =
79 e1inp_line_find(rline->mirror.line_nr);
80 struct e1inp_ts *other_ts;
81 other_ts = &other_line->ts[ts->num-1];
Harald Welte4a92d0b2016-10-18 21:36:01 +020082 if (!other_ts) {
83 msgb_free(msg);
Harald Welteb7e40232016-07-29 14:26:50 +020084 return;
Harald Welte4a92d0b2016-10-18 21:36:01 +020085 }
Harald Welte39cfbf42016-07-28 09:04:11 +020086 /* forward data to destination line */
Harald Welteb7e40232016-07-29 14:26:50 +020087 OSMO_ASSERT(other_ts->type == ts->type);
88 msgb_enqueue(&other_ts->raw.tx_queue, msg);
Harald Welte4a92d0b2016-10-18 21:36:01 +020089 } else
90 msgb_free(msg);
Harald Welte39cfbf42016-07-28 09:04:11 +020091}
92
93static int inp_sig_cb(unsigned int subsys, unsigned int signal,
94 void *handler_data, void *signal_data)
95{
96 OSMO_ASSERT(subsys == SS_L_INPUT);
97
98 /* FIXME */
99
100 return 0;
101}
102
Harald Welte39cfbf42016-07-28 09:04:11 +0200103static const struct log_info_cat recorder_categories[] = {
104 [DMAIN] = {
105 .name = "MAIN",
Harald Welteb7e40232016-07-29 14:26:50 +0200106 .description = "Osmocom E1 Recorder",
Harald Welte39cfbf42016-07-28 09:04:11 +0200107 .enabled = 1, .loglevel = LOGL_DEBUG,
108 },
109};
110static struct log_info info = {
111 .cat = recorder_categories,
112 .num_cat = ARRAY_SIZE(recorder_categories),
113};
114
115struct vty_app_info vty_info = {
116 .name = "osmo-e1-recorder",
Harald Welte06e31982019-12-03 22:06:17 +0100117 .version = PACKAGE_VERSION,
118 .copyright = "(C) 2016-2019 by Harald Welte <laforge@gnumonks.org>\n",
Harald Welte39cfbf42016-07-28 09:04:11 +0200119};
120
121static void *rec_tall_ctx;
122struct e1_recorder g_recorder;
Harald Welte4dc14a72016-10-19 10:53:47 +0200123static char *g_config_file = "osmo-e1-recorder.cfg";
Harald Welte39cfbf42016-07-28 09:04:11 +0200124
Harald Weltedf7a3062016-10-19 10:47:17 +0200125static void signal_handler(int signo)
126{
127 switch (signo) {
128 case SIGHUP:
129 storage_close();
130 break;
131 case SIGUSR1:
132 talloc_report(rec_tall_ctx, stderr);
133 break;
134 }
135}
136
Harald Welte06e31982019-12-03 22:06:17 +0100137static void print_help(void)
138{
139 printf( " -h --help This help\n"
140 " -V --version Print version of the program\n"
141 " -c --config FILE Specify configuration file\n"
142 );
143}
144
Harald Welte4dc14a72016-10-19 10:53:47 +0200145static void handle_options(int argc, char **argv)
146{
147 while (1) {
148 int option_index = 0, c;
149 static const struct option long_options[] = {
150 { "config-file", 1, 0, 'c' },
Harald Welte06e31982019-12-03 22:06:17 +0100151 { "help", 0, 0, 'h' },
152 { "version", 0, 0, 'V' },
Harald Welte4dc14a72016-10-19 10:53:47 +0200153 { 0, 0, 0, 0 }
154 };
155
Harald Welte06e31982019-12-03 22:06:17 +0100156 c = getopt_long(argc, argv, "c:hV",
Harald Welte4dc14a72016-10-19 10:53:47 +0200157 long_options, &option_index);
158 if (c == -1)
159 break;
160
161 switch (c) {
162 case 'c':
163 g_config_file = optarg;
164 break;
Harald Welte06e31982019-12-03 22:06:17 +0100165 case 'h':
166 print_help();
167 exit(0);
168 break;
169 case 'V':
170 print_version(1);
171 exit(0);
172 break;
Harald Welte4dc14a72016-10-19 10:53:47 +0200173 }
174 }
Harald Weltecbf23b62019-12-03 22:14:20 +0100175
176 if (argc > optind) {
177 fprintf(stderr, "Unsupported positional arguments on command line\n");
178 exit(2);
179 }
Harald Welte4dc14a72016-10-19 10:53:47 +0200180}
181
Harald Welte39cfbf42016-07-28 09:04:11 +0200182int main(int argc, char **argv)
183{
184 int rc;
185
186 rec_tall_ctx = talloc_named_const(NULL, 0, "recorder");
187
Harald Welte45e12d32019-12-04 14:14:54 +0100188 osmo_init_logging2(rec_tall_ctx, &info);
Harald Welte39cfbf42016-07-28 09:04:11 +0200189 vty_init(&vty_info);
Harald Welteb7e40232016-07-29 14:26:50 +0200190 logging_vty_add_cmds(&info);
Harald Welte39cfbf42016-07-28 09:04:11 +0200191 osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
192 libosmo_abis_init(rec_tall_ctx);
193 e1inp_vty_init();
194 recorder_vty_init();
195
Harald Weltedf7a3062016-10-19 10:47:17 +0200196 signal(SIGHUP, &signal_handler);
197 signal(SIGUSR1, &signal_handler);
198
Harald Welte4dc14a72016-10-19 10:53:47 +0200199 handle_options(argc, argv);
200
Harald Welte84869382019-11-06 16:44:04 +0100201 osmo_signal_register_handler(SS_L_INPUT, sig_inp_cbfn, NULL);
202
Harald Welte4dc14a72016-10-19 10:53:47 +0200203 rc = vty_read_config_file(g_config_file, NULL);
Harald Welte2c5c0792019-12-04 11:35:14 +0100204 if (rc < 0) {
205 fprintf(stderr, "Cannot parse configuration file '%s': %s\n", g_config_file,
206 strerror(errno));
Harald Welte39cfbf42016-07-28 09:04:11 +0200207 exit(1);
Harald Welte2c5c0792019-12-04 11:35:14 +0100208 }
Harald Welte39cfbf42016-07-28 09:04:11 +0200209
210 /* start telne tafte reading config for vty_get_bind_adr() */
211 telnet_init_dynif(rec_tall_ctx, NULL, vty_get_bind_addr(), 4444);
212
213 while (1) {
214 osmo_select_main(0);
215 };
216}