From 3813821129ddd38312503d55a763ee687634f104 Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 14 Jun 2022 14:17:09 +0300 Subject: [PATCH] Add 'all' recording method --- daemon/main.c | 2 +- daemon/recording.c | 99 +++++++++++++++++++++++++++++++++++++------- daemon/rtpengine.pod | 7 +++- include/recording.h | 5 ++- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/daemon/main.c b/daemon/main.c index e237974d4..e312667bd 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -512,7 +512,7 @@ static void options(int *argc, char ***argv) { { "homer-protocol",0,0,G_OPTION_ARG_STRING, &homerproto, "Transport protocol for Homer (default udp)", "udp|tcp" }, { "homer-id", 0, 0, G_OPTION_ARG_INT, &rtpe_config.homer_id, "'Capture ID' to use within the HEP protocol", "INT" }, { "recording-dir", 0, 0, G_OPTION_ARG_STRING, &rtpe_config.spooldir, "Directory for storing pcap and metadata files", "FILE" }, - { "recording-method",0, 0, G_OPTION_ARG_STRING, &rtpe_config.rec_method, "Strategy for call recording", "pcap|proc" }, + { "recording-method",0, 0, G_OPTION_ARG_STRING, &rtpe_config.rec_method, "Strategy for call recording", "pcap|proc|all" }, { "recording-format",0, 0, G_OPTION_ARG_STRING, &rtpe_config.rec_format, "File format for stored pcap files", "raw|eth" }, #ifdef WITH_IPTABLES_OPTION { "iptables-chain",0,0, G_OPTION_ARG_STRING, &rtpe_config.iptables_chain,"Add explicit firewall rules to this iptables chain","STRING" }, diff --git a/daemon/recording.c b/daemon/recording.c index f95c38c36..e903356f2 100644 --- a/daemon/recording.c +++ b/daemon/recording.c @@ -39,6 +39,14 @@ static int append_meta_chunk(struct recording *recording, const char *buf, unsig const char *label_fmt, ...) __attribute__((format(printf,4,5))); +// all methods +static int create_spool_dir_all(const char *spoolpath); +static void init_all(struct call *call); +static void sdp_after_all(struct recording *recording, GString *str, struct call_monologue *ml, + enum call_opmode opmode); +static void dump_packet_all(struct media_packet *mp, const str *s); +static void finish_all(struct call *call); + // pcap methods static int rec_pcap_create_spool_dir(const char *dirpath); static void rec_pcap_init(struct call *); @@ -68,15 +76,23 @@ static void rec_pcap_eth_header(unsigned char *, struct packet_stream *); #define append_meta_chunk_null(r,f...) append_meta_chunk(r, "", 0, f) -static const struct recording_method methods[] = { +const struct recording_method methods[] = { { .name = "pcap", .kernel_support = 0, .create_spool_dir = rec_pcap_create_spool_dir, .init_struct = rec_pcap_init, + .sdp_before = NULL, .sdp_after = sdp_after_pcap, + .meta_chunk = NULL, + .update_flags = NULL, .dump_packet = dump_packet_pcap, .finish = finish_pcap, + .init_stream_struct = NULL, + .setup_stream = NULL, + .setup_media = NULL, + .setup_monologue = NULL, + .stream_kernel_info = NULL, .response = response_pcap, }, { @@ -95,6 +111,25 @@ static const struct recording_method methods[] = { .setup_media = setup_media_proc, .setup_monologue = setup_monologue_proc, .stream_kernel_info = kernel_info_proc, + .response = NULL, + }, + { + .name = "all", + .kernel_support = 0, + .create_spool_dir = create_spool_dir_all, + .init_struct = init_all, + .sdp_before = sdp_before_proc, + .sdp_after = sdp_after_all, + .meta_chunk = meta_chunk_proc, + .update_flags = update_flags_proc, + .dump_packet = dump_packet_all, + .finish = finish_all, + .init_stream_struct = init_stream_proc, + .setup_stream = setup_stream_proc, + .setup_media = setup_media_proc, + .setup_monologue = setup_monologue_proc, + .stream_kernel_info = kernel_info_proc, + .response = response_pcap, }, }; @@ -425,14 +460,14 @@ static char *meta_setup_file(struct recording *recording) { } char *meta_filepath = file_path_str(recording->meta_prefix, "/tmp/rtpengine-meta-", ".tmp"); - recording->meta_filepath = meta_filepath; + recording->meta_filepath_pcap = meta_filepath; FILE *mfp = fopen(meta_filepath, "w"); // coverity[check_return : FALSE] chmod(meta_filepath, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); if (mfp == NULL) { ilog(LOG_ERROR, "Could not open metadata file: %s%s%s", FMT_M(meta_filepath)); free(meta_filepath); - recording->meta_filepath = NULL; + recording->meta_filepath_pcap = NULL; return NULL; } recording->u.pcap.meta_fp = mfp; @@ -513,10 +548,10 @@ static int rec_pcap_meta_finish_file(struct call *call) { // and move it to the finished file location. // Rename extension to ".txt". int fn_len; - char *meta_filename = strrchr(recording->meta_filepath, '/'); + char *meta_filename = strrchr(recording->meta_filepath_pcap, '/'); char *meta_ext = NULL; if (meta_filename == NULL) { - meta_filename = recording->meta_filepath; + meta_filename = recording->meta_filepath_pcap; } else { meta_filename = meta_filename + 1; @@ -529,13 +564,13 @@ static int rec_pcap_meta_finish_file(struct call *call) { char new_metapath[prefix_len + fn_len + ext_len + 1]; snprintf(new_metapath, prefix_len+fn_len+1, "%s/metadata/%s", spooldir, meta_filename); snprintf(new_metapath + prefix_len+fn_len, ext_len+1, ".txt"); - return_code = return_code || rename(recording->meta_filepath, new_metapath); + return_code = return_code || rename(recording->meta_filepath_pcap, new_metapath); if (return_code != 0) { ilog(LOG_ERROR, "Could not move metadata file \"%s\" to \"%s/metadata/\"", - recording->meta_filepath, spooldir); + recording->meta_filepath_pcap, spooldir); } else { ilog(LOG_INFO, "Moved metadata file \"%s\" to \"%s/metadata\"", - recording->meta_filepath, spooldir); + recording->meta_filepath_pcap, spooldir); } mutex_destroy(&recording->u.pcap.recording_lock); @@ -672,7 +707,8 @@ void recording_finish(struct call *call) { free(recording->meta_prefix); free(recording->escaped_callid); - free(recording->meta_filepath); + free(recording->meta_filepath_pcap); + free(recording->meta_filepath_proc); g_slice_free1(sizeof(*(recording)), recording); call->recording = NULL; @@ -687,10 +723,10 @@ void recording_finish(struct call *call) { static int open_proc_meta_file(struct recording *recording) { int fd; - fd = open(recording->meta_filepath, O_WRONLY | O_APPEND | O_CREAT, 0666); + fd = open(recording->meta_filepath_proc, O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd == -1) { ilog(LOG_ERR, "Failed to open recording metadata file '%s' for writing: %s", - recording->meta_filepath, strerror(errno)); + recording->meta_filepath_proc, strerror(errno)); return -1; } return fd; @@ -756,8 +792,8 @@ static void proc_init(struct call *call) { } ilog(LOG_DEBUG, "kernel call idx is %u", recording->u.proc.call_idx); - recording->meta_filepath = file_path_str(recording->meta_prefix, "/", ".meta"); - unlink(recording->meta_filepath); // start fresh XXX good idea? + recording->meta_filepath_proc = file_path_str(recording->meta_prefix, "/", ".meta"); + unlink(recording->meta_filepath_proc); // start fresh XXX good idea? append_meta_chunk_str(recording, &call->callid, "CALL-ID"); append_meta_chunk_s(recording, recording->meta_prefix, "PARENT"); @@ -791,7 +827,7 @@ static void finish_proc(struct call *call) { struct packet_stream *ps = l->data; ps->recording.u.proc.stream_idx = UNINIT_IDX; } - unlink(recording->meta_filepath); + unlink(recording->meta_filepath_proc); } static void init_stream_proc(struct packet_stream *stream) { @@ -904,3 +940,38 @@ static void kernel_info_proc(struct packet_stream *stream, struct rtpengine_targ static void meta_chunk_proc(struct recording *recording, const char *label, const str *data) { append_meta_chunk_str(recording, data, "%s", label); } + +static int create_spool_dir_all(const char *spoolpath) { + int ret1, ret2; + + ret1 = rec_pcap_create_spool_dir(spoolpath); + ret2 = check_main_spool_dir(spoolpath); + + if (ret1 == FALSE || ret2 == FALSE) { + return FALSE; + } + + return TRUE; +} + +static void init_all(struct call *call) { + rec_pcap_init(call); + proc_init(call); +} + +static void sdp_after_all(struct recording *recording, GString *str, struct call_monologue *ml, + enum call_opmode opmode) +{ + sdp_after_pcap(recording, str, ml, opmode); + sdp_after_proc(recording, str, ml, opmode); +} + +static void dump_packet_all(struct media_packet *mp, const str *s) { + dump_packet_pcap(mp, s); + dump_packet_proc(mp, s); +} + +static void finish_all(struct call *call) { + finish_pcap(call); + finish_proc(call); +} diff --git a/daemon/rtpengine.pod b/daemon/rtpengine.pod index 93153dbb5..6968003e6 100644 --- a/daemon/rtpengine.pod +++ b/daemon/rtpengine.pod @@ -603,11 +603,11 @@ Since call recording via this method happens entirely in userspace, in-kernel packet forwarding cannot be used for calls that are currently being recorded and packet forwarding will thus be done in userspace only. -=item B<--recording-method=>B|B +=item B<--recording-method=>B|B|B Multiple methods of call recording are supported and this option can be used to select one. -Currently supported are the method B and B. +Currently supported are the method B, B and B. The default method is B and is the one described above. The recording method B works by writing metadata files directly into @@ -629,6 +629,9 @@ any purpose or not. In-kernel packet forwarding is fully supported with this recording method even for calls being recorded. +The recording method B will enable both B and B +at the same time. + =item B<--recording-format=>B|B When recording to pcap file in B (default) format, there is no diff --git a/include/recording.h b/include/recording.h index da6f841f3..0b30fa914 100644 --- a/include/recording.h +++ b/include/recording.h @@ -44,14 +44,15 @@ struct recording_stream_proc { }; struct recording { - union { + struct { struct recording_pcap pcap; struct recording_proc proc; } u; char *escaped_callid; // call-id with dangerous characters escaped char *meta_prefix; // escaped call-id plus random suffix - char *meta_filepath; // full file path + char *meta_filepath_proc; // full file path + char *meta_filepath_pcap; // full file path }; struct recording_stream {