diff options
-rw-r--r-- | Makefile.common | 2 | ||||
-rw-r--r-- | capture.c | 725 | ||||
-rw-r--r-- | capture_sync.c | 796 | ||||
-rw-r--r-- | capture_sync.h | 76 |
4 files changed, 882 insertions, 717 deletions
diff --git a/Makefile.common b/Makefile.common index 13d78709a6..09044da7ac 100644 --- a/Makefile.common +++ b/Makefile.common @@ -140,6 +140,7 @@ ethereal_SOURCES = \ $(ETHEREAL_COMMON_SRC) \ alert_box.c \ capture.c \ + capture_sync.c \ capture_combo_utils.c \ color_filters.c \ file.c \ @@ -153,6 +154,7 @@ ethereal_SOURCES = \ ethereal_INCLUDES = \ alert_box.h \ capture.h \ + capture_sync.h \ capture_combo_utils.h \ color_filters.h \ filters.h \ @@ -105,10 +105,6 @@ # include "snprintf.h" #endif -#ifdef _WIN32 -#include <process.h> /* For spawning child process */ -#endif - /* * We don't want to do a "select()" on the pcap_t's file descriptor on * BSD (because "select()" doesn't work correctly on BPF devices on at @@ -136,6 +132,7 @@ #include <epan/dfilter/dfilter.h> #include "file.h" #include "capture.h" +#include "capture_sync.h" #include "util.h" #include "pcap-util.h" #include "alert_box.h" @@ -179,22 +176,6 @@ capture_options capture_opts; gboolean quit_after_cap = FALSE;/* Makes a "capture only mode". Implies -k */ gboolean capture_child; /* if this is the child for "-S" */ -static int sync_pipe[2]; /* used to sync father */ -enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */ -static int fork_child = -1; /* If not -1, in parent, process ID of child */ - -/* Size of buffer to hold decimal representation of - signed/unsigned 64-bit int */ -#define SP_DECISIZE 20 - -/* - * Indications sent out on the sync pipe. - */ -#define SP_CAPSTART ';' /* capture start message */ -#define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */ -#define SP_ERROR_MSG '!' /* followed by length of error message that follows */ -#define SP_DROPS '#' /* followed by count of packets dropped in capture */ - typedef struct _loop_data { gboolean go; /* TRUE as long as we're supposed to keep capturing */ @@ -224,14 +205,6 @@ typedef struct _loop_data { #define O_BINARY 0 #endif -static gboolean sync_pipe_do_capture(gboolean is_tempfile); -static gboolean sync_pipe_input_cb(gint source, gpointer user_data); -static void sync_pipe_wait_for_child(gboolean); -static void sync_pipe_errmsg_to_parent(const char *); -#ifndef _WIN32 -static char *sync_pipe_signame(int); -#endif - static gboolean normal_do_capture(gboolean is_tempfile); static void capture_pcap_cb(guchar *, const struct pcap_pkthdr *, const guchar *); @@ -303,7 +276,6 @@ do_capture(const char *save_file) cfile.save_file = capfile_name; /* cfile.save_file is "g_free"ed below, which is equivalent to "g_free(capfile_name)". */ - fork_child = -1; if (capture_opts.sync_mode) { /* sync mode: do the capture in a child process */ @@ -322,660 +294,9 @@ do_capture(const char *save_file) -/* Add a string pointer to a NULL-terminated array of string pointers. */ -static char ** -sync_pipe_add_arg(char **args, int *argc, char *arg) -{ - /* Grow the array; "*argc" currently contains the number of string - pointers, *not* counting the NULL pointer at the end, so we have - to add 2 in order to get the new size of the array, including the - new pointer and the terminating NULL pointer. */ - args = g_realloc(args, (*argc + 2) * sizeof (char *)); - - /* Stuff the pointer into the penultimate element of the array, which - is the one at the index specified by "*argc". */ - args[*argc] = arg; - - /* Now bump the count. */ - (*argc)++; - - /* We overwrite the NULL pointer; put it back right after the - element we added. */ - args[*argc] = NULL; - - return args; -} - -#ifdef _WIN32 -/* Given a string, return a pointer to a quote-encapsulated version of - the string, so we can pass it as an argument with "spawnvp" even - if it contains blanks. */ -char * -sync_pipe_quote_encapsulate(const char *string) -{ - char *encapsulated_string; - - encapsulated_string = g_new(char, strlen(string) + 3); - sprintf(encapsulated_string, "\"%s\"", string); - return encapsulated_string; -} -#endif - - - -static gboolean -sync_pipe_do_capture(gboolean is_tempfile) { - guint byte_count; - int i; - guchar c; - char *msg; - int err; - char ssnap[24]; - char scount[24]; /* need a constant for len of numbers */ - char sautostop_filesize[24]; /* need a constant for len of numbers */ - char sautostop_duration[24]; /* need a constant for len of numbers */ - char save_file_fd[24]; -#ifndef _WIN32 - char errmsg[1024+1]; -#endif - int error; - int argc; - char **argv; -#ifdef _WIN32 - char sync_pipe_fd[24]; - char *fontstring; - char *filterstring; -#endif - - /* Allocate the string pointer array with enough space for the - terminating NULL pointer. */ - argc = 0; - argv = g_malloc(sizeof (char *)); - *argv = NULL; - - /* Now add those arguments used on all platforms. */ - argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME); - - argv = sync_pipe_add_arg(argv, &argc, "-i"); - argv = sync_pipe_add_arg(argv, &argc, cfile.iface); - - argv = sync_pipe_add_arg(argv, &argc, "-w"); - argv = sync_pipe_add_arg(argv, &argc, cfile.save_file); - - argv = sync_pipe_add_arg(argv, &argc, "-W"); - sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */ - argv = sync_pipe_add_arg(argv, &argc, save_file_fd); - - if (capture_opts.has_autostop_packets) { - argv = sync_pipe_add_arg(argv, &argc, "-c"); - sprintf(scount,"%d",capture_opts.autostop_packets); - argv = sync_pipe_add_arg(argv, &argc, scount); - } - - if (capture_opts.has_snaplen) { - argv = sync_pipe_add_arg(argv, &argc, "-s"); - sprintf(ssnap,"%d",capture_opts.snaplen); - argv = sync_pipe_add_arg(argv, &argc, ssnap); - } - - if (capture_opts.linktype != -1) { - argv = sync_pipe_add_arg(argv, &argc, "-y"); -#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME - sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts.linktype)); -#else - /* XXX - just treat it as a number */ - sprintf(ssnap,"%d",capture_opts.linktype); -#endif - argv = sync_pipe_add_arg(argv, &argc, ssnap); - } - - if (capture_opts.has_autostop_filesize) { - argv = sync_pipe_add_arg(argv, &argc, "-a"); - sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize); - argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize); - } - - if (capture_opts.has_autostop_duration) { - argv = sync_pipe_add_arg(argv, &argc, "-a"); - sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration); - argv = sync_pipe_add_arg(argv, &argc, sautostop_duration); - } - - if (!capture_opts.show_info) { - argv = sync_pipe_add_arg(argv, &argc, "-H"); - } - - if (!capture_opts.promisc_mode) - argv = sync_pipe_add_arg(argv, &argc, "-p"); - -#ifdef _WIN32 - /* Create a pipe for the child process */ - - if(_pipe(sync_pipe, 512, O_BINARY) < 0) { - /* Couldn't create the pipe between parent and child. */ - error = errno; - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", - strerror(error)); - return FALSE; - } - - /* Convert font name to a quote-encapsulated string and pass to child */ - argv = sync_pipe_add_arg(argv, &argc, "-m"); - fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME); - argv = sync_pipe_add_arg(argv, &argc, fontstring); - - /* Convert pipe write handle to a string and pass to child */ - argv = sync_pipe_add_arg(argv, &argc, "-Z"); - itoa(sync_pipe[WRITE], sync_pipe_fd, 10); - argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd); - - /* Convert filter string to a quote delimited string and pass to child */ - filterstring = NULL; - if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) { - argv = sync_pipe_add_arg(argv, &argc, "-f"); - filterstring = sync_pipe_quote_encapsulate(cfile.cfilter); - argv = sync_pipe_add_arg(argv, &argc, filterstring); - } - - /* Spawn process */ - fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv); - g_free(fontstring); - if (filterstring) { - g_free(filterstring); - } -#else - if (pipe(sync_pipe) < 0) { - /* Couldn't create the pipe between parent and child. */ - error = errno; - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", - strerror(error)); - return FALSE; - } - - argv = sync_pipe_add_arg(argv, &argc, "-m"); - argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME); - - if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) { - argv = sync_pipe_add_arg(argv, &argc, "-f"); - argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter); - } - - if ((fork_child = fork()) == 0) { - /* - * Child process - run Ethereal with the right arguments to make - * it just pop up the live capture dialog box and capture with - * the specified capture parameters, writing to the specified file. - * - * args: -i interface specification - * -w file to write - * -W file descriptor to write - * -c count to capture - * -s snaplen - * -m / -b fonts - * -f "filter expression" - */ - close(1); - dup(sync_pipe[WRITE]); - close(sync_pipe[READ]); - execvp(ethereal_path, argv); - snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s", - ethereal_path, strerror(errno)); - sync_pipe_errmsg_to_parent(errmsg); - - /* Exit with "_exit()", so that we don't close the connection - to the X server (and cause stuff buffered up by our parent but - not yet sent to be sent, as that stuff should only be sent by - our parent). */ - _exit(2); - } -#endif - - /* Parent process - read messages from the child process over the - sync pipe. */ - g_free(argv); /* free up arg array */ - - /* Close the write side of the pipe, so that only the child has it - open, and thus it completely closes, and thus returns to us - an EOF indication, if the child closes it (either deliberately - or by exiting abnormally). */ - close(sync_pipe[WRITE]); - - /* Close the save file FD, as we won't be using it - we'll be opening - it and reading the save file through Wiretap. */ - close(cfile.save_file_fd); - - if (fork_child == -1) { - /* We couldn't even create the child process. */ - error = errno; - close(sync_pipe[READ]); - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Couldn't create child process: %s", strerror(error)); - return FALSE; - } - - /* Read a byte count from "sync_pipe[READ]", terminated with a - colon; if the count is 0, the child process created the - capture file and we should start reading from it, otherwise - the capture couldn't start and the count is a count of bytes - of error message, and we should display the message. */ - byte_count = 0; - for (;;) { - i = read(sync_pipe[READ], &c, 1); - if (i == 0) { - /* EOF - the child process died. - Close the read side of the sync pipe, remove the capture file, - and report the failure. */ - close(sync_pipe[READ]); - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - sync_pipe_wait_for_child(TRUE); - return FALSE; - } - if (c == SP_CAPSTART || c == SP_ERROR_MSG) - break; - if (!isdigit(c)) { - /* Child process handed us crap. - Close the read side of the sync pipe, remove the capture file, - and report the failure. */ - close(sync_pipe[READ]); - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Capture child process sent us a bad message"); - return FALSE; - } - byte_count = byte_count*10 + c - '0'; - } - if (c != SP_CAPSTART) { - /* Failure - the child process sent us a message indicating - what the problem was. */ - if (byte_count == 0) { - /* Zero-length message? */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Capture child process failed, but its error message was empty."); - } else { - msg = g_malloc(byte_count + 1); - if (msg == NULL) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Capture child process failed, but its error message was too big."); - } else { - i = read(sync_pipe[READ], msg, byte_count); - msg[byte_count] = '\0'; - if (i < 0) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Capture child process failed: Error %s reading its error message.", - strerror(errno)); - } else if (i == 0) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Capture child process failed: EOF reading its error message."); - sync_pipe_wait_for_child(FALSE); - } else - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg); - g_free(msg); - } - - /* Close the sync pipe. */ - close(sync_pipe[READ]); - - /* Get rid of the save file - the capture never started. */ - unlink(cfile.save_file); - g_free(cfile.save_file); - cfile.save_file = NULL; - } - return FALSE; - } - - /* The child process started a capture. - Attempt to open the capture file and set up to read it. */ - err = cf_start_tail(cfile.save_file, is_tempfile, &cfile); - if (err != 0) { - /* We weren't able to open the capture file; user has been - alerted. Close the sync pipe. */ - - close(sync_pipe[READ]); - - /* Don't unlink the save file - leave it around, for debugging - purposes. */ - g_free(cfile.save_file); - cfile.save_file = NULL; - return FALSE; - } - /* We were able to open and set up to read the capture file; - arrange that our callback be called whenever it's possible - to read from the sync pipe, so that it's called when - the child process wants to tell us something. */ - pipe_input_set_handler(sync_pipe[READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb); - - return TRUE; -} - - -/* There's stuff to read from the sync pipe, meaning the child has sent - us a message, or the sync pipe has closed, meaning the child has - closed it (perhaps because it exited). */ -static gboolean -sync_pipe_input_cb(gint source, gpointer user_data) -{ - capture_file *cf = (capture_file *)user_data; -#define BUFSIZE 4096 - char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r; - int nread, msglen, chars_to_copy; - int to_read = 0; - int err; - - - if ((nread = read(source, buffer, BUFSIZE)) <= 0) { - /* The child has closed the sync pipe, meaning it's not going to be - capturing any more packets. Pick up its exit status, and - complain if it did anything other than exit with status 0. */ - sync_pipe_wait_for_child(FALSE); - - /* Read what remains of the capture file, and finish the capture. - XXX - do something if this fails? */ - switch (cf_finish_tail(cf, &err)) { - - case READ_SUCCESS: - if(cf->count == 0) { - simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, - "%sNo packets captured!%s\n\n" - "As no data was captured, closing the %scapture file!", - simple_dialog_primary_start(), simple_dialog_primary_end(), - (cf->is_tempfile) ? "temporary " : ""); - cf_close(cf); - } - break; - case READ_ERROR: - /* Just because we got an error, that doesn't mean we were unable - to read any of the file; we handle what we could get from the - file. */ - break; - - case READ_ABORTED: - /* Exit by leaving the main loop, so that any quit functions - we registered get called. */ - main_window_quit(); - return FALSE; - } - - /* We're not doing a capture any more, so we don't have a save - file. */ - g_free(cf->save_file); - cf->save_file = NULL; - - return FALSE; - } - - buffer[nread] = '\0'; - - while (nread != 0) { - /* look for (possibly multiple) indications */ - switch (*q) { - case SP_PACKET_COUNT : - to_read += atoi(p); - p = q + 1; - q++; - nread--; - break; - case SP_DROPS : - cf->drops_known = TRUE; - cf->drops = atoi(p); - p = q + 1; - q++; - nread--; - break; - case SP_ERROR_MSG : - msglen = atoi(p); - p = q + 1; - q++; - nread--; - - /* Read the entire message. - XXX - if the child hasn't sent it all yet, this could cause us - to hang until they do. */ - msg = g_malloc(msglen + 1); - r = msg; - while (msglen != 0) { - if (nread == 0) { - /* Read more. */ - if ((nread = read(source, buffer, BUFSIZE)) <= 0) - break; - p = buffer; - q = buffer; - } - chars_to_copy = MIN(msglen, nread); - memcpy(r, q, chars_to_copy); - r += chars_to_copy; - q += chars_to_copy; - nread -= chars_to_copy; - msglen -= chars_to_copy; - } - *r = '\0'; - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg); - g_free(msg); - break; - default : - q++; - nread--; - break; - } - } - - /* Read from the capture file the number of records the child told us - it added. - XXX - do something if this fails? */ - switch (cf_continue_tail(cf, to_read, &err)) { - - case READ_SUCCESS: - case READ_ERROR: - /* Just because we got an error, that doesn't mean we were unable - to read any of the file; we handle what we could get from the - file. - - XXX - abort on a read error? */ - break; - - case READ_ABORTED: - /* Kill the child capture process; the user wants to exit, and we - shouldn't just leave it running. */ - kill_capture_child(); - break; - } - - return TRUE; -} - -static void -sync_pipe_wait_for_child(gboolean always_report) -{ - int wstatus; - -#ifdef _WIN32 - /* XXX - analyze the wait status and display more information - in the dialog box? - XXX - set "fork_child" to -1 if we find it exited? */ - if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process stopped unexpectedly"); - } -#else - if (wait(&wstatus) != -1) { - if (WIFEXITED(wstatus)) { - /* The child exited; display its exit status, if it's not zero, - and even if it's zero if "always_report" is true. */ - if (always_report || WEXITSTATUS(wstatus) != 0) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process exited: exit status %d", - WEXITSTATUS(wstatus)); - } - } else if (WIFSTOPPED(wstatus)) { - /* It stopped, rather than exiting. "Should not happen." */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process stopped: %s", - sync_pipe_signame(WSTOPSIG(wstatus))); - } else if (WIFSIGNALED(wstatus)) { - /* It died with a signal. */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process died: %s%s", - sync_pipe_signame(WTERMSIG(wstatus)), - WCOREDUMP(wstatus) ? " - core dumped" : ""); - } else { - /* What? It had to either have exited, or stopped, or died with - a signal; what happened here? */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process died: wait status %#o", wstatus); - } - } - - /* No more child process. */ - fork_child = -1; -#endif -} - -static void -sync_pipe_errmsg_to_parent(const char *errmsg) -{ - int msglen = strlen(errmsg); - char lenbuf[SP_DECISIZE+1+1]; - - sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG); - write(1, lenbuf, strlen(lenbuf)); - write(1, errmsg, msglen); -} - -static void -sync_pipe_drops_to_parent(int drops) -{ - char tmp[SP_DECISIZE+1+1]; - sprintf(tmp, "%d%c", drops, SP_DROPS); - write(1, tmp, strlen(tmp)); -} - -static void -sync_pipe_packet_count_to_parent(int packet_count) -{ - char tmp[SP_DECISIZE+1+1]; - sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT); - write(1, tmp, strlen(tmp)); -} - -static void -sync_pipe_capstart_to_parent(void) -{ - static const char capstart_msg = SP_CAPSTART; - - write(1, &capstart_msg, 1); -} - -#ifndef _WIN32 -static char * -sync_pipe_signame(int sig) -{ - char *sigmsg; - static char sigmsg_buf[6+1+3+1]; - - switch (sig) { - - case SIGHUP: - sigmsg = "Hangup"; - break; - - case SIGINT: - sigmsg = "Interrupted"; - break; - - case SIGQUIT: - sigmsg = "Quit"; - break; - - case SIGILL: - sigmsg = "Illegal instruction"; - break; - - case SIGTRAP: - sigmsg = "Trace trap"; - break; - - case SIGABRT: - sigmsg = "Abort"; - break; - - case SIGFPE: - sigmsg = "Arithmetic exception"; - break; - - case SIGKILL: - sigmsg = "Killed"; - break; - - case SIGBUS: - sigmsg = "Bus error"; - break; - - case SIGSEGV: - sigmsg = "Segmentation violation"; - break; - - /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO - Linux is POSIX compliant. These are not POSIX-defined signals --- - ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez: - - ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS - were omitted from POSIX.1 because their behavior is - implementation dependent and could not be adequately catego- - rized. Conforming implementations may deliver these sig- - nals, but must document the circumstances under which they - are delivered and note any restrictions concerning their - delivery.'' - - So we only check for SIGSYS on those systems that happen to - implement them (a system can be POSIX-compliant and implement - them, it's just that POSIX doesn't *require* a POSIX-compliant - system to implement them). - */ - -#ifdef SIGSYS - case SIGSYS: - sigmsg = "Bad system call"; - break; -#endif - - case SIGPIPE: - sigmsg = "Broken pipe"; - break; - - case SIGALRM: - sigmsg = "Alarm clock"; - break; - - case SIGTERM: - sigmsg = "Terminated"; - break; - - default: - sprintf(sigmsg_buf, "Signal %d", sig); - sigmsg = sigmsg_buf; - break; - } - return sigmsg; -} -#endif - - - - +/* start a normal capture session */ static gboolean normal_do_capture(gboolean is_tempfile) { @@ -2213,24 +1534,9 @@ stop_capture_signal_handler(int signo _U_) void capture_stop(void) { - if (fork_child != -1) { -#ifndef _WIN32 - kill(fork_child, SIGUSR1); -#else - /* XXX: this is not the preferred method of closing a process! - * the clean way would be getting the process id of the child process, - * then getting window handle hWnd of that process (using EnumChildWindows), - * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) - * - * Unfortunately, I don't know how to get the process id from the handle */ - /* Hint: OpenProcess will get an handle from the id, not vice versa :-( - * - * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are - * running in the same console, I don't know if that is true for our case. - * And this also will require to have the process id - */ - TerminateProcess((HANDLE) fork_child, 0); -#endif + + if (capture_opts.sync_mode) { + sync_pipe_stop(); } else { ld.go = FALSE; } @@ -2239,24 +1545,9 @@ capture_stop(void) void kill_capture_child(void) { - if (fork_child != -1) -#ifndef _WIN32 - kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */ -#else - /* XXX: this is not the preferred method of closing a process! - * the clean way would be getting the process id of the child process, - * then getting window handle hWnd of that process (using EnumChildWindows), - * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) - * - * Unfortunately, I don't know how to get the process id from the handle */ - /* Hint: OpenProcess will get an handle from the id, not vice versa :-( - * - * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are - * running in the same console, I don't know if that is true for our case. - * And this also will require to have the process id - */ - TerminateProcess((HANDLE) fork_child, 0); -#endif + if (capture_opts.sync_mode) { + sync_pipe_kill(); + } } /* one packet was captured, process it */ diff --git a/capture_sync.c b/capture_sync.c new file mode 100644 index 0000000000..11d8007177 --- /dev/null +++ b/capture_sync.c @@ -0,0 +1,796 @@ +/* capture_sync.c + * Synchronisation between Ethereal capture parent and child instances + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* With MSVC and a libethereal.dll this file needs to import some variables + in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */ +#define _NEED_VAR_IMPORT_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_LIBPCAP + + +#include <glib.h> +#include <stdio.h> +#include <string.h> + +#include <epan/packet.h> +#include <epan/prefs.h> + +#include "globals.h" + +#include "capture.h" +#include "capture_sync.h" +#include "simple_dialog.h" + +#ifdef _WIN32 +#include "capture-wpcap.h" +#endif +#include "ui_util.h" + +#ifdef HAVE_IO_H +# include <io.h> +#endif + +int fork_child = -1; /* If not -1, in parent, process ID of child */ + +#ifdef _WIN32 +#include <process.h> /* For spawning child process */ +#endif + +/* Win32 needs the O_BINARY flag for open() */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + +#ifndef _WIN32 +static char *sync_pipe_signame(int); +#endif + + +static gboolean sync_pipe_input_cb(gint source, gpointer user_data); +static void sync_pipe_wait_for_child(gboolean always_report); + +/* Size of buffer to hold decimal representation of + signed/unsigned 64-bit int */ +#define SP_DECISIZE 20 + +/* + * Indications sent out on the sync pipe. + */ +#define SP_CAPSTART ';' /* capture start message */ +#define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */ +#define SP_ERROR_MSG '!' /* followed by length of error message that follows */ +#define SP_DROPS '#' /* followed by count of packets dropped in capture */ + + + +/* Add a string pointer to a NULL-terminated array of string pointers. */ +static char ** +sync_pipe_add_arg(char **args, int *argc, char *arg) +{ + /* Grow the array; "*argc" currently contains the number of string + pointers, *not* counting the NULL pointer at the end, so we have + to add 2 in order to get the new size of the array, including the + new pointer and the terminating NULL pointer. */ + args = g_realloc(args, (*argc + 2) * sizeof (char *)); + + /* Stuff the pointer into the penultimate element of the array, which + is the one at the index specified by "*argc". */ + args[*argc] = arg; + + /* Now bump the count. */ + (*argc)++; + + /* We overwrite the NULL pointer; put it back right after the + element we added. */ + args[*argc] = NULL; + + return args; +} + +#ifdef _WIN32 +/* Given a string, return a pointer to a quote-encapsulated version of + the string, so we can pass it as an argument with "spawnvp" even + if it contains blanks. */ +char * +sync_pipe_quote_encapsulate(const char *string) +{ + char *encapsulated_string; + + encapsulated_string = g_new(char, strlen(string) + 3); + sprintf(encapsulated_string, "\"%s\"", string); + return encapsulated_string; +} +#endif + + + +gboolean +sync_pipe_do_capture(gboolean is_tempfile) { + guint byte_count; + int i; + guchar c; + char *msg; + int err; + char ssnap[24]; + char scount[24]; /* need a constant for len of numbers */ + char sautostop_filesize[24]; /* need a constant for len of numbers */ + char sautostop_duration[24]; /* need a constant for len of numbers */ + char save_file_fd[24]; +#ifndef _WIN32 + char errmsg[1024+1]; +#endif + int error; + int argc; + char **argv; +#ifdef _WIN32 + char sync_pipe_fd[24]; + char *fontstring; + char *filterstring; +#endif + enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */ + int sync_pipe[2]; /* pipes used to sync between instances */ + + + fork_child = -1; + + /* Allocate the string pointer array with enough space for the + terminating NULL pointer. */ + argc = 0; + argv = g_malloc(sizeof (char *)); + *argv = NULL; + + /* Now add those arguments used on all platforms. */ + argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME); + + argv = sync_pipe_add_arg(argv, &argc, "-i"); + argv = sync_pipe_add_arg(argv, &argc, cfile.iface); + + argv = sync_pipe_add_arg(argv, &argc, "-w"); + argv = sync_pipe_add_arg(argv, &argc, cfile.save_file); + + argv = sync_pipe_add_arg(argv, &argc, "-W"); + sprintf(save_file_fd,"%d",cfile.save_file_fd); /* in lieu of itoa */ + argv = sync_pipe_add_arg(argv, &argc, save_file_fd); + + if (capture_opts.has_autostop_packets) { + argv = sync_pipe_add_arg(argv, &argc, "-c"); + sprintf(scount,"%d",capture_opts.autostop_packets); + argv = sync_pipe_add_arg(argv, &argc, scount); + } + + if (capture_opts.has_snaplen) { + argv = sync_pipe_add_arg(argv, &argc, "-s"); + sprintf(ssnap,"%d",capture_opts.snaplen); + argv = sync_pipe_add_arg(argv, &argc, ssnap); + } + + if (capture_opts.linktype != -1) { + argv = sync_pipe_add_arg(argv, &argc, "-y"); +#ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME + sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts.linktype)); +#else + /* XXX - just treat it as a number */ + sprintf(ssnap,"%d",capture_opts.linktype); +#endif + argv = sync_pipe_add_arg(argv, &argc, ssnap); + } + + if (capture_opts.has_autostop_filesize) { + argv = sync_pipe_add_arg(argv, &argc, "-a"); + sprintf(sautostop_filesize,"filesize:%d",capture_opts.autostop_filesize); + argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize); + } + + if (capture_opts.has_autostop_duration) { + argv = sync_pipe_add_arg(argv, &argc, "-a"); + sprintf(sautostop_duration,"duration:%d",capture_opts.autostop_duration); + argv = sync_pipe_add_arg(argv, &argc, sautostop_duration); + } + + if (!capture_opts.show_info) { + argv = sync_pipe_add_arg(argv, &argc, "-H"); + } + + if (!capture_opts.promisc_mode) + argv = sync_pipe_add_arg(argv, &argc, "-p"); + +#ifdef _WIN32 + /* Create a pipe for the child process */ + + if(_pipe(sync_pipe, 512, O_BINARY) < 0) { + /* Couldn't create the pipe between parent and child. */ + error = errno; + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", + strerror(error)); + return FALSE; + } + + /* Convert font name to a quote-encapsulated string and pass to child */ + argv = sync_pipe_add_arg(argv, &argc, "-m"); + fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME); + argv = sync_pipe_add_arg(argv, &argc, fontstring); + + /* Convert pipe write handle to a string and pass to child */ + argv = sync_pipe_add_arg(argv, &argc, "-Z"); + itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10); + argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd); + + /* Convert filter string to a quote delimited string and pass to child */ + filterstring = NULL; + if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) { + argv = sync_pipe_add_arg(argv, &argc, "-f"); + filterstring = sync_pipe_quote_encapsulate(cfile.cfilter); + argv = sync_pipe_add_arg(argv, &argc, filterstring); + } + + /* Spawn process */ + fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv); + g_free(fontstring); + if (filterstring) { + g_free(filterstring); + } +#else + if (pipe(sync_pipe) < 0) { + /* Couldn't create the pipe between parent and child. */ + error = errno; + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", + strerror(error)); + return FALSE; + } + + argv = sync_pipe_add_arg(argv, &argc, "-m"); + argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME); + + if (cfile.cfilter != NULL && strlen(cfile.cfilter) != 0) { + argv = sync_pipe_add_arg(argv, &argc, "-f"); + argv = sync_pipe_add_arg(argv, &argc, cfile.cfilter); + } + + if ((fork_child = fork()) == 0) { + /* + * Child process - run Ethereal with the right arguments to make + * it just pop up the live capture dialog box and capture with + * the specified capture parameters, writing to the specified file. + * + * args: -i interface specification + * -w file to write + * -W file descriptor to write + * -c count to capture + * -s snaplen + * -m / -b fonts + * -f "filter expression" + */ + close(1); + dup(sync_pipe[PIPE_WRITE]); + close(sync_pipe[PIPE_READ]); + execvp(ethereal_path, argv); + snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s", + ethereal_path, strerror(errno)); + sync_pipe_errmsg_to_parent(errmsg); + + /* Exit with "_exit()", so that we don't close the connection + to the X server (and cause stuff buffered up by our parent but + not yet sent to be sent, as that stuff should only be sent by + our parent). */ + _exit(2); + } +#endif + + /* Parent process - read messages from the child process over the + sync pipe. */ + g_free(argv); /* free up arg array */ + + /* Close the write side of the pipe, so that only the child has it + open, and thus it completely closes, and thus returns to us + an EOF indication, if the child closes it (either deliberately + or by exiting abnormally). */ + close(sync_pipe[PIPE_WRITE]); + + /* Close the save file FD, as we won't be using it - we'll be opening + it and reading the save file through Wiretap. */ + close(cfile.save_file_fd); + + if (fork_child == -1) { + /* We couldn't even create the child process. */ + error = errno; + close(sync_pipe[PIPE_READ]); + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Couldn't create child process: %s", strerror(error)); + return FALSE; + } + + /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a + colon; if the count is 0, the child process created the + capture file and we should start reading from it, otherwise + the capture couldn't start and the count is a count of bytes + of error message, and we should display the message. */ + byte_count = 0; + for (;;) { + i = read(sync_pipe[PIPE_READ], &c, 1); + if (i == 0) { + /* EOF - the child process died. + Close the read side of the sync pipe, remove the capture file, + and report the failure. */ + close(sync_pipe[PIPE_READ]); + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + sync_pipe_wait_for_child(TRUE); + return FALSE; + } + if (c == SP_CAPSTART || c == SP_ERROR_MSG) + break; + if (!isdigit(c)) { + /* Child process handed us crap. + Close the read side of the sync pipe, remove the capture file, + and report the failure. */ + close(sync_pipe[PIPE_READ]); + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Capture child process sent us a bad message"); + return FALSE; + } + byte_count = byte_count*10 + c - '0'; + } + if (c != SP_CAPSTART) { + /* Failure - the child process sent us a message indicating + what the problem was. */ + if (byte_count == 0) { + /* Zero-length message? */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Capture child process failed, but its error message was empty."); + } else { + msg = g_malloc(byte_count + 1); + if (msg == NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Capture child process failed, but its error message was too big."); + } else { + i = read(sync_pipe[PIPE_READ], msg, byte_count); + msg[byte_count] = '\0'; + if (i < 0) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Capture child process failed: Error %s reading its error message.", + strerror(errno)); + } else if (i == 0) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Capture child process failed: EOF reading its error message."); + sync_pipe_wait_for_child(FALSE); + } else + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg); + g_free(msg); + } + + /* Close the sync pipe. */ + close(sync_pipe[PIPE_READ]); + + /* Get rid of the save file - the capture never started. */ + unlink(cfile.save_file); + g_free(cfile.save_file); + cfile.save_file = NULL; + } + return FALSE; + } + + /* The child process started a capture. + Attempt to open the capture file and set up to read it. */ + err = cf_start_tail(cfile.save_file, is_tempfile, &cfile); + if (err != 0) { + /* We weren't able to open the capture file; user has been + alerted. Close the sync pipe. */ + + close(sync_pipe[PIPE_READ]); + + /* Don't unlink the save file - leave it around, for debugging + purposes. */ + g_free(cfile.save_file); + cfile.save_file = NULL; + return FALSE; + } + /* We were able to open and set up to read the capture file; + arrange that our callback be called whenever it's possible + to read from the sync pipe, so that it's called when + the child process wants to tell us something. */ + pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) &cfile, &fork_child, sync_pipe_input_cb); + + return TRUE; +} + + +/* There's stuff to read from the sync pipe, meaning the child has sent + us a message, or the sync pipe has closed, meaning the child has + closed it (perhaps because it exited). */ +static gboolean +sync_pipe_input_cb(gint source, gpointer user_data) +{ + capture_file *cf = (capture_file *)user_data; +#define BUFSIZE 4096 + char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r; + int nread, msglen, chars_to_copy; + int to_read = 0; + int err; + + + if ((nread = read(source, buffer, BUFSIZE)) <= 0) { + /* The child has closed the sync pipe, meaning it's not going to be + capturing any more packets. Pick up its exit status, and + complain if it did anything other than exit with status 0. */ + sync_pipe_wait_for_child(FALSE); + + /* Read what remains of the capture file, and finish the capture. + XXX - do something if this fails? */ + switch (cf_finish_tail(cf, &err)) { + + case READ_SUCCESS: + if(cf->count == 0) { + simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, + "%sNo packets captured!%s\n\n" + "As no data was captured, closing the %scapture file!", + simple_dialog_primary_start(), simple_dialog_primary_end(), + (cf->is_tempfile) ? "temporary " : ""); + cf_close(cf); + } + break; + case READ_ERROR: + /* Just because we got an error, that doesn't mean we were unable + to read any of the file; we handle what we could get from the + file. */ + break; + + case READ_ABORTED: + /* Exit by leaving the main loop, so that any quit functions + we registered get called. */ + main_window_quit(); + return FALSE; + } + + /* We're not doing a capture any more, so we don't have a save + file. */ + g_free(cf->save_file); + cf->save_file = NULL; + + return FALSE; + } + + buffer[nread] = '\0'; + + while (nread != 0) { + /* look for (possibly multiple) indications */ + switch (*q) { + case SP_PACKET_COUNT : + to_read += atoi(p); + p = q + 1; + q++; + nread--; + break; + case SP_DROPS : + cf->drops_known = TRUE; + cf->drops = atoi(p); + p = q + 1; + q++; + nread--; + break; + case SP_ERROR_MSG : + msglen = atoi(p); + p = q + 1; + q++; + nread--; + + /* Read the entire message. + XXX - if the child hasn't sent it all yet, this could cause us + to hang until they do. */ + msg = g_malloc(msglen + 1); + r = msg; + while (msglen != 0) { + if (nread == 0) { + /* Read more. */ + if ((nread = read(source, buffer, BUFSIZE)) <= 0) + break; + p = buffer; + q = buffer; + } + chars_to_copy = MIN(msglen, nread); + memcpy(r, q, chars_to_copy); + r += chars_to_copy; + q += chars_to_copy; + nread -= chars_to_copy; + msglen -= chars_to_copy; + } + *r = '\0'; + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg); + g_free(msg); + break; + default : + q++; + nread--; + break; + } + } + + /* Read from the capture file the number of records the child told us + it added. + XXX - do something if this fails? */ + switch (cf_continue_tail(cf, to_read, &err)) { + + case READ_SUCCESS: + case READ_ERROR: + /* Just because we got an error, that doesn't mean we were unable + to read any of the file; we handle what we could get from the + file. + + XXX - abort on a read error? */ + break; + + case READ_ABORTED: + /* Kill the child capture process; the user wants to exit, and we + shouldn't just leave it running. */ + kill_capture_child(); + break; + } + + return TRUE; +} + +static void +sync_pipe_wait_for_child(gboolean always_report) +{ + int wstatus; + +#ifdef _WIN32 + /* XXX - analyze the wait status and display more information + in the dialog box? + XXX - set "fork_child" to -1 if we find it exited? */ + if (_cwait(&wstatus, fork_child, _WAIT_CHILD) == -1) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Child capture process stopped unexpectedly"); + } +#else + if (wait(&wstatus) != -1) { + if (WIFEXITED(wstatus)) { + /* The child exited; display its exit status, if it's not zero, + and even if it's zero if "always_report" is true. */ + if (always_report || WEXITSTATUS(wstatus) != 0) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Child capture process exited: exit status %d", + WEXITSTATUS(wstatus)); + } + } else if (WIFSTOPPED(wstatus)) { + /* It stopped, rather than exiting. "Should not happen." */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Child capture process stopped: %s", + sync_pipe_signame(WSTOPSIG(wstatus))); + } else if (WIFSIGNALED(wstatus)) { + /* It died with a signal. */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Child capture process died: %s%s", + sync_pipe_signame(WTERMSIG(wstatus)), + WCOREDUMP(wstatus) ? " - core dumped" : ""); + } else { + /* What? It had to either have exited, or stopped, or died with + a signal; what happened here? */ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Child capture process died: wait status %#o", wstatus); + } + } + + /* No more child process. */ + fork_child = -1; +#endif +} + +void +sync_pipe_errmsg_to_parent(const char *errmsg) +{ + int msglen = strlen(errmsg); + char lenbuf[SP_DECISIZE+1+1]; + + sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG); + write(1, lenbuf, strlen(lenbuf)); + write(1, errmsg, msglen); +} + +void +sync_pipe_drops_to_parent(int drops) +{ + char tmp[SP_DECISIZE+1+1]; + sprintf(tmp, "%d%c", drops, SP_DROPS); + write(1, tmp, strlen(tmp)); +} + +void +sync_pipe_packet_count_to_parent(int packet_count) +{ + char tmp[SP_DECISIZE+1+1]; + sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT); + write(1, tmp, strlen(tmp)); +} + +void +sync_pipe_capstart_to_parent(void) +{ + static const char capstart_msg = SP_CAPSTART; + + write(1, &capstart_msg, 1); +} + +#ifndef _WIN32 +static char * +sync_pipe_signame(int sig) +{ + char *sigmsg; + static char sigmsg_buf[6+1+3+1]; + + switch (sig) { + + case SIGHUP: + sigmsg = "Hangup"; + break; + + case SIGINT: + sigmsg = "Interrupted"; + break; + + case SIGQUIT: + sigmsg = "Quit"; + break; + + case SIGILL: + sigmsg = "Illegal instruction"; + break; + + case SIGTRAP: + sigmsg = "Trace trap"; + break; + + case SIGABRT: + sigmsg = "Abort"; + break; + + case SIGFPE: + sigmsg = "Arithmetic exception"; + break; + + case SIGKILL: + sigmsg = "Killed"; + break; + + case SIGBUS: + sigmsg = "Bus error"; + break; + + case SIGSEGV: + sigmsg = "Segmentation violation"; + break; + + /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO + Linux is POSIX compliant. These are not POSIX-defined signals --- + ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez: + + ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS + were omitted from POSIX.1 because their behavior is + implementation dependent and could not be adequately catego- + rized. Conforming implementations may deliver these sig- + nals, but must document the circumstances under which they + are delivered and note any restrictions concerning their + delivery.'' + + So we only check for SIGSYS on those systems that happen to + implement them (a system can be POSIX-compliant and implement + them, it's just that POSIX doesn't *require* a POSIX-compliant + system to implement them). + */ + +#ifdef SIGSYS + case SIGSYS: + sigmsg = "Bad system call"; + break; +#endif + + case SIGPIPE: + sigmsg = "Broken pipe"; + break; + + case SIGALRM: + sigmsg = "Alarm clock"; + break; + + case SIGTERM: + sigmsg = "Terminated"; + break; + + default: + sprintf(sigmsg_buf, "Signal %d", sig); + sigmsg = sigmsg_buf; + break; + } + return sigmsg; +} +#endif + + +void +sync_pipe_stop(void) +{ + if (fork_child != -1) { +#ifndef _WIN32 + kill(fork_child, SIGUSR1); +#else + /* XXX: this is not the preferred method of closing a process! + * the clean way would be getting the process id of the child process, + * then getting window handle hWnd of that process (using EnumChildWindows), + * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) + * + * Unfortunately, I don't know how to get the process id from the handle */ + /* Hint: OpenProcess will get an handle from the id, not vice versa :-( + * + * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are + * running in the same console, I don't know if that is true for our case. + * And this also will require to have the process id + */ + TerminateProcess((HANDLE) fork_child, 0); +#endif + } +} + + +void +sync_pipe_kill(void) +{ + if (fork_child != -1) +#ifndef _WIN32 + kill(fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */ +#else + /* XXX: this is not the preferred method of closing a process! + * the clean way would be getting the process id of the child process, + * then getting window handle hWnd of that process (using EnumChildWindows), + * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0) + * + * Unfortunately, I don't know how to get the process id from the handle */ + /* Hint: OpenProcess will get an handle from the id, not vice versa :-( + * + * Hint: GenerateConsoleCtrlEvent() will only work, if both processes are + * running in the same console, I don't know if that is true for our case. + * And this also will require to have the process id + */ + TerminateProcess((HANDLE) fork_child, 0); +#endif +} + + +#endif /* HAVE_LIBPCAP */ diff --git a/capture_sync.h b/capture_sync.h new file mode 100644 index 0000000000..b82fcd4b4b --- /dev/null +++ b/capture_sync.h @@ -0,0 +1,76 @@ +/* capture_sync.h + * Synchronisation between Ethereal capture parent and child instances + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@ethereal.com> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/** @file + * + * Sync mode capture (internal interface). + * + * Will start a new Ethereal instance which will do the actual capture work. + * This is only used, if the "Update list of packets in real time" option is + * used. + */ + +#ifndef __CAPTURE_SYNC_H__ +#define __CAPTURE_SYNC_H__ + +/** + * Start a new synced capture session. + * Create a capture child which is doing the real capture work. + * + * Most of the parameters are passed through the global capture_opts. + * + * @param is_tempfile TRUE if the current cfile is a tempfile + * @return TRUE if a capture could be started, FALSE if not + */ +extern gboolean +sync_pipe_do_capture(gboolean is_tempfile); + +/** User wants to stop capturing, gracefully close the capture child */ +extern void +sync_pipe_stop(void); + +/** We want to stop the program, just kill the child as soon as possible */ +extern void +sync_pipe_kill(void); + + +/** the child will immediately start capturing, notify the parent */ +extern void +sync_pipe_capstart_to_parent(void); + +/** the child captured some new packets, notify the parent */ +extern void +sync_pipe_packet_count_to_parent(int packet_count); + +/** the child stopped capturing, notify the parent */ +extern void +sync_pipe_drops_to_parent(int drops); + +/** the child encountered an error, notify the parent */ +extern void +sync_pipe_errmsg_to_parent(const char *errmsg); + + +#endif /* capture_sync.h */ |