diff options
author | Gerald Combs <gerald@wireshark.org> | 2007-10-26 16:32:28 +0000 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2007-10-26 16:32:28 +0000 |
commit | 8f052940279d78755869b3bd9a1d91da022975d1 (patch) | |
tree | dd39295013303ddb2873ef04b583ab3d31c51c1b | |
parent | 381c1f1c9ecc1363f632540de214ef5e66a10124 (diff) | |
download | wireshark-8f052940279d78755869b3bd9a1d91da022975d1.tar.gz |
For the Wireshark/TShark -> dumpcap signal pipe on Windows, use a named
pipe instead of stdin. Add an argument (currently the parent PID) back
to the "-Z" flag and use it to construct the pipe name. This lets us
pass the parent's stdin handle to dumpcap, which lets us capture from
stdin on Windows. Add a comment about checking for the parent process.
In capture_loop.c, remove the wait_forever argument from cap_pipe_select()
since it was always FALSE. Set the timeout under Windows to 250 ms
instead of 250000 ms.
svn path=/trunk/; revision=23279
-rw-r--r-- | Makefile.nmake | 4 | ||||
-rw-r--r-- | capture_loop.c | 25 | ||||
-rw-r--r-- | capture_sync.c | 31 | ||||
-rw-r--r-- | capture_sync.h | 2 | ||||
-rw-r--r-- | dumpcap.c | 52 |
5 files changed, 80 insertions, 34 deletions
diff --git a/Makefile.nmake b/Makefile.nmake index 0c9f126603..83751d57f2 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -274,10 +274,10 @@ randpkt.exe : $(randpkt_OBJECTS) getopt.obj mt.exe -nologo -manifest "randpkt.exe.manifest" -outputresource:randpkt.exe;1 !ENDIF -dumpcap.exe : $(LIBS_CHECK) config.h svnversion.h $(dumpcap_OBJECTS) getopt.obj inet_ntop.obj mkstemp.obj wiretap\wiretap-$(WTAP_VERSION).lib image\dumpcap.res +dumpcap.exe : $(LIBS_CHECK) config.h svnversion.h $(dumpcap_OBJECTS) getopt.obj epan/unicode-utils.obj inet_ntop.obj mkstemp.obj wiretap\wiretap-$(WTAP_VERSION).lib image\dumpcap.res @echo Linking $@ $(LINK) @<< - /OUT:dumpcap.exe $(conflags) $(conlibsdll) $(LDFLAGS) /SUBSYSTEM:console $(dumpcap_LIBS) $(dumpcap_OBJECTS) getopt.obj inet_ntop.obj mkstemp.obj image\dumpcap.res + /OUT:dumpcap.exe $(conflags) $(conlibsdll) $(LDFLAGS) /SUBSYSTEM:console $(dumpcap_LIBS) $(dumpcap_OBJECTS) getopt.obj epan/unicode-utils.obj inet_ntop.obj mkstemp.obj image\dumpcap.res << !IF "$(MSVC_VARIANT)" == "MSVC2005" || "$(MSVC_VARIANT)" == "MSVC2005EE" || "$(MSVC_VARIANT)" == "DOTNET20" mt.exe -nologo -manifest "dumpcap.exe.manifest" -outputresource:dumpcap.exe;1 diff --git a/capture_loop.c b/capture_loop.c index 8493302087..de9538f9a3 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -156,7 +156,7 @@ cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcapr * the string cap_pipe_err_str should be used instead of errno. */ static int -cap_pipe_select(int pipe_fd, gboolean wait_forever) { +cap_pipe_select(int pipe_fd) { #ifndef _WIN32 fd_set rfds; struct timeval timeout, *pto; @@ -166,13 +166,11 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) { FD_ZERO(&rfds); FD_SET(pipe_fd, &rfds); - if (wait_forever) { - pto = NULL; - } else { - timeout.tv_sec = 0; - timeout.tv_usec = CAP_READ_TIMEOUT * 1000; - pto = &timeout; - } + + timeout.tv_sec = 0; + timeout.tv_usec = CAP_READ_TIMEOUT * 1000; + pto = &timeout; + sel_ret = select(pipe_fd+1, &rfds, NULL, NULL, pto); if (sel_ret < 0) cap_pipe_err_str = strerror(errno); @@ -185,7 +183,6 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) { */ HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd); wchar_t *err_str; - DWORD timeout = wait_forever ? INFINITE : CAP_READ_TIMEOUT * 1000; DWORD wait_ret; if (hPipe == INVALID_HANDLE_VALUE) { @@ -195,7 +192,7 @@ cap_pipe_select(int pipe_fd, gboolean wait_forever) { cap_pipe_err_str = "Unknown error"; - wait_ret = WaitForSingleObject(hPipe, timeout); + wait_ret = WaitForSingleObject(hPipe, CAP_READ_TIMEOUT); switch (wait_ret) { /* XXX - This probably isn't correct */ case WAIT_ABANDONED: @@ -374,7 +371,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld, /* read the pcap header */ bytes_read = 0; while (bytes_read < sizeof magic) { - sel_ret = cap_pipe_select(fd, FALSE); + sel_ret = cap_pipe_select(fd); if (sel_ret < 0) { g_snprintf(errmsg, errmsgl, "Unexpected error from select: %s", strerror(errno)); @@ -429,7 +426,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld, /* Read the rest of the header */ bytes_read = 0; while (bytes_read < sizeof(struct pcap_hdr)) { - sel_ret = cap_pipe_select(fd, FALSE); + sel_ret = cap_pipe_select(fd); if (sel_ret < 0) { g_snprintf(errmsg, errmsgl, "Unexpected error from select: %s", strerror(errno)); @@ -962,7 +959,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld, #ifdef LOG_CAPTURE_VERBOSE g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from capture pipe"); #endif - sel_ret = cap_pipe_select(ld->cap_pipe_fd, FALSE); + sel_ret = cap_pipe_select(ld->cap_pipe_fd); if (sel_ret <= 0) { inpkts = 0; if (sel_ret < 0 && errno != EINTR) { @@ -1002,7 +999,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld, g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch with select"); #endif if (ld->pcap_fd != -1) { - sel_ret = cap_pipe_select(ld->pcap_fd, FALSE); + sel_ret = cap_pipe_select(ld->pcap_fd); if (sel_ret > 0) { /* * "select()" says we can read from it without blocking; go for diff --git a/capture_sync.c b/capture_sync.c index 1a9723344f..9c840ea264 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -254,14 +254,15 @@ sync_pipe_start(capture_options *capture_opts) { char buffer_size[ARGV_NUMBER_LEN]; HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */ HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */ - HANDLE signal_pipe_read; /* pipe used to send messages from parent to child (currently only stop) */ - HANDLE signal_pipe_write; /* pipe used to send messages from parent to child (currently only stop) */ + HANDLE signal_pipe; /* named pipe used to send messages from parent to child (currently only stop) */ GString *args = g_string_sized_new(200); gchar *quoted_arg; SECURITY_ATTRIBUTES sa; STARTUPINFO si; PROCESS_INFORMATION pi; int i; + char control_id[ARGV_NUMBER_LEN]; + gchar *signal_pipe_name; #else char errmsg[1024+1]; int sync_pipe[2]; /* pipe used to send messages from child to parent */ @@ -354,6 +355,12 @@ sync_pipe_start(capture_options *capture_opts) { /* dumpcap should be running in capture child mode (hidden feature) */ #ifndef DEBUG_CHILD argv = sync_pipe_add_arg(argv, &argc, "-Z"); +#ifdef _WIN32 + g_snprintf(control_id, ARGV_NUMBER_LEN, "%d", GetCurrentProcessId()); + argv = sync_pipe_add_arg(argv, &argc, control_id); +#else + argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE); +#endif #endif #ifdef _WIN32 @@ -389,13 +396,16 @@ sync_pipe_start(capture_options *capture_opts) { return FALSE; } - /* Create a pipe for the parent process */ - if (! CreatePipe(&signal_pipe_read, &signal_pipe_write, &sa, 512)) { + /* Create the signal pipe */ + signal_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, control_id); + signal_pipe = CreateNamedPipe(utf_8to16(signal_pipe_name), + PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 65535, 65535, 0, NULL); + g_free(signal_pipe_name); + + if (signal_pipe == INVALID_HANDLE_VALUE) { /* Couldn't create the signal pipe between parent and child. */ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create signal pipe: %s", strerror(errno)); - CloseHandle(sync_pipe_read); - CloseHandle(sync_pipe_write); g_free( (gpointer) argv[0]); g_free( (gpointer) argv); return FALSE; @@ -410,7 +420,7 @@ sync_pipe_start(capture_options *capture_opts) { #else si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; /* this hides the console window */ - si.hStdInput = signal_pipe_read; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = sync_pipe_write; /*si.hStdError = (HANDLE) _get_osfhandle(2);*/ @@ -446,10 +456,8 @@ sync_pipe_start(capture_options *capture_opts) { sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY); /* associate the operating system filehandle to a C run-time file handle */ - capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe_write, _O_BINARY); + capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe, _O_BINARY); - /* child owns the read side now, close our handle */ - CloseHandle(signal_pipe_read); #else /* _WIN32 */ if (pipe(sync_pipe) < 0) { /* Couldn't create the pipe between parent and child. */ @@ -804,6 +812,7 @@ sync_interface_list_open(gchar **msg) { /* dumpcap should be running in capture child mode (hidden feature) */ #ifndef DEBUG_CHILD argv = sync_pipe_add_arg(argv, &argc, "-Z"); + argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE); #endif return sync_pipe_run_command(argv, msg); @@ -843,6 +852,7 @@ sync_linktype_list_open(gchar *ifname, gchar **msg) { /* dumpcap should be running in capture child mode (hidden feature) */ #ifndef DEBUG_CHILD argv = sync_pipe_add_arg(argv, &argc, "-Z"); + argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE); #endif return sync_pipe_run_command(argv, msg); @@ -880,6 +890,7 @@ sync_interface_stats_open(int *read_fd, int *fork_child, gchar **msg) { /* dumpcap should be running in capture child mode (hidden feature) */ #ifndef DEBUG_CHILD argv = sync_pipe_add_arg(argv, &argc, "-Z"); + argv = sync_pipe_add_arg(argv, &argc, SIGNAL_PIPE_CTRL_ID_NONE); #endif return sync_pipe_open_command(argv, read_fd, fork_child, msg); diff --git a/capture_sync.h b/capture_sync.h index a0a9f55185..46eff4a715 100644 --- a/capture_sync.h +++ b/capture_sync.h @@ -58,9 +58,11 @@ extern void sync_pipe_kill(int fork_child); /** Has the parent signalled the child to stop? */ +#define SIGNAL_PIPE_CTRL_ID_NONE "none" #ifdef _WIN32 extern gboolean signal_pipe_check_running(void); +#define SIGNAL_PIPE_FORMAT "\\\\.\\pipe\\wireshark.%s.signal" #endif /** Get an interface list using dumpcap */ @@ -55,6 +55,10 @@ #include "capture-wpcap.h" #endif +#ifdef _WIN32 +#include "epan/unicode-utils.h" +#endif + #include "sync_pipe.h" #include "capture.h" @@ -70,6 +74,10 @@ /*#define DEBUG_DUMPCAP*/ gboolean capture_child = FALSE; /* FALSE: standalone call, TRUE: this is an Wireshark capture child */ +#ifdef _WIN32 +gchar *sig_pipe_name = NULL; +HANDLE sig_pipe_handle = NULL; +#endif static void console_log_handler(const char *log_domain, GLogLevelFlags log_level, @@ -253,7 +261,7 @@ main(int argc, char *argv[]) gboolean print_statistics = FALSE; int status, run_once_args = 0; -#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z" +#define OPTSTRING_INIT "a:b:c:Df:hi:LMpSs:vw:y:Z:" #ifdef _WIN32 #define OPTSTRING_WIN32 "B:" @@ -365,6 +373,23 @@ main(int argc, char *argv[]) #ifdef _WIN32 /* set output pipe to binary mode, to avoid ugly text conversions */ _setmode(2, O_BINARY); + /* + * optarg = the control ID, aka the PPID, currently used for the + * signal pipe name. + */ + if (strcmp(optarg, SIGNAL_PIPE_CTRL_ID_NONE) != 0) { + sig_pipe_name = g_strdup_printf(SIGNAL_PIPE_FORMAT, + optarg); + sig_pipe_handle = CreateFile(utf_8to16(sig_pipe_name), + GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (sig_pipe_handle == INVALID_HANDLE_VALUE) { + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, + "Signal pipe: Unable to open %s. Dead parent?", + sig_pipe_name); + exit_main(1); + } + } #endif break; @@ -632,27 +657,38 @@ report_packet_drops(int drops) gboolean signal_pipe_check_running(void) { - /* any news from our parent (stdin)? -> just stop the capture */ - HANDLE handle; + /* any news from our parent? -> just stop the capture */ DWORD avail = 0; gboolean result; - /* if we are running standalone, no check required */ if(!capture_child) { return TRUE; } - handle = (HANDLE) GetStdHandle(STD_INPUT_HANDLE); - result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + if(!sig_pipe_name || !sig_pipe_handle) { + /* This shouldn't happen */ + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, + "Signal pipe: No name or handle"); + return FALSE; + } + + /* + * XXX - We should have the process ID of the parent (from the "-Z" flag) + * at this point. Should we check to see if the parent is still alive, + * e.g. by using OpenProcess? + */ + + result = PeekNamedPipe(sig_pipe_handle, NULL, 0, NULL, &avail, NULL); if(!result || avail > 0) { /* peek failed or some bytes really available */ /* (if not piping from stdin this would fail) */ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, - "Signal pipe: Stop capture"); + "Signal pipe: Stop capture: %s", sig_pipe_name); g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, - "Signal pipe: handle: %x result: %u avail: %u", handle, result, avail); + "Signal pipe: %s (%p) result: %u avail: %u", sig_pipe_name, + sig_pipe_handle, result, avail); return FALSE; } else { /* pipe ok and no bytes available */ |