|
|
|
@ -285,16 +285,16 @@ static void pcap_init(struct call *call) { |
|
|
|
struct recording *recording = call->recording; |
|
|
|
|
|
|
|
// Wireshark starts at packet index 1, so we start there, too |
|
|
|
recording->pcap.packet_num = 1; |
|
|
|
mutex_init(&recording->pcap.recording_lock); |
|
|
|
recording->u.pcap.packet_num = 1; |
|
|
|
mutex_init(&recording->u.pcap.recording_lock); |
|
|
|
meta_setup_file(recording); |
|
|
|
|
|
|
|
// set up pcap file |
|
|
|
char *pcap_path = recording_setup_file(recording); |
|
|
|
if (pcap_path != NULL && recording->pcap.recording_pdumper != NULL |
|
|
|
&& recording->pcap.meta_fp) { |
|
|
|
if (pcap_path != NULL && recording->u.pcap.recording_pdumper != NULL |
|
|
|
&& recording->u.pcap.meta_fp) { |
|
|
|
// Write the location of the PCAP file to the metadata file |
|
|
|
fprintf(recording->pcap.meta_fp, "%s\n\n", pcap_path); |
|
|
|
fprintf(recording->u.pcap.meta_fp, "%s\n\n", pcap_path); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -326,7 +326,7 @@ static char *meta_setup_file(struct recording *recording) { |
|
|
|
recording->meta_filepath = NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
recording->pcap.meta_fp = mfp; |
|
|
|
recording->u.pcap.meta_fp = mfp; |
|
|
|
ilog(LOG_DEBUG, "Wrote metadata file to temporary path: %s", meta_filepath); |
|
|
|
return meta_filepath; |
|
|
|
} |
|
|
|
@ -337,7 +337,7 @@ static char *meta_setup_file(struct recording *recording) { |
|
|
|
static void sdp_after_pcap(struct recording *recording, struct iovec *sdp_iov, int iovcnt, |
|
|
|
unsigned int str_len, struct call_monologue *ml, enum call_opmode opmode) |
|
|
|
{ |
|
|
|
FILE *meta_fp = recording->pcap.meta_fp; |
|
|
|
FILE *meta_fp = recording->u.pcap.meta_fp; |
|
|
|
if (!meta_fp) |
|
|
|
return; |
|
|
|
|
|
|
|
@ -347,7 +347,7 @@ static void sdp_after_pcap(struct recording *recording, struct iovec *sdp_iov, i |
|
|
|
// so the file contents appear in order. |
|
|
|
fprintf(meta_fp, "\nSDP mode: "); |
|
|
|
fprintf(meta_fp, "%s", get_opmode_text(opmode)); |
|
|
|
fprintf(meta_fp, "\nSDP before RTP packet: %" PRIu64 "\n\n", recording->pcap.packet_num); |
|
|
|
fprintf(meta_fp, "\nSDP before RTP packet: %" PRIu64 "\n\n", recording->u.pcap.packet_num); |
|
|
|
fflush(meta_fp); |
|
|
|
if (writev(meta_fd, sdp_iov, iovcnt) <= 0) |
|
|
|
ilog(LOG_WARN, "Error writing SDP body to metadata file: %s", strerror(errno)); |
|
|
|
@ -362,7 +362,7 @@ static int pcap_meta_finish_file(struct call *call) { |
|
|
|
struct recording *recording = call->recording; |
|
|
|
int return_code = 0; |
|
|
|
|
|
|
|
if (recording == NULL || recording->pcap.meta_fp == NULL) { |
|
|
|
if (recording == NULL || recording->u.pcap.meta_fp == NULL) { |
|
|
|
ilog(LOG_INFO, "Trying to clean up recording meta file without a file pointer opened."); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -375,16 +375,16 @@ static int pcap_meta_finish_file(struct call *call) { |
|
|
|
struct tm *timeinfo; |
|
|
|
timeinfo = localtime(&start); |
|
|
|
strftime(timebuffer, 20, "%FT%T", timeinfo); |
|
|
|
fprintf(recording->pcap.meta_fp, "\n\ncall start time: %s\n", timebuffer); |
|
|
|
fprintf(recording->u.pcap.meta_fp, "\n\ncall start time: %s\n", timebuffer); |
|
|
|
timeinfo = localtime(&end); |
|
|
|
strftime(timebuffer, 20, "%FT%T", timeinfo); |
|
|
|
fprintf(recording->pcap.meta_fp, "call end time: %s\n", timebuffer); |
|
|
|
fprintf(recording->u.pcap.meta_fp, "call end time: %s\n", timebuffer); |
|
|
|
|
|
|
|
// Print metadata |
|
|
|
if (recording->metadata.len) |
|
|
|
fprintf(recording->pcap.meta_fp, "\n\n"STR_FORMAT"\n", STR_FMT(&recording->metadata)); |
|
|
|
fclose(recording->pcap.meta_fp); |
|
|
|
recording->pcap.meta_fp = NULL; |
|
|
|
fprintf(recording->u.pcap.meta_fp, "\n\n"STR_FORMAT"\n", STR_FMT(&recording->metadata)); |
|
|
|
fclose(recording->u.pcap.meta_fp); |
|
|
|
recording->u.pcap.meta_fp = NULL; |
|
|
|
|
|
|
|
// Get the filename (in between its directory and the file extension) |
|
|
|
// and move it to the finished file location. |
|
|
|
@ -415,7 +415,7 @@ static int pcap_meta_finish_file(struct call *call) { |
|
|
|
recording->meta_filepath, spooldir); |
|
|
|
} |
|
|
|
|
|
|
|
mutex_destroy(&recording->pcap.recording_lock); |
|
|
|
mutex_destroy(&recording->u.pcap.recording_lock); |
|
|
|
|
|
|
|
return return_code; |
|
|
|
} |
|
|
|
@ -429,17 +429,17 @@ static char *recording_setup_file(struct recording *recording) { |
|
|
|
|
|
|
|
if (!spooldir) |
|
|
|
return NULL; |
|
|
|
if (recording->pcap.recording_pd || recording->pcap.recording_pdumper) |
|
|
|
if (recording->u.pcap.recording_pd || recording->u.pcap.recording_pdumper) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
recording_path = file_path_str(recording->meta_prefix, "/pcaps/", ".pcap"); |
|
|
|
recording->pcap.recording_path = recording_path; |
|
|
|
recording->u.pcap.recording_path = recording_path; |
|
|
|
|
|
|
|
recording->pcap.recording_pd = pcap_open_dead(pcap_format->linktype, 65535); |
|
|
|
recording->pcap.recording_pdumper = pcap_dump_open(recording->pcap.recording_pd, recording_path); |
|
|
|
if (recording->pcap.recording_pdumper == NULL) { |
|
|
|
pcap_close(recording->pcap.recording_pd); |
|
|
|
recording->pcap.recording_pd = NULL; |
|
|
|
recording->u.pcap.recording_pd = pcap_open_dead(pcap_format->linktype, 65535); |
|
|
|
recording->u.pcap.recording_pdumper = pcap_dump_open(recording->u.pcap.recording_pd, recording_path); |
|
|
|
if (recording->u.pcap.recording_pdumper == NULL) { |
|
|
|
pcap_close(recording->u.pcap.recording_pd); |
|
|
|
recording->u.pcap.recording_pd = NULL; |
|
|
|
ilog(LOG_INFO, "Failed to write recording file: %s", recording_path); |
|
|
|
} else { |
|
|
|
ilog(LOG_INFO, "Writing recording file: %s", recording_path); |
|
|
|
@ -452,13 +452,13 @@ static char *recording_setup_file(struct recording *recording) { |
|
|
|
* Flushes PCAP file, closes the dumper and descriptors, and frees object memory. |
|
|
|
*/ |
|
|
|
static void pcap_recording_finish_file(struct recording *recording) { |
|
|
|
if (recording->pcap.recording_pdumper != NULL) { |
|
|
|
pcap_dump_flush(recording->pcap.recording_pdumper); |
|
|
|
pcap_dump_close(recording->pcap.recording_pdumper); |
|
|
|
free(recording->pcap.recording_path); |
|
|
|
if (recording->u.pcap.recording_pdumper != NULL) { |
|
|
|
pcap_dump_flush(recording->u.pcap.recording_pdumper); |
|
|
|
pcap_dump_close(recording->u.pcap.recording_pdumper); |
|
|
|
free(recording->u.pcap.recording_path); |
|
|
|
} |
|
|
|
if (recording->pcap.recording_pd != NULL) { |
|
|
|
pcap_close(recording->pcap.recording_pd); |
|
|
|
if (recording->u.pcap.recording_pd != NULL) { |
|
|
|
pcap_close(recording->u.pcap.recording_pd); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -510,10 +510,10 @@ static void stream_pcap_dump(pcap_dumper_t *pdumper, struct packet_stream *strea |
|
|
|
} |
|
|
|
|
|
|
|
static void dump_packet_pcap(struct recording *recording, struct packet_stream *stream, const str *s) { |
|
|
|
mutex_lock(&recording->pcap.recording_lock); |
|
|
|
stream_pcap_dump(recording->pcap.recording_pdumper, stream, s); |
|
|
|
recording->pcap.packet_num++; |
|
|
|
mutex_unlock(&recording->pcap.recording_lock); |
|
|
|
mutex_lock(&recording->u.pcap.recording_lock); |
|
|
|
stream_pcap_dump(recording->u.pcap.recording_pdumper, stream, s); |
|
|
|
recording->u.pcap.packet_num++; |
|
|
|
mutex_unlock(&recording->u.pcap.recording_lock); |
|
|
|
} |
|
|
|
|
|
|
|
static void finish_pcap(struct call *call) { |
|
|
|
@ -522,11 +522,11 @@ static void finish_pcap(struct call *call) { |
|
|
|
} |
|
|
|
|
|
|
|
static void response_pcap(struct recording *recording, bencode_item_t *output) { |
|
|
|
if (!recording->pcap.recording_path) |
|
|
|
if (!recording->u.pcap.recording_path) |
|
|
|
return; |
|
|
|
|
|
|
|
bencode_item_t *recordings = bencode_dictionary_add_list(output, "recordings"); |
|
|
|
bencode_list_add_string(recordings, recording->pcap.recording_path); |
|
|
|
bencode_list_add_string(recordings, recording->u.pcap.recording_path); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -638,17 +638,17 @@ static int append_meta_chunk(struct recording *recording, const char *buf, unsig |
|
|
|
static void proc_init(struct call *call) { |
|
|
|
struct recording *recording = call->recording; |
|
|
|
|
|
|
|
recording->proc.call_idx = UNINIT_IDX; |
|
|
|
recording->u.proc.call_idx = UNINIT_IDX; |
|
|
|
if (!kernel.is_open) { |
|
|
|
ilog(LOG_WARN, "Call recording through /proc interface requested, but kernel table not open"); |
|
|
|
return; |
|
|
|
} |
|
|
|
recording->proc.call_idx = kernel_add_call(recording->meta_prefix); |
|
|
|
if (recording->proc.call_idx == UNINIT_IDX) { |
|
|
|
recording->u.proc.call_idx = kernel_add_call(recording->meta_prefix); |
|
|
|
if (recording->u.proc.call_idx == UNINIT_IDX) { |
|
|
|
ilog(LOG_ERR, "Failed to add call to kernel recording interface: %s", strerror(errno)); |
|
|
|
return; |
|
|
|
} |
|
|
|
ilog(LOG_DEBUG, "kernel call idx is %u", recording->proc.call_idx); |
|
|
|
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? |
|
|
|
@ -676,13 +676,13 @@ static void finish_proc(struct call *call) { |
|
|
|
struct recording *recording = call->recording; |
|
|
|
if (!kernel.is_open) |
|
|
|
return; |
|
|
|
if (recording->proc.call_idx != UNINIT_IDX) |
|
|
|
kernel_del_call(recording->proc.call_idx); |
|
|
|
if (recording->u.proc.call_idx != UNINIT_IDX) |
|
|
|
kernel_del_call(recording->u.proc.call_idx); |
|
|
|
unlink(recording->meta_filepath); |
|
|
|
} |
|
|
|
|
|
|
|
static void init_stream_proc(struct packet_stream *stream) { |
|
|
|
stream->recording.proc.stream_idx = UNINIT_IDX; |
|
|
|
stream->recording.u.proc.stream_idx = UNINIT_IDX; |
|
|
|
} |
|
|
|
|
|
|
|
static void setup_stream_proc(struct packet_stream *stream) { |
|
|
|
@ -697,7 +697,7 @@ static void setup_stream_proc(struct packet_stream *stream) { |
|
|
|
return; |
|
|
|
if (!kernel.is_open) |
|
|
|
return; |
|
|
|
if (stream->recording.proc.stream_idx != UNINIT_IDX) |
|
|
|
if (stream->recording.u.proc.stream_idx != UNINIT_IDX) |
|
|
|
return; |
|
|
|
|
|
|
|
len = snprintf(buf, sizeof(buf), "TAG %u MEDIA %u COMPONENT %u FLAGS %u", |
|
|
|
@ -709,12 +709,12 @@ static void setup_stream_proc(struct packet_stream *stream) { |
|
|
|
ml->unique_id, media->index, stream->component, |
|
|
|
(PS_ISSET(stream, RTCP) && !PS_ISSET(stream, RTP)) ? "RTCP" : "RTP", |
|
|
|
stream->unique_id); |
|
|
|
stream->recording.proc.stream_idx = kernel_add_intercept_stream(recording->proc.call_idx, buf); |
|
|
|
if (stream->recording.proc.stream_idx == UNINIT_IDX) { |
|
|
|
stream->recording.u.proc.stream_idx = kernel_add_intercept_stream(recording->u.proc.call_idx, buf); |
|
|
|
if (stream->recording.u.proc.stream_idx == UNINIT_IDX) { |
|
|
|
ilog(LOG_ERR, "Failed to add stream to kernel recording interface: %s", strerror(errno)); |
|
|
|
return; |
|
|
|
} |
|
|
|
ilog(LOG_DEBUG, "kernel stream idx is %u", stream->recording.proc.stream_idx); |
|
|
|
ilog(LOG_DEBUG, "kernel stream idx is %u", stream->recording.u.proc.stream_idx); |
|
|
|
append_meta_chunk(recording, buf, len, "STREAM %u interface", stream->unique_id); |
|
|
|
} |
|
|
|
|
|
|
|
@ -739,7 +739,7 @@ static void setup_media_proc(struct call_media *media) { |
|
|
|
|
|
|
|
|
|
|
|
static void dump_packet_proc(struct recording *recording, struct packet_stream *stream, const str *s) { |
|
|
|
if (stream->recording.proc.stream_idx == UNINIT_IDX) |
|
|
|
if (stream->recording.u.proc.stream_idx == UNINIT_IDX) |
|
|
|
return; |
|
|
|
|
|
|
|
struct rtpengine_message *remsg; |
|
|
|
@ -748,8 +748,8 @@ static void dump_packet_proc(struct recording *recording, struct packet_stream * |
|
|
|
|
|
|
|
ZERO(*remsg); |
|
|
|
remsg->cmd = REMG_PACKET; |
|
|
|
//remsg->u.packet.call_idx = stream->call->recording->proc.call_idx; // unused |
|
|
|
remsg->u.packet.stream_idx = stream->recording.proc.stream_idx; |
|
|
|
//remsg->u.packet.call_idx = stream->call->recording->u.proc.call_idx; // unused |
|
|
|
remsg->u.packet.stream_idx = stream->recording.u.proc.stream_idx; |
|
|
|
|
|
|
|
unsigned int pkt_len = fake_ip_header(remsg->data, stream, s); |
|
|
|
pkt_len += sizeof(*remsg); |
|
|
|
@ -762,11 +762,11 @@ static void dump_packet_proc(struct recording *recording, struct packet_stream * |
|
|
|
static void kernel_info_proc(struct packet_stream *stream, struct rtpengine_target_info *reti) { |
|
|
|
if (!stream->call->recording) |
|
|
|
return; |
|
|
|
if (stream->recording.proc.stream_idx == UNINIT_IDX) |
|
|
|
if (stream->recording.u.proc.stream_idx == UNINIT_IDX) |
|
|
|
return; |
|
|
|
ilog(LOG_DEBUG, "enabling kernel intercept with stream idx %u", stream->recording.proc.stream_idx); |
|
|
|
ilog(LOG_DEBUG, "enabling kernel intercept with stream idx %u", stream->recording.u.proc.stream_idx); |
|
|
|
reti->do_intercept = 1; |
|
|
|
reti->intercept_stream_idx = stream->recording.proc.stream_idx; |
|
|
|
reti->intercept_stream_idx = stream->recording.u.proc.stream_idx; |
|
|
|
} |
|
|
|
|
|
|
|
static void meta_chunk_proc(struct recording *recording, const char *label, const str *data) { |
|
|
|
|