diff --git a/capture.h b/capture.h index 8ca2a4df47..fcaaf2527a 100644 --- a/capture.h +++ b/capture.h @@ -82,6 +82,9 @@ typedef struct capture_options_tag { /* internally used (don't touch from outside) */ int fork_child; /**< If not -1, in parent, process ID of child */ +#ifdef _WIN32 + int signal_pipe_fd; /**< the pipe to signal the child */ +#endif } capture_options; diff --git a/capture_loop.c b/capture_loop.c index 057596b72b..a78efc20fc 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -1228,6 +1228,23 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct capture_info_update(&capture_ui); } +#if _WIN32 + /* some news from our parent (signal pipe)? -> just stop the capture */ + { + HANDLE handle; + DWORD avail = 0; + gboolean result; + + + handle = (HANDLE) _get_osfhandle (0); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + + if(!result || avail > 0) { + ld.go = FALSE; + } + } +#endif + /* Let the parent process know. */ if (ld.packets_sync_pipe) { /* do sync here */ diff --git a/capture_opts.c b/capture_opts.c index 64a9b85e25..f00f2fc9a8 100644 --- a/capture_opts.c +++ b/capture_opts.c @@ -81,6 +81,9 @@ capture_opts_init(capture_options *capture_opts, void *cfile) capture_opts->fork_child = -1; /* invalid process handle */ +#ifdef _WIN32 + capture_opts->signal_pipe_fd = -1; +#endif } @@ -112,6 +115,9 @@ capture_opts_info(capture_options *capture_opts) { g_warning("AutostopDuration(%u): %u", capture_opts->has_autostop_duration, capture_opts->autostop_duration); g_warning("ForkChild : %d", capture_opts->fork_child); +#ifdef _WIN32 + g_warning("SignalPipeFd : %d", capture_opts->signal_pipe_fd); +#endif } /* @@ -216,13 +222,69 @@ get_ring_arguments(capture_options *capture_opts, const char *appname, const cha } +#ifdef _WIN32 +/* + * Given a string of the form ":", as might appear + * as an argument to a "-Z" option, parse it and set the arguments in + * question. Return an indication of whether it succeeded or failed + * in some fashion. + */ +static gboolean +get_pipe_arguments(capture_options *capture_opts, const char *appname, const char *arg) +{ + gchar *p = NULL, *colonp; + int pipe_fd; + + + colonp = strchr(arg, ':'); + if (colonp == NULL) + return TRUE; + + p = colonp; + *p++ = '\0'; + + /* + * Skip over any white space (there probably won't be any, but + * as we allow it in the preferences file, we might as well + * allow it here). + */ + while (isspace((guchar)*p)) + p++; + if (*p == '\0') { + /* + * Put the colon back, so if our caller uses, in an + * error message, the string they passed us, the message + * looks correct. + */ + *colonp = ':'; + return FALSE; + } + + if (strcmp(arg,"sync") == 0) { + /* associate stdout with sync pipe */ + pipe_fd = get_natural_int(appname, p, "sync pipe file descriptor"); + if (dup2(pipe_fd, 1) < 0) { + fprintf(stderr, "%s: Unable to dup sync pipe handle\n", appname); + return FALSE; + } + } else if (strcmp(arg,"signal") == 0) { + /* associate stdin with signal pipe */ + pipe_fd = get_natural_int(appname, p, "signal pipe file descriptor"); + if (dup2(pipe_fd, 0) < 0) { + fprintf(stderr, "%s: Unable to dup signal pipe handle\n", appname); + return FALSE; + } + } + + *colonp = ':'; /* put the colon back */ + return TRUE; +} +#endif + + void capture_opts_add_opt(capture_options *capture_opts, const char *appname, int opt, const char *optarg, gboolean *start_capture) { -#ifdef _WIN32 - int i; -#endif - switch(opt) { case 'a': /* autostop criteria */ if (set_autostop_criterion(capture_opts, appname, optarg) == FALSE) { @@ -289,10 +351,8 @@ capture_opts_add_opt(capture_options *capture_opts, const char *appname, int opt #ifdef _WIN32 /* Hidden option supporting Sync mode */ case 'Z': /* Write to pipe FD XXX */ - /* associate stdout with pipe */ - i = atoi(optarg); - if (dup2(i, 1) < 0) { - fprintf(stderr, "%s: Unable to dup pipe handle\n", appname); + if (get_pipe_arguments(capture_opts, appname, optarg) == FALSE) { + fprintf(stderr, "%s: Invalid or unknown -Z flag \"%s\"\n", appname, optarg); exit(1); } break; diff --git a/capture_sync.c b/capture_sync.c index 16d74c0b91..4ce506621f 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -173,6 +173,19 @@ sync_pipe_drops_to_parent(int drops) } +#ifdef _WIN32 +#define SP_CAPEND 'q' + +static void +signal_pipe_capend_to_child(capture_options *capture_opts) +{ + static const char capend_msg = SP_CAPEND; + + write(capture_opts->signal_pipe_fd, &capend_msg, 1); +} +#endif + + /* Add a string pointer to a NULL-terminated array of string pointers. */ static char ** sync_pipe_add_arg(char **args, int *argc, char *arg) @@ -228,15 +241,17 @@ sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) { char sautostop_duration[ARGV_NUMBER_LEN]; #ifdef _WIN32 char sync_pipe_fd[ARGV_NUMBER_LEN]; + char signal_pipe_fd[ARGV_NUMBER_LEN]; char *fontstring; char *filterstring; + int signal_pipe[2]; /* pipe used to send messages from parent to child (currently only stop) */ #else char errmsg[1024+1]; #endif int argc; char **argv; 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 */ + int sync_pipe[2]; /* pipe used to send messages from child to parent */ /*g_warning("sync_pipe_do_capture"); @@ -335,19 +350,38 @@ sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) { /* Couldn't create the pipe between parent and child. */ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", strerror(errno)); + g_free(argv); return FALSE; } + /* Create a pipe for the parent process */ + if(_pipe(signal_pipe, 512, O_BINARY) < 0) { + /* 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)); + close(sync_pipe[PIPE_READ]); + close(sync_pipe[PIPE_WRITE]); + g_free(argv); + return FALSE; + } + + capture_opts->signal_pipe_fd = signal_pipe[PIPE_WRITE]; + /* 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 */ + /* Convert sync 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); + sprintf(sync_pipe_fd,"sync:%d",sync_pipe[PIPE_WRITE]); argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd); + /* Convert signal pipe read handle to a string and pass to child */ + argv = sync_pipe_add_arg(argv, &argc, "-Z"); + sprintf(signal_pipe_fd,"signal:%d",signal_pipe[PIPE_READ]); + argv = sync_pipe_add_arg(argv, &argc, signal_pipe_fd); + /* Convert filter string to a quote delimited string and pass to child */ filterstring = NULL; if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) { @@ -362,11 +396,15 @@ sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) { if (filterstring) { g_free(filterstring); } + + /* child own's the read side now, close our handle */ + close(signal_pipe[PIPE_READ]); #else if (pipe(sync_pipe) < 0) { /* Couldn't create the pipe between parent and child. */ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s", strerror(errno)); + g_free(argv); return FALSE; } @@ -423,13 +461,22 @@ sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create child process: %s", strerror(errno)); close(sync_pipe[PIPE_READ]); +#ifdef _WIN32 + close(signal_pipe[PIPE_WRITE]); +#endif return FALSE; } + /* we might wait for a moment till child is ready, so update screen now */ + main_window_update(); + /* the child have to send us a capture start or error message now */ if(!sync_pipe_input_wait_for_start(capture_opts, sync_pipe[PIPE_READ])) { /* Close the sync pipe. */ close(sync_pipe[PIPE_READ]); +#ifdef _WIN32 + close(signal_pipe[PIPE_WRITE]); +#endif return FALSE; } @@ -547,6 +594,9 @@ sync_pipe_input_cb(gint source, gpointer user_data) 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(capture_opts, FALSE); +#ifdef _WIN32 + close(capture_opts->signal_pipe_fd); +#endif capture_input_closed(capture_opts); return FALSE; } @@ -806,25 +856,9 @@ sync_pipe_stop(capture_options *capture_opts) /* XXX - in which cases this will be 0? */ if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) { #ifndef _WIN32 - kill(capture_opts->fork_child, SIGUSR1); + kill(capture_opts->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. OpenProcess will get an handle (not a window handle) - * from the process ID; it will not get a window handle from the - * process ID. (How could it? A process can have more than one - * window.) - * - * Hint: GenerateConsoleCtrlEvent() will only work if both processes are - * running in the same console; that's not necessarily the case for - * us, as we might not be running in a console. - * And this also will require to have the process id. - */ - TerminateProcess((HANDLE) (capture_opts->fork_child), 0); + signal_pipe_capend_to_child(capture_opts); #endif } }