diff --git a/src/capture.c b/src/capture.c index 9d6562e..6548872 100644 --- a/src/capture.c +++ b/src/capture.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "capture.h" #ifdef USE_EEP #include "capture_eep.h" @@ -49,10 +51,26 @@ #include "setting.h" #include "util.h" +#if __STDC_VERSION__ >= 201112L && __STDC_NO_ATOMICS__ != 1 +// modern C with atomics +#include +typedef atomic_int signal_flag_type; +#else +// no atomics available +typedef volatile sig_atomic_t signal_flag_type; +#endif + // Capture information capture_config_t capture_cfg = { 0 }; +signal_flag_type sighup_received = 0; + +void sighup_handler(int signum) +{ + sighup_received = 1; +} + void capture_init(size_t limit, bool rtp_capture, bool rotate, size_t pcap_buffer_size) { @@ -63,6 +81,13 @@ capture_init(size_t limit, bool rtp_capture, bool rotate, size_t pcap_buffer_siz capture_cfg.paused = 0; capture_cfg.sources = vector_create(1, 1); + // set up SIGHUP handler + // the handler will be served by any of the running threads + // so we just set a flag and check it in dump_packet + // so it is only acted upon before then next packed will be dumped + if (signal(SIGHUP, sighup_handler) == SIG_ERR) + exit(EXIT_FAILURE); + // Fixme if (setting_has_value(SETTING_CAPTURE_STORAGE, "none")) { capture_cfg.storage = CAPTURE_STORAGE_NONE; @@ -383,7 +408,7 @@ parse_packet(u_char *info, const struct pcap_pkthdr *header, const u_char *packe capture_eep_send(pkt); #endif // Store this packets in output file - dump_packet(capture_cfg.pd, pkt); + capture_dump_packet(pkt);; // If storage is disabled, delete frames payload if (capture_cfg.storage == 0) { packet_free_frames(pkt); @@ -1204,18 +1229,40 @@ capture_packet_time_sorter(vector_t *vector, void *item) } void -capture_set_dumper(pcap_dumper_t *dumper) +capture_set_dumper(pcap_dumper_t *dumper, ino_t dump_inode) { capture_cfg.pd = dumper; + capture_cfg.dump_inode = dump_inode; } void capture_dump_packet(packet_t *packet) { + if (sighup_received && capture_cfg.pd) { + // we got a SIGHUP: reopen the dump file because it could have been renamed + // we don't need to care about locking or other threads accessing in parallel + // because dump_open ensures count(capture_cfg.sources) == 1 + + // check if the file has actually changed + // only reopen if it has, otherwise we would overwrite the existing one + struct stat sb; + if (stat(capture_cfg.dumpfilename, &sb) == -1 || + sb.st_ino != capture_cfg.dump_inode) + { + pcap_dump_close(capture_cfg.pd); + capture_cfg.pd = dump_open(capture_cfg.dumpfilename, &capture_cfg.dump_inode); + } + + sighup_received = 0; + + // error reopening capture file: we can't capture anymore + if (!capture_cfg.pd) + return; + } + dump_packet(capture_cfg.pd, packet); } - int8_t datalink_size(int datalink) { @@ -1264,13 +1311,31 @@ datalink_size(int datalink) } pcap_dumper_t * -dump_open(const char *dumpfile) +dump_open(const char *dumpfile, ino_t* dump_inode) { capture_info_t *capinfo; if (vector_count(capture_cfg.sources) == 1) { + capture_cfg.dumpfilename = dumpfile; capinfo = vector_first(capture_cfg.sources); - return pcap_dump_open(capinfo->handle, dumpfile); + + FILE *fp = fopen(dumpfile,"wb+"); + if (!fp) + return NULL; + + struct stat sb; + if (fstat(fileno(fp), &sb) == -1) + return NULL; + + if (dump_inode) { + // read out the files inode, allows to later check if it has changed + struct stat sb; + if (fstat(fileno(fp), &sb) == -1) + return NULL; + *dump_inode = sb.st_ino; + } + + return pcap_dump_fopen(capinfo->handle, fp); } return NULL; } diff --git a/src/capture.h b/src/capture.h index 363b4c3..755ca5d 100644 --- a/src/capture.h +++ b/src/capture.h @@ -139,6 +139,10 @@ struct capture_config { struct bpf_program fp; //! libpcap dump file handler pcap_dumper_t *pd; + //! libpcap dump file name + const char *dumpfilename; + //! inode of the dump file we have open + ino_t dump_inode; //! Capture sources vector_t *sources; //! Capture Lock. Avoid parsing and handling data at the same time @@ -469,7 +473,7 @@ capture_close(); * @brief Set general capture dumper */ void -capture_set_dumper(pcap_dumper_t *dumper); +capture_set_dumper(pcap_dumper_t *dumper, ino_t dump_inode); /** * @brief Store a packet in dumper file @@ -488,7 +492,7 @@ datalink_size(int datalink); * @brief Open a new dumper file for capture handler */ pcap_dumper_t * -dump_open(const char *dumpfile); +dump_open(const char *dumpfile, ino_t* dump_inode); /** * @brief Store a packet in dump file diff --git a/src/curses/ui_save.c b/src/curses/ui_save.c index 29bf6ec..eebe5fd 100644 --- a/src/curses/ui_save.c +++ b/src/curses/ui_save.c @@ -465,7 +465,7 @@ save_to_file(ui_t *ui) if (info->saveformat == SAVE_PCAP || info->saveformat == SAVE_PCAP_RTP) { // Open dump file - pd = dump_open(fullfile); + pd = dump_open(fullfile, NULL); if (access(fullfile, W_OK) != 0) { dialog_run("%s", capture_last_error()); return 1; diff --git a/src/main.c b/src/main.c index e8b91f6..28e170c 100644 --- a/src/main.c +++ b/src/main.c @@ -381,8 +381,11 @@ main(int argc, char* argv[]) return 1; } - if (outfile) { - capture_set_dumper(dump_open(outfile)); + if (outfile) + { + ino_t dump_inode; + pcap_dumper_t *dumper = dump_open(outfile, &dump_inode); + capture_set_dumper(dumper, dump_inode); } // Remove Input files vector