All RTP packet data for a call goes to one PCAP file.

This involved moving all code from fs.(c|h) to recording.(c|h).
We still spoof packets, so the UDP will look like all monologues are coming
over the same port and will probably look like they are all one stream if
you look at the PCAP file.
pull/245/head
Dylan Mikus 11 years ago committed by Eric Green
parent fa4cd75820
commit f516684ade

@ -69,7 +69,7 @@ endif
SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \
bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \
crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \
media_socket.c rtcp_xr.c homer.c fs.c
media_socket.c rtcp_xr.c homer.c recording.c
OBJS= $(SRCS:.c=.o)

@ -36,7 +36,7 @@
#include "ice.h"
#include "rtpengine_config.h"
#include "log_funcs.h"
#include "fs.h"
#include "recording.h"
@ -1523,11 +1523,13 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
ml_media = other_ml_media = NULL;
str *pcap_path = recording_setup_file(call, monologue);
if (pcap_path != NULL != NULL && monologue->recording_pdumper != NULL
&& call->meta_fp) {
// Write the location of the PCAP file to the metadata file
fprintf(call->meta_fp, "%s\n", pcap_path->s);
if (call->recording != NULL && call->recording->recording_pdumper == NULL) {
str *pcap_path = recording_setup_file(call->recording);
if (pcap_path != NULL && call->recording->recording_pdumper != NULL
&& call->recording->meta_fp) {
// Write the location of the PCAP file to the metadata file
fprintf(call->recording->meta_fp, "%s\n", pcap_path->s);
}
}
for (media_iter = streams->head; media_iter; media_iter = media_iter->next) {
@ -2216,13 +2218,12 @@ void call_destroy(struct call *c) {
obj_put(sfd);
}
while (c->recording_pcaps) {
free(c->recording_pcaps->data);
c->recording_pcaps = g_slist_delete_link(c->recording_pcaps, c->recording_pcaps);
if (c->recording != NULL) {
recording_finish_file(c->recording);
free(c->recording->metadata);
}
meta_finish_file(c);
free(c->metadata);
rwlock_unlock_w(&c->master_lock);
}
@ -2319,6 +2320,7 @@ static struct call *call_create(const str *callid, struct callmaster *m) {
ilog(LOG_NOTICE, "Creating new call");
c = obj_alloc0("call", sizeof(*c), __call_free);
c->recording = NULL;
c->callmaster = m;
mutex_init(&c->buffer_lock);
call_buffer_init(&c->buffer);
@ -2415,8 +2417,6 @@ struct call_monologue *__monologue_create(struct call *call) {
ret->call = call;
ret->created = poller_now;
ret->other_tags = g_hash_table_new(str_hash, str_equal);
ret->recording_pd = NULL;
ret->recording_pdumper = NULL;
g_queue_init(&ret->medias);
gettimeofday(&ret->started, NULL);
@ -2491,7 +2491,6 @@ static void __monologue_destroy(struct call_monologue *monologue) {
GList *l;
call = monologue->call;
recording_finish_file(monologue);
g_hash_table_remove(call->tags, &monologue->tag);

@ -399,9 +399,6 @@ struct call_monologue {
GHashTable *other_tags;
struct call_monologue *active_dialogue;
GQueue medias;
pcap_t *recording_pd;
pcap_dumper_t *recording_pdumper;
str *recording_path;
};
struct call {
@ -423,9 +420,6 @@ struct call {
GQueue endpoint_maps;
struct dtls_cert *dtls_cert; /* for outgoing */
unsigned int record_call;
GSList *recording_pcaps;
str callid;
time_t created;
time_t last_signal;
@ -438,9 +432,7 @@ struct call {
unsigned int redis_hosted_db;
unsigned int foreign_call; // created_via_redis_notify call
str *meta_filepath;
FILE *meta_fp;
str *metadata;
struct recording *recording;
};
struct callmaster_config {

@ -18,6 +18,7 @@
#include "control_udp.h"
#include "rtp.h"
#include "ice.h"
#include "recording.h"
@ -689,17 +690,26 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster
goto out;
if (recordcall.s && !str_cmp(&recordcall, "yes")) {
if (!call->record_call) {
meta_setup_file(call);
call->record_call = 1;
if (call->recording == NULL) {
call->recording = g_slice_alloc0(sizeof(struct recording));
call->recording->recording_pd = NULL;
call->recording->recording_pdumper = NULL;
meta_setup_file(call->recording);
}
bencode_dictionary_get_str(input, "metadata", &metadata);
if (metadata.len > 0) {
free(call->metadata);
call->metadata = str_dup(&metadata);
free(call->recording->metadata);
call->recording->metadata = str_dup(&metadata);
}
} else {
call->record_call = 0;
if (call->recording != NULL) {
g_slice_free1(sizeof(*(call->recording)), call->recording);
str *rec_metadata = call->recording->metadata;
if (rec_metadata != NULL) {
free(rec_metadata);
}
}
call->recording = NULL;
}
if (!call->created_from && addr) {
@ -750,10 +760,9 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster
chopper->iov_num, chopper->str_len);
bencode_dictionary_add_string(output, "result", "ok");
bencode_item_t *recordings = bencode_dictionary_add_list(output, "recordings");
GList *l;
char *recording_path;
for (l = call->recording_pcaps; l; l = l->next) {
bencode_list_add_string(recordings, l->data);
if (call->recording != NULL && call->recording->recording_path != NULL) {
char *recording_path = call->recording->recording_path->s;
bencode_list_add_string(recordings, recording_path);
}
errstr = NULL;

@ -30,7 +30,7 @@
#include "socket.h"
#include "media_socket.h"
#include "homer.h"
#include "fs.h"
#include "recording.h"
@ -521,7 +521,7 @@ static void init_everything() {
socket_init();
log_init();
fs_init(spooldir);
recording_fs_init(spooldir);
clock_gettime(CLOCK_REALTIME, &ts);
srandom(ts.tv_sec ^ ts.tv_nsec);
SSL_library_init();

@ -18,7 +18,7 @@
#include "aux.h"
#include "log_funcs.h"
#include "poller.h"
#include "fs.h"
#include "recording.h"
@ -834,7 +834,7 @@ void kernelize(struct packet_stream *stream) {
struct packet_stream *sink = NULL;
const char *nk_warn_msg;
if (PS_ISSET(stream, KERNELIZED) || call->record_call)
if (PS_ISSET(stream, KERNELIZED) || call->recording != NULL)
return;
if (cm->conf.kernelid < 0)
goto no_kernel;
@ -1035,8 +1035,8 @@ static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin,
struct rtp_header *rtp_h;
struct rtp_stats *rtp_s;
recording_pdumper = sfd->stream->media->monologue->recording_pdumper;
call = sfd->call;
recording_pdumper = call->recording != NULL ? call->recording->recording_pdumper : NULL;
cm = call->callmaster;
rwlock_lock_r(&call->master_lock);

@ -1,4 +1,4 @@
#include "fs.h"
#include "recording.h"
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
@ -21,7 +21,7 @@ static char *spooldir = NULL;
* Initialize RTP Engine filesystem settings and structure.
* Check for or create the RTP Engine spool directory.
*/
void fs_init(char *spoolpath) {
void recording_fs_init(char *spoolpath) {
// Whether or not to fail if the spool directory does not exist.
int dne_fail;
if (spoolpath == NULL || spoolpath[0] == '\0') {
@ -97,7 +97,7 @@ int maybe_create_spool_dir(char *spoolpath) {
* Create a call metadata file in a temporary location.
* Attaches the filepath and the file pointer to the call struct.
*/
str *meta_setup_file(struct call *call) {
str *meta_setup_file(struct recording *recording) {
if (spooldir == NULL) {
// No spool directory was created, so we cannot have metadata files.
return NULL;
@ -108,15 +108,15 @@ str *meta_setup_file(struct call *call) {
// Initially file extension is ".tmp". When call is over, it changes to ".txt".
char *path_chars = rand_affixed_str(rand_bytes, "/tmp/rtpengine-meta-", ".tmp");
meta_filepath = str_init(meta_filepath, path_chars);
call->meta_filepath = meta_filepath;
recording->meta_filepath = meta_filepath;
FILE *mfp = fopen(meta_filepath->s, "w");
if (mfp == NULL) {
ilog(LOG_ERROR, "Could not open metadata file: %s", meta_filepath->s);
free(call->meta_filepath->s);
free(call->meta_filepath);
call->meta_filepath = NULL;
free(recording->meta_filepath->s);
free(recording->meta_filepath);
recording->meta_filepath = NULL;
}
call->meta_fp = mfp;
recording->meta_fp = mfp;
ilog(LOG_INFO, "Wrote metadata file to temporary path: %s", meta_filepath->s);
return meta_filepath;
}
@ -127,9 +127,10 @@ str *meta_setup_file(struct call *call) {
* Returns non-zero for failure.
*/
int meta_finish_file(struct call *call) {
struct recording *recording = call->recording;
int return_code = 0;
if (call->meta_fp != NULL) {
if (recording != NULL && recording->meta_fp != NULL) {
// Print start timestamp and end timestamp
// YYYY-MM-DDThh:mm:ss
time_t start = 0, end = 0;
@ -143,23 +144,23 @@ int meta_finish_file(struct call *call) {
}
timeinfo = localtime(&start);
strftime(timebuffer, 20, "%FT%T", timeinfo);
fprintf(call->meta_fp, "\n%s\n", timebuffer);
fprintf(recording->meta_fp, "\n%s\n", timebuffer);
timeinfo = localtime(&end);
strftime(timebuffer, 20, "%FT%T", timeinfo);
fprintf(call->meta_fp, "%s\n", timebuffer);
fprintf(recording->meta_fp, "%s\n", timebuffer);
// Print metadata
fprintf(call->meta_fp, "\n%s\n", call->metadata->s);
fclose(call->meta_fp);
fprintf(recording->meta_fp, "\n%s\n", recording->metadata->s);
fclose(recording->meta_fp);
// Get the filename (in between its directory and the file extension)
// and move it to the finished file location.
// Rename extension to ".txt".
int fn_len;
char *meta_filename = strrchr(call->meta_filepath->s, '/');
char *meta_filename = strrchr(recording->meta_filepath->s, '/');
char *meta_ext = NULL;
if (meta_filename == NULL) {
meta_filename = call->meta_filepath->s;
meta_filename = recording->meta_filepath->s;
}
else {
meta_filename = meta_filename + 1;
@ -172,18 +173,18 @@ int 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(call->meta_filepath->s, new_metapath);
return_code = return_code || rename(recording->meta_filepath->s, new_metapath);
if (return_code != 0) {
ilog(LOG_ERROR, "Could not move metadata file \"%s\" to \"%s/metadata/\"",
call->meta_filepath->s, spooldir);
recording->meta_filepath->s, spooldir);
} else {
ilog(LOG_INFO, "Moved metadata file \"%s\" to \"%s/metadata\"",
call->meta_filepath->s, spooldir);
recording->meta_filepath->s, spooldir);
}
}
if (call->meta_filepath != NULL) {
free(call->meta_filepath->s);
free(call->meta_filepath);
if (recording != NULL && recording->meta_filepath != NULL) {
free(recording->meta_filepath->s);
free(recording->meta_filepath);
}
return return_code;
@ -192,11 +193,11 @@ int meta_finish_file(struct call *call) {
/**
* Generate a random PCAP filepath to write recorded RTP stream.
*/
str *recording_setup_file(struct call *call, struct call_monologue *monologue) {
str *recording_setup_file(struct recording *recording) {
str *recording_path = NULL;
if (spooldir != NULL
&& call->record_call
&& monologue->recording_pd == NULL && monologue->recording_pdumper == NULL) {
&& recording != NULL
&& recording->recording_pd == NULL && recording->recording_pdumper == NULL) {
int rand_bytes = 16;
int rec_path_len = strlen(spooldir) + 8; // spool directory path + "/pcaps/"
char rec_path[rec_path_len];
@ -205,22 +206,21 @@ str *recording_setup_file(struct call *call, struct call_monologue *monologue) {
recording_path = malloc(sizeof(str));
recording_path = str_init(recording_path, path_chars);
monologue->recording_path = recording_path;
recording->recording_path = recording_path;
call->recording_pcaps = g_slist_prepend(call->recording_pcaps, g_strdup(path_chars));
monologue->recording_pd = pcap_open_dead(DLT_RAW, 65535);
monologue->recording_pdumper = pcap_dump_open(monologue->recording_pd, path_chars);
if (monologue->recording_pdumper == NULL) {
pcap_close(monologue->recording_pd);
monologue->recording_pd = NULL;
recording->recording_pd = pcap_open_dead(DLT_RAW, 65535);
recording->recording_pdumper = pcap_dump_open(recording->recording_pd, path_chars);
if (recording->recording_pdumper == NULL) {
pcap_close(recording->recording_pd);
recording->recording_pd = NULL;
ilog(LOG_INFO, "Failed to write recording file: %s", recording_path->s);
} else {
ilog(LOG_INFO, "Writing recording file: %s", recording_path->s);
}
} else {
monologue->recording_path = NULL;
monologue->recording_pd = NULL;
monologue->recording_pdumper = NULL;
} else if (recording != NULL) {
recording->recording_path = NULL;
recording->recording_pd = NULL;
recording->recording_pdumper = NULL;
}
return recording_path;
@ -229,15 +229,15 @@ str *recording_setup_file(struct call *call, struct call_monologue *monologue) {
/**
* Flushes PCAP file, closes the dumper and descriptors, and frees object memory.
*/
void recording_finish_file(struct call_monologue *monologue) {
if (monologue->recording_pdumper != NULL) {
pcap_dump_flush(monologue->recording_pdumper);
pcap_dump_close(monologue->recording_pdumper);
free(monologue->recording_path->s);
free(monologue->recording_path);
void recording_finish_file(struct recording *recording) {
if (recording->recording_pdumper != NULL) {
pcap_dump_flush(recording->recording_pdumper);
pcap_dump_close(recording->recording_pdumper);
free(recording->recording_path->s);
free(recording->recording_path);
}
if (monologue->recording_pd != NULL) {
pcap_close(monologue->recording_pd);
if (recording->recording_pd != NULL) {
pcap_close(recording->recording_pd);
}
}

@ -1,16 +1,34 @@
#ifndef __FS_H__
#define __FS_H__
/**
* recording.h
*
* Handles call recording to PCAP files and recording metadata.
* Mostly filesystem operations
*/
#ifndef __RECORDING_H__
#define __RECORDING_H__
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include "call.h"
struct recording {
str *meta_filepath;
FILE *meta_fp;
str *metadata;
pcap_t *recording_pd;
pcap_dumper_t *recording_pdumper;
str *recording_path;
};
/**
* Initialize RTP Engine filesystem settings and structure.
* Check for or create the RTP Engine spool directory.
*/
void fs_init(char *spooldir);
void recording_fs_init(char *spooldir);
/**
* Create a call metadata file in a temporary location.
@ -30,7 +48,7 @@ void fs_init(char *spooldir);
* generic metadata
*
*/
str *meta_setup_file(struct call *call);
str *meta_setup_file(struct recording *recording);
/**
* Writes metadata to metafile, closes file, and renames it to finished location.
@ -42,12 +60,12 @@ int meta_finish_file(struct call *call);
* Generate a random PCAP filepath to write recorded RTP stream.
* Returns path to created file.
*/
str *recording_setup_file(struct call *call, struct call_monologue *monologue);
str *recording_setup_file(struct recording *recording);
/**
* Flushes PCAP file, closes the dumper and descriptors, and frees object memory.
*/
void recording_finish_file(struct call_monologue *monologue);
void recording_finish_file(struct recording *recording);
/**
* Write out a PCAP packet with payload string.
Loading…
Cancel
Save