2 * Synchronisation between Ethereal capture parent and child instances
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
44 #ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
50 * Define various POSIX macros (and, in the case of WCOREDUMP, non-POSIX
51 * macros) on UNIX systems that don't have them.
54 # define WIFEXITED(status) (((status) & 0177) == 0)
57 # define WIFSTOPPED(status) (((status) & 0177) == 0177)
60 # define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
63 # define WEXITSTATUS(status) ((status) >> 8)
66 # define WTERMSIG(status) ((status) & 0177)
69 # define WCOREDUMP(status) ((status) & 0200)
72 # define WSTOPSIG(status) ((status) >> 8)
76 #include <epan/packet.h>
77 #include <epan/prefs.h>
81 #include <epan/filesystem.h>
84 #include "capture_sync.h"
85 #include "simple_dialog.h"
88 #include "capture-wpcap.h"
91 #include "file_util.h"
95 #include <process.h> /* For spawning child process */
100 static const char *sync_pipe_signame(int);
104 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
105 static void sync_pipe_wait_for_child(capture_options *capture_opts);
108 * Maximum length of sync pipe message data. Must be < 2^24, as the
109 * message length is 3 bytes.
110 * XXX - this must be large enough to handle a Really Big Filter
111 * Expression, as the error message for an incorrect filter expression
112 * is a bit larger than the filter expression.
114 #define SP_MAX_MSG_LEN 4096
117 /* write a message to the recipient pipe in the standard format
118 (3 digit message length (excluding length and indicator field),
119 1 byte message indicator and the rest is the message) */
121 pipe_write_block(int pipe, char indicator, int len, const char *msg)
123 guchar header[3+1]; /* indicator + 3-byte len */
126 /*g_warning("write %d enter", pipe);*/
128 g_assert(indicator < '0' || indicator > '9');
129 g_assert(len <= SP_MAX_MSG_LEN);
131 /* write header (indicator + 3-byte len) */
132 header[0] = indicator;
133 header[1] = (len >> 16) & 0xFF;
134 header[2] = (len >> 8) & 0xFF;
135 header[3] = (len >> 0) & 0xFF;
137 ret = write(pipe, header, sizeof header);
142 /* write value (if we have one) */
144 /*g_warning("write %d indicator: %c value len: %u msg: %s", pipe, indicator, len, msg);*/
145 ret = write(pipe, msg, len);
150 /*g_warning("write %d indicator: %c no value", pipe, indicator);*/
153 /*g_warning("write %d leave", pipe);*/
159 sync_pipe_errmsg_to_parent(const char *errmsg)
161 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
163 pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
170 signal_pipe_capquit_to_child(capture_options *capture_opts)
173 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
175 pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, 0, NULL);
181 /* read a message from the sending pipe in the standard format
182 (1-byte message indicator, 3-byte message length (excluding length
183 and indicator field), and the rest is the message) */
185 pipe_read_block(int pipe, char *indicator, int len, char *msg) {
192 /* read header (indicator and 3-byte length) */
196 newly = read(pipe, &header[offset], required);
199 /*g_warning("read %d header empty (capture closed)", pipe);*/
204 /*g_warning("read %d header error: %s", pipe, strerror(errno));*/
212 /* convert header values */
213 *indicator = header[0];
214 required = header[1]<<16 | header[2]<<8 | header[3];
216 /* only indicator with no value? */
218 /*g_warning("read %d indicator: %c empty value", pipe, *indicator);*/
230 newly = read(pipe, &msg[offset], required);
233 /*g_warning("read %d value error, indicator: %u", pipe, *indicator);*/
241 /*g_warning("read %d ok indicator: %c len: %u msg: %s", pipe, *indicator, len, msg);*/
247 /* Add a string pointer to a NULL-terminated array of string pointers. */
249 sync_pipe_add_arg(const char **args, int *argc, const char *arg)
251 /* Grow the array; "*argc" currently contains the number of string
252 pointers, *not* counting the NULL pointer at the end, so we have
253 to add 2 in order to get the new size of the array, including the
254 new pointer and the terminating NULL pointer. */
255 args = g_realloc( (gpointer) args, (*argc + 2) * sizeof (char *));
257 /* Stuff the pointer into the penultimate element of the array, which
258 is the one at the index specified by "*argc". */
261 /* Now bump the count. */
264 /* We overwrite the NULL pointer; put it back right after the
273 #define ARGV_NUMBER_LEN 24
276 sync_pipe_start(capture_options *capture_opts) {
277 char ssnap[ARGV_NUMBER_LEN];
278 char scount[ARGV_NUMBER_LEN];
279 char sfilesize[ARGV_NUMBER_LEN];
280 char sfile_duration[ARGV_NUMBER_LEN];
281 char sring_num_files[ARGV_NUMBER_LEN];
282 char sautostop_files[ARGV_NUMBER_LEN];
283 char sautostop_filesize[ARGV_NUMBER_LEN];
284 char sautostop_duration[ARGV_NUMBER_LEN];
286 char buffer_size[ARGV_NUMBER_LEN];
288 char *savefilestring;
289 HANDLE sync_pipe_read; /* pipe used to send messages from child to parent */
290 HANDLE sync_pipe_write; /* pipe used to send messages from child to parent */
291 HANDLE signal_pipe_read; /* pipe used to send messages from parent to child (currently only stop) */
292 HANDLE signal_pipe_write; /* pipe used to send messages from parent to child (currently only stop) */
293 GString *args = g_string_sized_new(200);
294 SECURITY_ATTRIBUTES sa;
296 PROCESS_INFORMATION pi;
300 int sync_pipe[2]; /* pipe used to send messages from child to parent */
301 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
303 int sync_pipe_read_fd;
310 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_start");
311 capture_opts_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, capture_opts);
313 capture_opts->fork_child = -1;
315 /* Allocate the string pointer array with enough space for the
316 terminating NULL pointer. */
318 argv = g_malloc(sizeof (char *));
321 argv = sync_pipe_add_arg(argv, &argc, "-i");
322 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
324 if (capture_opts->has_snaplen) {
325 argv = sync_pipe_add_arg(argv, &argc, "-s");
326 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->snaplen);
327 argv = sync_pipe_add_arg(argv, &argc, ssnap);
330 if (capture_opts->linktype != -1) {
331 argv = sync_pipe_add_arg(argv, &argc, "-y");
332 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
333 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%s",pcap_datalink_val_to_name(capture_opts->linktype));
335 /* XXX - just treat it as a number */
336 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->linktype);
338 argv = sync_pipe_add_arg(argv, &argc, ssnap);
341 if(capture_opts->multi_files_on) {
342 if (capture_opts->has_autostop_filesize) {
343 argv = sync_pipe_add_arg(argv, &argc, "-b");
344 g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
345 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
348 if (capture_opts->has_file_duration) {
349 argv = sync_pipe_add_arg(argv, &argc, "-b");
350 g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->file_duration);
351 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
354 if (capture_opts->has_ring_num_files) {
355 argv = sync_pipe_add_arg(argv, &argc, "-b");
356 g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
357 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
360 if (capture_opts->has_autostop_files) {
361 argv = sync_pipe_add_arg(argv, &argc, "-a");
362 g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
363 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
366 if (capture_opts->has_autostop_filesize) {
367 argv = sync_pipe_add_arg(argv, &argc, "-a");
368 g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
369 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
373 if (capture_opts->has_autostop_packets) {
374 argv = sync_pipe_add_arg(argv, &argc, "-c");
375 g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
376 argv = sync_pipe_add_arg(argv, &argc, scount);
379 if (capture_opts->has_autostop_duration) {
380 argv = sync_pipe_add_arg(argv, &argc, "-a");
381 g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->autostop_duration);
382 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
385 if (!capture_opts->promisc_mode)
386 argv = sync_pipe_add_arg(argv, &argc, "-p");
388 /* dumpcap should be running in capture child mode (hidden feature) */
390 argv = sync_pipe_add_arg(argv, &argc, "-Z");
393 /* take ethereal's absolute program path and replace ethereal with dumpcap */
394 dirname = get_dirname(g_strdup(ethereal_path));
395 exename = g_strdup_printf("\"%s" G_DIR_SEPARATOR_S "dumpcap\"", dirname);
399 argv = sync_pipe_add_arg(argv, &argc, "-B");
400 g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d",capture_opts->buffer_size);
401 argv = sync_pipe_add_arg(argv, &argc, buffer_size);
403 /* Convert filter string to a quote delimited string and pass to child */
405 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
406 argv = sync_pipe_add_arg(argv, &argc, "-f");
407 filterstring = g_strdup_printf("\"%s\"", capture_opts->cfilter);
408 argv = sync_pipe_add_arg(argv, &argc, filterstring);
411 /* Convert save file name to a quote delimited string and pass to child */
412 savefilestring = NULL;
413 if(capture_opts->save_file) {
414 argv = sync_pipe_add_arg(argv, &argc, "-w");
415 savefilestring = g_strdup_printf("\"%s\"", capture_opts->save_file);
416 argv = sync_pipe_add_arg(argv, &argc, savefilestring);
419 /* init SECURITY_ATTRIBUTES */
420 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
421 sa.bInheritHandle = TRUE;
422 sa.lpSecurityDescriptor = NULL;
424 /* Create a pipe for the child process */
425 /* (inrease this value if you have trouble while fast capture file switches) */
426 if (! CreatePipe(&sync_pipe_read, &sync_pipe_write, &sa, 5120)) {
427 /* Couldn't create the pipe between parent and child. */
428 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
430 g_free( (gpointer) argv);
434 /* Create a pipe for the parent process */
435 if (! CreatePipe(&signal_pipe_read, &signal_pipe_write, &sa, 512)) {
436 /* Couldn't create the signal pipe between parent and child. */
437 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create signal pipe: %s",
439 CloseHandle(sync_pipe_read);
440 CloseHandle(sync_pipe_write);
441 g_free( (gpointer) argv);
445 /* init STARTUPINFO */
446 memset(&si, 0, sizeof(si));
449 si.dwFlags = STARTF_USESHOWWINDOW;
450 si.wShowWindow = SW_SHOW;
452 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
453 si.wShowWindow = SW_HIDE; /* this hides the console window */
454 si.hStdInput = signal_pipe_read;
455 si.hStdOutput = sync_pipe_write;
456 si.hStdError = sync_pipe_write;
459 g_string_append(args, exename);
461 /* convert args array into a single string */
462 /* XXX - could change sync_pipe_add_arg() instead */
463 /* there is a drawback here: the length is internally limited to 1024 bytes */
464 for(i=0; argv[i] != 0; i++) {
465 g_string_append_c(args, ' ');
466 g_string_append(args, argv[i]);
470 if(!CreateProcess(NULL, args->str, NULL, NULL, TRUE,
476 g_error("couldn't open dumpcap.exe!");
478 capture_opts->fork_child = (int) pi.hProcess;
479 g_string_free(args, TRUE);
481 /* associate the operating system filehandle to a C run-time file handle */
482 sync_pipe_read_fd = _open_osfhandle( (long) sync_pipe_read, _O_BINARY);
484 /* associate the operating system filehandle to a C run-time file handle */
485 capture_opts->signal_pipe_write_fd = _open_osfhandle( (long) signal_pipe_write, _O_BINARY);
488 g_free(filterstring);
491 g_free(savefilestring);
494 /* child own's the read side now, close our handle */
495 CloseHandle(signal_pipe_read);
497 if (pipe(sync_pipe) < 0) {
498 /* Couldn't create the pipe between parent and child. */
499 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
505 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
506 argv = sync_pipe_add_arg(argv, &argc, "-f");
507 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
510 if(capture_opts->save_file) {
511 argv = sync_pipe_add_arg(argv, &argc, "-w");
512 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
515 if ((capture_opts->fork_child = fork()) == 0) {
517 * Child process - run Ethereal with the right arguments to make
518 * it just pop up the live capture dialog box and capture with
519 * the specified capture parameters, writing to the specified file.
521 * args: -i interface specification
523 * -c count to capture
526 * -f "filter expression"
529 dup(sync_pipe[PIPE_WRITE]);
530 eth_close(sync_pipe[PIPE_READ]);
531 execvp(exename, argv);
532 g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
533 exename, strerror(errno));
534 sync_pipe_errmsg_to_parent(errmsg);
536 /* Exit with "_exit()", so that we don't close the connection
537 to the X server (and cause stuff buffered up by our parent but
538 not yet sent to be sent, as that stuff should only be sent by
543 sync_pipe_read_fd = sync_pipe[PIPE_READ];
548 /* Parent process - read messages from the child process over the
550 g_free( (gpointer) argv); /* free up arg array */
552 /* Close the write side of the pipe, so that only the child has it
553 open, and thus it completely closes, and thus returns to us
554 an EOF indication, if the child closes it (either deliberately
555 or by exiting abnormally). */
557 CloseHandle(sync_pipe_write);
559 eth_close(sync_pipe[PIPE_WRITE]);
562 if (capture_opts->fork_child == -1) {
563 /* We couldn't even create the child process. */
564 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
565 "Couldn't create child process: %s", strerror(errno));
566 eth_close(sync_pipe_read_fd);
568 eth_close(capture_opts->signal_pipe_write_fd);
573 /* we might wait for a moment till child is ready, so update screen now */
574 main_window_update();
576 /* We were able to set up to read the capture file;
577 arrange that our callback be called whenever it's possible
578 to read from the sync pipe, so that it's called when
579 the child process wants to tell us something. */
581 /* we have a running capture, now wait for the real capture filename */
582 pipe_input_set_handler(sync_pipe_read_fd, (gpointer) capture_opts,
583 &capture_opts->fork_child, sync_pipe_input_cb);
588 /* There's stuff to read from the sync pipe, meaning the child has sent
589 us a message, or the sync pipe has closed, meaning the child has
590 closed it (perhaps because it exited). */
592 sync_pipe_input_cb(gint source, gpointer user_data)
594 capture_options *capture_opts = (capture_options *)user_data;
595 char buffer[SP_MAX_MSG_LEN+1];
600 nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer);
602 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: child has closed sync_pipe");
604 /* The child has closed the sync pipe, meaning it's not going to be
605 capturing any more packets. Pick up its exit status, and
606 complain if it did anything other than exit with status 0. */
607 sync_pipe_wait_for_child(capture_opts);
610 eth_close(capture_opts->signal_pipe_write_fd);
612 capture_input_closed(capture_opts);
618 if(!capture_input_new_file(capture_opts, buffer)) {
619 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
621 /* We weren't able to open the new capture file; user has been
622 alerted. Close the sync pipe. */
625 /* the child has send us a filename which we couldn't open.
626 this probably means, the child is creating files faster than we can handle it.
627 this should only be the case for very fast file switches
628 we can't do much more than telling the child to stop
629 (this is the "emergency brake" if user e.g. wants to switch files every second) */
630 sync_pipe_stop(capture_opts);
633 case SP_PACKET_COUNT:
634 nread = atoi(buffer);
635 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", nread);
636 capture_input_new_packets(capture_opts, nread);
639 capture_input_error_message(capture_opts, buffer);
640 /* the capture child will close the sync_pipe, nothing to do for now */
643 capture_input_drops(capture_opts, atoi(buffer));
646 g_assert_not_reached();
654 /* the child process is going down, wait until it's completely terminated */
656 sync_pipe_wait_for_child(capture_options *capture_opts)
661 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
662 g_assert(capture_opts->fork_child != -1);
665 /* XXX - analyze the wait status and display more information
667 XXX - set "fork_child" to -1 if we find it exited? */
668 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
669 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
670 "Child capture process stopped unexpectedly");
673 if (wait(&wstatus) != -1) {
674 if (WIFEXITED(wstatus)) {
675 /* The child exited; display its exit status, if it seems uncommon (0=ok, 1=error) */
676 /* the child will inform us about errors through the sync_pipe, which will popup */
677 /* an error message, so don't popup another one */
679 /* XXX - if there are situations where the child won't send us such an error message, */
680 /* this should be fixed in the child and not here! */
681 if (WEXITSTATUS(wstatus) != 0 && WEXITSTATUS(wstatus) != 1) {
682 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
683 "Child capture process exited: exit status %d",
684 WEXITSTATUS(wstatus));
686 } else if (WIFSTOPPED(wstatus)) {
687 /* It stopped, rather than exiting. "Should not happen." */
688 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
689 "Child capture process stopped: %s",
690 sync_pipe_signame(WSTOPSIG(wstatus)));
691 } else if (WIFSIGNALED(wstatus)) {
692 /* It died with a signal. */
693 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
694 "Child capture process died: %s%s",
695 sync_pipe_signame(WTERMSIG(wstatus)),
696 WCOREDUMP(wstatus) ? " - core dumped" : "");
698 /* What? It had to either have exited, or stopped, or died with
699 a signal; what happened here? */
700 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
701 "Child capture process died: wait status %#o", wstatus);
705 /* No more child process. */
706 capture_opts->fork_child = -1;
709 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed");
714 /* convert signal to corresponding name */
716 sync_pipe_signame(int sig)
719 static char sigmsg_buf[6+1+3+1];
728 sigmsg = "Interrupted";
736 sigmsg = "Illegal instruction";
740 sigmsg = "Trace trap";
748 sigmsg = "Arithmetic exception";
756 sigmsg = "Bus error";
760 sigmsg = "Segmentation violation";
763 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
764 Linux is POSIX compliant. These are not POSIX-defined signals ---
765 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
767 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
768 were omitted from POSIX.1 because their behavior is
769 implementation dependent and could not be adequately catego-
770 rized. Conforming implementations may deliver these sig-
771 nals, but must document the circumstances under which they
772 are delivered and note any restrictions concerning their
775 So we only check for SIGSYS on those systems that happen to
776 implement them (a system can be POSIX-compliant and implement
777 them, it's just that POSIX doesn't *require* a POSIX-compliant
778 system to implement them).
783 sigmsg = "Bad system call";
788 sigmsg = "Broken pipe";
792 sigmsg = "Alarm clock";
796 sigmsg = "Terminated";
800 /* XXX - returning a static buffer is ok in the context we use it here */
801 g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
810 /* user wants to stop the capture run */
812 sync_pipe_stop(capture_options *capture_opts)
814 /* XXX - in which cases this will be 0? */
815 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
817 /* send the SIGUSR1 signal to close the capture child gracefully. */
818 kill(capture_opts->fork_child, SIGUSR1);
820 /* Win32 doesn't have the kill() system call, use the special signal pipe
821 instead to close the capture child gracefully. */
822 signal_pipe_capquit_to_child(capture_opts);
828 /* Ethereal has to exit, force the capture child to close */
830 sync_pipe_kill(capture_options *capture_opts)
832 /* XXX - in which cases this will be 0? */
833 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
835 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
837 /* XXX: this is not the preferred method of closing a process!
838 * the clean way would be getting the process id of the child process,
839 * then getting window handle hWnd of that process (using EnumChildWindows),
840 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
842 * Unfortunately, I don't know how to get the process id from the
843 * handle. OpenProcess will get an handle (not a window handle)
844 * from the process ID; it will not get a window handle from the
845 * process ID. (How could it? A process can have more than one
848 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
849 * running in the same console; that's not necessarily the case for
850 * us, as we might not be running in a console.
851 * And this also will require to have the process id.
853 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
858 #endif /* HAVE_LIBPCAP */