diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a507fd8..6f9af1f6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,6 +242,7 @@ set(SRCS src/fmt/regex.c src/fmt/str.c src/fmt/str_error.c + src/fmt/text2pcap.c src/fmt/time.c src/fmt/unicode.c diff --git a/include/re_fmt.h b/include/re_fmt.h index af4cd1841..ff694dea5 100644 --- a/include/re_fmt.h +++ b/include/re_fmt.h @@ -179,9 +179,10 @@ static inline bool str_isset(const char *s) /* time */ -int fmt_gmtime(struct re_printf *pf, void *ts); -int fmt_timestamp(struct re_printf *pf, void *ts); -int fmt_human_time(struct re_printf *pf, const uint32_t *seconds); +int fmt_gmtime(struct re_printf *pf, void *ts); +int fmt_timestamp(struct re_printf *pf, void *ts); +int fmt_timestamp_us(struct re_printf *pf, void *arg); +int fmt_human_time(struct re_printf *pf, const uint32_t *seconds); void hexdump(FILE *f, const void *p, size_t len); @@ -202,3 +203,15 @@ void fmt_param_apply(const struct pl *pl, fmt_param_h *ph, void *arg); int utf8_encode(struct re_printf *pf, const char *str); int utf8_decode(struct re_printf *pf, const struct pl *pl); size_t utf8_byteseq(char u[4], unsigned cp); + + +/* text2pcap */ +struct re_text2pcap { + bool in; + const struct mbuf *mb; + const char *id; +}; + +int re_text2pcap(struct re_printf *pf, struct re_text2pcap *pcap); +void re_text2pcap_trace(const char *name, const char *id, bool in, + const struct mbuf *mb); diff --git a/src/fmt/text2pcap.c b/src/fmt/text2pcap.c new file mode 100644 index 000000000..0d8a85f68 --- /dev/null +++ b/src/fmt/text2pcap.c @@ -0,0 +1,52 @@ +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include + +#include +#include +#include +#include +#include + + +int re_text2pcap(struct re_printf *pf, struct re_text2pcap *pcap) +{ + if (!pcap) + return EINVAL; + + uint8_t *buf = mbuf_buf(pcap->mb); + if (!buf) + return EINVAL; + + re_hprintf(pf, "%s %H 000000", pcap->in ? "I" : "O", fmt_timestamp_us, + NULL); + + size_t sz = mbuf_get_left(pcap->mb); + for (size_t i = 0; i < sz; i++) { + re_hprintf(pf, " %02x", buf[i]); + } + + re_hprintf(pf, " %s", pcap->id); + + return 0; +} + + +void re_text2pcap_trace(const char *name, const char *id, bool in, + const struct mbuf *mb) +{ + struct re_text2pcap pcap = {.in = in, .mb = mb, .id = id}; + size_t pcap_buf_sz = (mbuf_get_left(mb) * 3) + 64; + + char *pcap_buf = mem_alloc(pcap_buf_sz, NULL); + if (!pcap_buf) + return; + + re_snprintf(pcap_buf, pcap_buf_sz, "%H", re_text2pcap, &pcap); + + re_trace_event("pcap", name, 'I', NULL, RE_TRACE_ARG_STRING_COPY, + "pcap", pcap_buf); + + mem_deref(pcap_buf); +} diff --git a/src/fmt/time.c b/src/fmt/time.c index a0001fd89..76410c438 100644 --- a/src/fmt/time.c +++ b/src/fmt/time.c @@ -4,6 +4,10 @@ * Copyright (C) 2010 Creytiv.com */ +#ifdef __MINGW32__ +#define _POSIX_C_SOURCE 200809L +#endif + #include #ifdef WIN32 @@ -129,3 +133,39 @@ int fmt_timestamp(struct re_printf *pf, void *arg) return re_hprintf(pf, "%02u:%02u:%02u.%03llu", h, m, s, ms); } + + +/** + * Print local time stamp including microseconds relative to user's timezone + * + * @param pf Print function for output + * @param arg Not used + * + * @return 0 if success, otherwise errorcode + */ +int fmt_timestamp_us(struct re_printf *pf, void *arg) +{ + int h, m, s; + uint64_t us; + struct timespec tspec; + struct tm tm; + +#if defined(WIN32) && !defined(__MINGW32__) + timespec_get(&tspec, TIME_UTC); + int err = localtime_s(&tm, &tspec.tv_sec); + if (err) + return err; +#else + (void)clock_gettime(CLOCK_REALTIME, &tspec); + if (!localtime_r(&tspec.tv_sec, &tm)) + return EINVAL; +#endif + + h = tm.tm_hour; + m = tm.tm_min; + s = tm.tm_sec; + us = tspec.tv_nsec / 1000; + (void)arg; + + return re_hprintf(pf, "%02u:%02u:%02u.%06llu", h, m, s, us); +} diff --git a/src/rtp/rtp.c b/src/rtp/rtp.c index 76d73cf5f..e889f86c8 100644 --- a/src/rtp/rtp.c +++ b/src/rtp/rtp.c @@ -17,7 +17,6 @@ #include #include "rtcp.h" - #define DEBUG_MODULE "rtp" #define DEBUG_LEVEL 5 #include @@ -167,6 +166,10 @@ static void rtcp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg) struct rtp_sock *rs = arg; struct rtcp_msg *msg; +#ifdef RE_RTP_PCAP + re_text2pcap_trace("rtcp_recv", "RTCP", true, mb); +#endif + while (0 == rtcp_decode(&msg, mb)) { /* handle internally first */ @@ -202,10 +205,15 @@ static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg) } } +#ifdef RE_RTP_PCAP + re_text2pcap_trace("rtp_udp_recv", "RTP", true, mb); +#endif + err = rtp_decode(rs, mb, &hdr); if (err) return; + if (rs->rtcp) rtcp_sess_rx_rtp(rs->rtcp, &hdr, mbuf_get_left(mb), src); @@ -525,6 +533,10 @@ int rtp_send(struct rtp_sock *rs, const struct sa *dst, bool ext, mb->pos = pos; +#ifdef RE_RTP_PCAP + re_text2pcap_trace("rtp_send", "RTP", false, mb); +#endif + return udp_send(rs->sock_rtp, dst, mb); } @@ -569,6 +581,10 @@ int rtp_resend(struct rtp_sock *rs, uint16_t seq, const struct sa *dst, mb->pos = pos; +#ifdef RE_RTP_PCAP + re_text2pcap_trace("rtp_resend", "RTP", false, mb); +#endif + return udp_send(rs->sock_rtp, dst, mb); } @@ -704,6 +720,9 @@ int rtcp_send(struct rtp_sock *rs, struct mbuf *mb) if (!sock || !sa_isset(&rs->rtcp_peer, SA_ALL)) return EINVAL; +#ifdef RE_RTP_PCAP + re_text2pcap_trace("rtcp_send", "RTCP", false, mb); +#endif return udp_send(sock, &rs->rtcp_peer, mb); } diff --git a/src/trace/trace.c b/src/trace/trace.c index 832d0f977..397d48989 100644 --- a/src/trace/trace.c +++ b/src/trace/trace.c @@ -164,7 +164,7 @@ int re_trace_init(const char *json_file) trace.event_buffer_flush = mem_zalloc( TRACE_BUFFER_SIZE * sizeof(struct trace_event), NULL); if (!trace.event_buffer_flush) { - mem_deref(trace.event_buffer); + trace.event_buffer = mem_deref(trace.event_buffer); return ENOMEM; } @@ -191,8 +191,8 @@ int re_trace_init(const char *json_file) out: if (err) { re_atomic_rlx_set(&trace.init, false); - mem_deref(trace.event_buffer); - mem_deref(trace.event_buffer_flush); + trace.event_buffer = mem_deref(trace.event_buffer); + trace.event_buffer_flush = mem_deref(trace.event_buffer_flush); } return err; @@ -245,12 +245,12 @@ int re_trace_close(void) int re_trace_flush(void) { #ifdef RE_TRACE_ENABLED - int i, flush_count; + int flush_count; struct trace_event *event_tmp; struct trace_event *e; - char json_arg[256] = {0}; - char name[128] = {0}; - char id_str[128] = {0}; + char *json_arg; + char name[128] = {0}; + char id_str[128] = {0}; if (!re_atomic_rlx(&trace.init)) return 0; @@ -264,7 +264,21 @@ int re_trace_flush(void) trace.event_count = 0; mtx_unlock(&trace.lock); - for (i = 0; i < flush_count; i++) + size_t json_arg_sz = 4096; + json_arg = mem_zalloc(json_arg_sz, NULL); + if (!json_arg) { + for (int i = 0; i < flush_count; i++) { + e = &trace.event_buffer_flush[i]; + if (e->arg_type == RE_TRACE_ARG_STRING_COPY) + mem_deref((void *)e->arg.a_str); + + if (e->id) + mem_deref(e->id); + } + return ENOMEM; + } + + for (int i = 0; i < flush_count; i++) { e = &trace.event_buffer_flush[i]; @@ -273,17 +287,17 @@ int re_trace_flush(void) json_arg[0] = '\0'; break; case RE_TRACE_ARG_INT: - (void)re_snprintf(json_arg, sizeof(json_arg), + (void)re_snprintf(json_arg, json_arg_sz, ", \"args\":{\"%s\":%i}", e->arg_name, e->arg.a_int); break; case RE_TRACE_ARG_STRING_CONST: - (void)re_snprintf(json_arg, sizeof(json_arg), + (void)re_snprintf(json_arg, json_arg_sz, ", \"args\":{\"%s\":\"%s\"}", e->arg_name, e->arg.a_str); break; case RE_TRACE_ARG_STRING_COPY: - (void)re_snprintf(json_arg, sizeof(json_arg), + (void)re_snprintf(json_arg, json_arg_sz, ", \"args\":{\"%s\":\"%s\"}", e->arg_name, e->arg.a_str); @@ -310,6 +324,8 @@ int re_trace_flush(void) trace.new = false; } + mem_deref(json_arg); + (void)fflush(trace.f); return 0; #else diff --git a/test/fmt.c b/test/fmt.c index 7b82deebb..297346c3f 100644 --- a/test/fmt.c +++ b/test/fmt.c @@ -1158,3 +1158,30 @@ int test_fmt_hexdump(void) return 0; } + + +int test_text2pcap(void) +{ + char test[64]; + struct mbuf *mb; + int err = 0; + + mb = mbuf_alloc(2); + if (!mb) + return ENOMEM; + + mbuf_write_u8(mb, 42); + mbuf_write_u8(mb, 23); + + mbuf_set_pos(mb, 0); + + struct re_text2pcap pcap = {.id = "test", .in = true, .mb = mb}; + + int ret = re_snprintf(test, sizeof(test), "%H", re_text2pcap, &pcap); + + TEST_EQUALS(35, ret); + +out: + mem_deref(mb); + return err; +} diff --git a/test/test.c b/test/test.c index 261c1d96f..6bfc024f9 100644 --- a/test/test.c +++ b/test/test.c @@ -214,6 +214,7 @@ static const struct test tests[] = { TEST(test_sys_getenv), TEST(test_tcp), TEST(test_telev), + TEST(test_text2pcap), #ifdef USE_TLS TEST(test_tls), TEST(test_tls_ec), diff --git a/test/test.h b/test/test.h index 68a681e2c..cee4a3401 100644 --- a/test/test.h +++ b/test/test.h @@ -330,6 +330,7 @@ int test_sys_fs_fopen(void); int test_sys_getenv(void); int test_tcp(void); int test_telev(void); +int test_text2pcap(void); int test_thread(void); int test_thread_cnd_timedwait(void); int test_tmr_jiffies(void); diff --git a/test/trace.c b/test/trace.c index be85c828e..6966be3e2 100644 --- a/test/trace.c +++ b/test/trace.c @@ -67,5 +67,7 @@ int test_trace(void) #endif out: + if (err) + re_trace_close(); return err; }