blob: d0aa47b6f8197f7a2c818bc9e6bdbd3c5dcafd7a [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file logging_gsmtap.c
2 * libosmocore log output encapsulated in GSMTAP.
3 *
4 * Encapsulating the log output inside GSMTAP frames allows us to
5 * observer protocol traces (of Um, Abis, A or any other interface in
6 * the Osmocom world) with synchronous interspersed log messages.
7 */
8/*
9 * (C) 2016 by Harald Welte <laforge@gnumonks.org>
Harald Welteaa00f992016-12-02 15:30:02 +010010 * All Rights Reserved
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 *
26 */
27
28/*! \addtogroup logging
29 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020030 * \file logging_gsmtap.c */
Harald Welteaa00f992016-12-02 15:30:02 +010031
32#include "../config.h"
33
34#include <stdarg.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <string.h>
38#include <stdbool.h>
Harald Welteaa00f992016-12-02 15:30:02 +010039
40#ifdef HAVE_STRINGS_H
41#include <strings.h>
42#endif
43
44#include <osmocom/core/talloc.h>
45#include <osmocom/core/utils.h>
46#include <osmocom/core/gsmtap.h>
47#include <osmocom/core/gsmtap_util.h>
48#include <osmocom/core/logging.h>
49#include <osmocom/core/timer.h>
Harald Welte95871da2017-05-15 12:11:36 +020050#include <osmocom/core/byteswap.h>
Harald Welteaa00f992016-12-02 15:30:02 +010051
52#define GSMTAP_LOG_MAX_SIZE 4096
53
54static void _gsmtap_raw_output(struct log_target *target, int subsys,
55 unsigned int level, const char *file,
56 int line, int cont, const char *format,
57 va_list ap)
58{
59 struct msgb *msg;
60 struct gsmtap_hdr *gh;
61 struct gsmtap_osmocore_log_hdr *golh;
62 const char *subsys_name = log_category_name(subsys);
63 struct timeval tv;
64 int rc;
65
66 /* get timestamp ASAP */
67 osmo_gettimeofday(&tv, NULL);
68
69 msg = msgb_alloc(sizeof(*gh)+sizeof(*golh)+GSMTAP_LOG_MAX_SIZE,
70 "GSMTAP logging");
71
72 /* GSMTAP header */
73 gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
74 memset(gh, 0, sizeof(*gh));
75 gh->version = GSMTAP_VERSION;
76 gh->hdr_len = sizeof(*gh)/4;
77 gh->type = GSMTAP_TYPE_OSMOCORE_LOG;
78
79 /* Logging header */
80 golh = (struct gsmtap_osmocore_log_hdr *) msgb_put(msg, sizeof(*golh));
81 osmo_strlcpy(golh->proc_name, target->tgt_gsmtap.ident,
82 sizeof(golh->proc_name));
83 if (subsys_name)
84 osmo_strlcpy(golh->subsys, subsys_name+1, sizeof(golh->subsys));
85 else
86 golh->subsys[0] = '\0';
87 osmo_strlcpy(golh->src_file.name, file, sizeof(golh->src_file.name));
Harald Welte95871da2017-05-15 12:11:36 +020088 golh->src_file.line_nr = osmo_htonl(line);
Harald Welteaa00f992016-12-02 15:30:02 +010089 golh->level = level;
90 /* we always store the timestamp in the message, irrespective
91 * of hat prrint_[ext_]timestamp say */
Harald Welte95871da2017-05-15 12:11:36 +020092 golh->ts.sec = osmo_htonl(tv.tv_sec);
93 golh->ts.usec = osmo_htonl(tv.tv_usec);
Harald Welteaa00f992016-12-02 15:30:02 +010094
95 rc = vsnprintf((char *) msg->tail, msgb_tailroom(msg), format, ap);
96 if (rc < 0)
97 return;
98 msgb_put(msg, rc);
99
100 gsmtap_sendmsg(target->tgt_gsmtap.gsmtap_inst, msg);
101}
102
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200103/*! Create a new logging target for GSMTAP logging
Harald Welteaa00f992016-12-02 15:30:02 +0100104 * \param[in] ident string identifier
105 * \returns Log target in case of success, NULL in case of error
106 */
107struct log_target *log_target_create_gsmtap(const char *host, uint16_t port,
108 const char *ident,
109 bool ofd_wq_mode,
110 bool add_sink)
111{
112 struct log_target *target;
113 struct gsmtap_inst *gti;
114
115 target = log_target_create();
116 if (!target)
117 return NULL;
118
119 gti = gsmtap_source_init(host, port, ofd_wq_mode);
120 if (!gti) {
121 log_target_destroy(target);
122 return NULL;
123 }
124
125 if (add_sink)
126 gsmtap_source_add_sink(gti);
127
128 target->tgt_gsmtap.gsmtap_inst = gti;
129 target->tgt_gsmtap.ident = talloc_strdup(target, ident);
130 target->tgt_gsmtap.hostname = talloc_strdup(target, host);
131
132 target->type = LOG_TGT_TYPE_GSMTAP;
133 target->raw_output = _gsmtap_raw_output;
134
135 return target;
136}
137
138/* @} */