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>
83 #include "capture_sync.h"
84 #include "simple_dialog.h"
87 #include "capture-wpcap.h"
96 #include <process.h> /* For spawning child process */
99 /* Win32 needs the O_BINARY flag for open() */
106 static char *sync_pipe_signame(int);
110 static gboolean sync_pipe_input_cb(gint source, gpointer user_data);
111 static void sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report);
113 /* Size of buffer to hold decimal representation of
114 signed/unsigned 64-bit int */
115 #define SP_DECISIZE 20
118 * Indications sent out on the sync pipe.
120 #define SP_CAPSTART ';' /* capture start message */
121 #define SP_PACKET_COUNT '*' /* followed by count of packets captured since last message */
122 #define SP_ERROR_MSG '!' /* followed by length of error message that follows */
123 #define SP_DROPS '#' /* followed by count of packets dropped in capture */
124 #define SP_FILE ':' /* followed by length of the name of the last opened file that follows */
129 sync_pipe_capstart_to_parent(void)
131 static const char capstart_msg = SP_CAPSTART;
133 write(1, &capstart_msg, 1);
137 sync_pipe_packet_count_to_parent(int packet_count)
139 char tmp[SP_DECISIZE+1+1];
140 sprintf(tmp, "%d%c", packet_count, SP_PACKET_COUNT);
141 write(1, tmp, strlen(tmp));
145 sync_pipe_filename_to_parent(const char *filename)
147 int msglen = strlen(filename);
148 char lenbuf[SP_DECISIZE+1+1];
150 sprintf(lenbuf, "%u%c", msglen, SP_FILE);
151 write(1, lenbuf, strlen(lenbuf));
152 write(1, filename, msglen);
156 sync_pipe_errmsg_to_parent(const char *errmsg)
158 int msglen = strlen(errmsg);
159 char lenbuf[SP_DECISIZE+1+1];
161 sprintf(lenbuf, "%u%c", msglen, SP_ERROR_MSG);
162 write(1, lenbuf, strlen(lenbuf));
163 write(1, errmsg, msglen);
167 sync_pipe_drops_to_parent(int drops)
169 char tmp[SP_DECISIZE+1+1];
170 sprintf(tmp, "%d%c", drops, SP_DROPS);
171 write(1, tmp, strlen(tmp));
175 /* Add a string pointer to a NULL-terminated array of string pointers. */
177 sync_pipe_add_arg(char **args, int *argc, char *arg)
179 /* Grow the array; "*argc" currently contains the number of string
180 pointers, *not* counting the NULL pointer at the end, so we have
181 to add 2 in order to get the new size of the array, including the
182 new pointer and the terminating NULL pointer. */
183 args = g_realloc(args, (*argc + 2) * sizeof (char *));
185 /* Stuff the pointer into the penultimate element of the array, which
186 is the one at the index specified by "*argc". */
189 /* Now bump the count. */
192 /* We overwrite the NULL pointer; put it back right after the
200 /* Given a string, return a pointer to a quote-encapsulated version of
201 the string, so we can pass it as an argument with "spawnvp" even
202 if it contains blanks. */
204 sync_pipe_quote_encapsulate(const char *string)
206 char *encapsulated_string;
208 encapsulated_string = g_new(char, strlen(string) + 3);
209 sprintf(encapsulated_string, "\"%s\"", string);
210 return encapsulated_string;
217 sync_pipe_do_capture(capture_options *capture_opts, gboolean is_tempfile) {
224 char scount[24]; /* need a constant for len of numbers */
225 char sautostop_filesize[24]; /* need a constant for len of numbers */
226 char sautostop_duration[24]; /* need a constant for len of numbers */
227 char save_file_fd_str[24];
235 char sync_pipe_fd[24];
239 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
240 int sync_pipe[2]; /* pipes used to sync between instances */
242 capture_opts->fork_child = -1;
244 /* Allocate the string pointer array with enough space for the
245 terminating NULL pointer. */
247 argv = g_malloc(sizeof (char *));
250 /* Now add those arguments used on all platforms. */
251 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
253 argv = sync_pipe_add_arg(argv, &argc, "-i");
254 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
256 argv = sync_pipe_add_arg(argv, &argc, "-w");
257 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
259 argv = sync_pipe_add_arg(argv, &argc, "-W");
260 sprintf(save_file_fd_str,"%d",capture_opts->save_file_fd); /* in lieu of itoa */
261 argv = sync_pipe_add_arg(argv, &argc, save_file_fd_str);
263 if (capture_opts->has_autostop_packets) {
264 argv = sync_pipe_add_arg(argv, &argc, "-c");
265 sprintf(scount,"%d",capture_opts->autostop_packets);
266 argv = sync_pipe_add_arg(argv, &argc, scount);
269 if (capture_opts->has_snaplen) {
270 argv = sync_pipe_add_arg(argv, &argc, "-s");
271 sprintf(ssnap,"%d",capture_opts->snaplen);
272 argv = sync_pipe_add_arg(argv, &argc, ssnap);
275 if (capture_opts->linktype != -1) {
276 argv = sync_pipe_add_arg(argv, &argc, "-y");
277 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
278 sprintf(ssnap,"%s",pcap_datalink_val_to_name(capture_opts->linktype));
280 /* XXX - just treat it as a number */
281 sprintf(ssnap,"%d",capture_opts->linktype);
283 argv = sync_pipe_add_arg(argv, &argc, ssnap);
286 if (capture_opts->has_autostop_filesize) {
287 argv = sync_pipe_add_arg(argv, &argc, "-a");
288 sprintf(sautostop_filesize,"filesize:%d",capture_opts->autostop_filesize);
289 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
292 if (capture_opts->has_autostop_duration) {
293 argv = sync_pipe_add_arg(argv, &argc, "-a");
294 sprintf(sautostop_duration,"duration:%d",capture_opts->autostop_duration);
295 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
298 if (!capture_opts->show_info) {
299 argv = sync_pipe_add_arg(argv, &argc, "-H");
302 if (!capture_opts->promisc_mode)
303 argv = sync_pipe_add_arg(argv, &argc, "-p");
306 /* Create a pipe for the child process */
308 if(_pipe(sync_pipe, 512, O_BINARY) < 0) {
309 /* Couldn't create the pipe between parent and child. */
311 unlink(capture_opts->save_file);
312 g_free(capture_opts->save_file);
313 capture_opts->save_file = NULL;
314 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
319 /* Convert font name to a quote-encapsulated string and pass to child */
320 argv = sync_pipe_add_arg(argv, &argc, "-m");
321 fontstring = sync_pipe_quote_encapsulate(prefs.PREFS_GUI_FONT_NAME);
322 argv = sync_pipe_add_arg(argv, &argc, fontstring);
324 /* Convert pipe write handle to a string and pass to child */
325 argv = sync_pipe_add_arg(argv, &argc, "-Z");
326 itoa(sync_pipe[PIPE_WRITE], sync_pipe_fd, 10);
327 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
329 /* Convert filter string to a quote delimited string and pass to child */
331 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
332 argv = sync_pipe_add_arg(argv, &argc, "-f");
333 filterstring = sync_pipe_quote_encapsulate(capture_opts->cfilter);
334 argv = sync_pipe_add_arg(argv, &argc, filterstring);
338 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
341 g_free(filterstring);
344 if (pipe(sync_pipe) < 0) {
345 /* Couldn't create the pipe between parent and child. */
347 unlink(capture_opts->save_file);
348 g_free(capture_opts->save_file);
349 capture_opts->save_file = NULL;
350 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
355 argv = sync_pipe_add_arg(argv, &argc, "-m");
356 argv = sync_pipe_add_arg(argv, &argc, prefs.PREFS_GUI_FONT_NAME);
358 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
359 argv = sync_pipe_add_arg(argv, &argc, "-f");
360 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
363 if ((capture_opts->fork_child = fork()) == 0) {
365 * Child process - run Ethereal with the right arguments to make
366 * it just pop up the live capture dialog box and capture with
367 * the specified capture parameters, writing to the specified file.
369 * args: -i interface specification
371 * -W file descriptor to write
372 * -c count to capture
375 * -f "filter expression"
378 dup(sync_pipe[PIPE_WRITE]);
379 close(sync_pipe[PIPE_READ]);
380 execvp(ethereal_path, argv);
381 snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
382 ethereal_path, strerror(errno));
383 sync_pipe_errmsg_to_parent(errmsg);
385 /* Exit with "_exit()", so that we don't close the connection
386 to the X server (and cause stuff buffered up by our parent but
387 not yet sent to be sent, as that stuff should only be sent by
393 /* Parent process - read messages from the child process over the
395 g_free(argv); /* free up arg array */
397 /* Close the write side of the pipe, so that only the child has it
398 open, and thus it completely closes, and thus returns to us
399 an EOF indication, if the child closes it (either deliberately
400 or by exiting abnormally). */
401 close(sync_pipe[PIPE_WRITE]);
403 /* Close the save file FD, as we won't be using it - we'll be opening
404 it and reading the save file through Wiretap. */
405 close(capture_opts->save_file_fd);
407 if (capture_opts->fork_child == -1) {
408 /* We couldn't even create the child process. */
410 close(sync_pipe[PIPE_READ]);
411 unlink(capture_opts->save_file);
412 g_free(capture_opts->save_file);
413 capture_opts->save_file = NULL;
414 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
415 "Couldn't create child process: %s", strerror(error));
419 /* Read a byte count from "sync_pipe[PIPE_READ]", terminated with a
420 colon; if the count is 0, the child process created the
421 capture file and we should start reading from it, otherwise
422 the capture couldn't start and the count is a count of bytes
423 of error message, and we should display the message. */
426 i = read(sync_pipe[PIPE_READ], &c, 1);
428 /* EOF - the child process died.
429 Close the read side of the sync pipe, remove the capture file,
430 and report the failure. */
431 close(sync_pipe[PIPE_READ]);
432 unlink(capture_opts->save_file);
433 g_free(capture_opts->save_file);
434 capture_opts->save_file = NULL;
435 sync_pipe_wait_for_child(capture_opts, TRUE);
438 if (c == SP_CAPSTART || c == SP_ERROR_MSG)
441 /* Child process handed us crap.
442 Close the read side of the sync pipe, remove the capture file,
443 and report the failure. */
444 close(sync_pipe[PIPE_READ]);
445 unlink(capture_opts->save_file);
446 g_free(capture_opts->save_file);
447 capture_opts->save_file = NULL;
448 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
449 "Capture child process sent us a bad message");
452 byte_count = byte_count*10 + c - '0';
454 if (c != SP_CAPSTART) {
455 /* Failure - the child process sent us a message indicating
456 what the problem was. */
457 if (byte_count == 0) {
458 /* Zero-length message? */
459 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
460 "Capture child process failed, but its error message was empty.");
462 msg = g_malloc(byte_count + 1);
464 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
465 "Capture child process failed, but its error message was too big.");
467 i = read(sync_pipe[PIPE_READ], msg, byte_count);
468 msg[byte_count] = '\0';
470 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
471 "Capture child process failed: Error %s reading its error message.",
474 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
475 "Capture child process failed: EOF reading its error message.");
476 sync_pipe_wait_for_child(capture_opts, FALSE);
478 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
482 /* Close the sync pipe. */
483 close(sync_pipe[PIPE_READ]);
485 /* Get rid of the save file - the capture never started. */
486 unlink(capture_opts->save_file);
487 g_free(capture_opts->save_file);
488 capture_opts->save_file = NULL;
493 if(capture_opts->sync_mode) {
494 /* The child process started a capture.
495 Attempt to open the capture file and set up to read it. */
496 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
498 /* We were able to open and set up to read the capture file;
499 arrange that our callback be called whenever it's possible
500 to read from the sync pipe, so that it's called when
501 the child process wants to tell us something. */
502 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
507 /* We weren't able to open the capture file; user has been
508 alerted. Close the sync pipe. */
510 close(sync_pipe[PIPE_READ]);
512 /* Don't unlink the save file - leave it around, for debugging
514 g_free(capture_opts->save_file);
515 capture_opts->save_file = NULL;
520 g_assert_not_reached();
523 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts, &capture_opts->fork_child, sync_pipe_input_cb);
530 sync_pipe_closed(capture_options *capture_opts)
535 /* The child has closed the sync pipe, meaning it's not going to be
536 capturing any more packets. Pick up its exit status, and
537 complain if it did anything other than exit with status 0. */
538 sync_pipe_wait_for_child(capture_opts, FALSE);
540 if(capture_opts->sync_mode) {
541 /* Read what remains of the capture file, and finish the capture.
542 XXX - do something if this fails? */
543 switch (cf_finish_tail(capture_opts->cf, &err)) {
546 if(cf_packet_count(capture_opts->cf) == 0) {
547 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
548 "%sNo packets captured!%s\n\n"
549 "As no data was captured, closing the %scapture file!",
550 simple_dialog_primary_start(), simple_dialog_primary_end(),
551 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
552 cf_close(capture_opts->cf);
556 /* Just because we got an error, that doesn't mean we were unable
557 to read any of the file; we handle what we could get from the
561 case CF_READ_ABORTED:
562 /* Exit by leaving the main loop, so that any quit functions
563 we registered get called. */
567 /* We're not doing a capture any more, so we don't have a save
569 g_free(capture_opts->save_file);
570 capture_opts->save_file = NULL;
572 /* this is a normal mode capture, read in the capture file data */
573 capture_read(capture_opts, cf_is_tempfile(capture_opts->cf), cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
578 /* There's stuff to read from the sync pipe, meaning the child has sent
579 us a message, or the sync pipe has closed, meaning the child has
580 closed it (perhaps because it exited). */
582 sync_pipe_input_cb(gint source, gpointer user_data)
584 capture_options *capture_opts = (capture_options *)user_data;
586 char buffer[BUFSIZE+1], *p = buffer, *q = buffer, *msg, *r;
587 int nread, msglen, chars_to_copy;
592 /* we are a capture parent */
593 g_assert(!capture_opts->capture_child);
595 if ((nread = read(source, buffer, BUFSIZE)) <= 0) {
596 /* The child has closed the sync pipe, meaning it's not going to be
597 capturing any more packets. Pick up its exit status, and
598 complain if it did anything other than exit with status 0. */
599 sync_pipe_closed(capture_opts);
603 buffer[nread] = '\0';
606 /* look for (possibly multiple) indications */
608 case SP_PACKET_COUNT :
615 cf_set_drops_known(capture_opts->cf, TRUE);
616 cf_set_drops(capture_opts->cf, atoi(p));
627 /* Read the entire message.
628 XXX - if the child hasn't sent it all yet, this could cause us
629 to hang until they do. */
630 msg = g_malloc(msglen + 1);
632 while (msglen != 0) {
635 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
640 chars_to_copy = MIN(msglen, nread);
641 memcpy(r, q, chars_to_copy);
644 nread -= chars_to_copy;
645 msglen -= chars_to_copy;
648 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, msg);
657 /* Read the entire message.
658 XXX - if the child hasn't sent it all yet, this could cause us
659 to hang until they do. */
660 msg = g_malloc(msglen + 1);
662 while (msglen != 0) {
665 if ((nread = read(source, buffer, BUFSIZE)) <= 0)
670 chars_to_copy = MIN(msglen, nread);
671 memcpy(r, q, chars_to_copy);
674 nread -= chars_to_copy;
675 msglen -= chars_to_copy;
679 /* currently, both filenames must be equal */
680 /* (this will change, when multiple files together with sync_mode are captured) */
681 g_assert(strcmp(capture_opts->save_file, msg) == 0);
683 /* save the new filename */
684 if(capture_opts->save_file != NULL) {
685 g_free(capture_opts->save_file);
687 capture_opts->save_file = g_strdup(msg);
697 if(capture_opts->sync_mode) {
698 /* Read from the capture file the number of records the child told us
700 XXX - do something if this fails? */
701 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
705 /* Just because we got an error, that doesn't mean we were unable
706 to read any of the file; we handle what we could get from the
709 XXX - abort on a read error? */
712 case CF_READ_ABORTED:
713 /* Kill the child capture process; the user wants to exit, and we
714 shouldn't just leave it running. */
715 capture_kill_child(capture_opts);
724 /* the child process is going down, wait until it's completely terminated */
726 sync_pipe_wait_for_child(capture_options *capture_opts, gboolean always_report)
731 g_assert(capture_opts->fork_child != -1);
734 /* XXX - analyze the wait status and display more information
736 XXX - set "fork_child" to -1 if we find it exited? */
737 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
738 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
739 "Child capture process stopped unexpectedly");
742 if (wait(&wstatus) != -1) {
743 if (WIFEXITED(wstatus)) {
744 /* The child exited; display its exit status, if it's not zero,
745 and even if it's zero if "always_report" is true. */
746 if (always_report || WEXITSTATUS(wstatus) != 0) {
747 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
748 "Child capture process exited: exit status %d",
749 WEXITSTATUS(wstatus));
751 } else if (WIFSTOPPED(wstatus)) {
752 /* It stopped, rather than exiting. "Should not happen." */
753 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
754 "Child capture process stopped: %s",
755 sync_pipe_signame(WSTOPSIG(wstatus)));
756 } else if (WIFSIGNALED(wstatus)) {
757 /* It died with a signal. */
758 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
759 "Child capture process died: %s%s",
760 sync_pipe_signame(WTERMSIG(wstatus)),
761 WCOREDUMP(wstatus) ? " - core dumped" : "");
763 /* What? It had to either have exited, or stopped, or died with
764 a signal; what happened here? */
765 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
766 "Child capture process died: wait status %#o", wstatus);
770 /* No more child process. */
771 capture_opts->fork_child = -1;
778 sync_pipe_signame(int sig)
781 static char sigmsg_buf[6+1+3+1];
790 sigmsg = "Interrupted";
798 sigmsg = "Illegal instruction";
802 sigmsg = "Trace trap";
810 sigmsg = "Arithmetic exception";
818 sigmsg = "Bus error";
822 sigmsg = "Segmentation violation";
825 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
826 Linux is POSIX compliant. These are not POSIX-defined signals ---
827 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
829 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
830 were omitted from POSIX.1 because their behavior is
831 implementation dependent and could not be adequately catego-
832 rized. Conforming implementations may deliver these sig-
833 nals, but must document the circumstances under which they
834 are delivered and note any restrictions concerning their
837 So we only check for SIGSYS on those systems that happen to
838 implement them (a system can be POSIX-compliant and implement
839 them, it's just that POSIX doesn't *require* a POSIX-compliant
840 system to implement them).
845 sigmsg = "Bad system call";
850 sigmsg = "Broken pipe";
854 sigmsg = "Alarm clock";
858 sigmsg = "Terminated";
862 sprintf(sigmsg_buf, "Signal %d", sig);
872 sync_pipe_stop(capture_options *capture_opts)
874 /* XXX - in which cases this will be 0? */
875 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
877 kill(capture_opts->fork_child, SIGUSR1);
879 /* XXX: this is not the preferred method of closing a process!
880 * the clean way would be getting the process id of the child process,
881 * then getting window handle hWnd of that process (using EnumChildWindows),
882 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
884 * Unfortunately, I don't know how to get the process id from the
885 * handle. OpenProcess will get an handle (not a window handle)
886 * from the process ID; it will not get a window handle from the
887 * process ID. (How could it? A process can have more than one
890 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
891 * running in the same console; that's not necessarily the case for
892 * us, as we might not be running in a console.
893 * And this also will require to have the process id.
895 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
902 sync_pipe_kill(capture_options *capture_opts)
904 /* XXX - in which cases this will be 0? */
905 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
907 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
909 /* XXX: this is not the preferred method of closing a process!
910 * the clean way would be getting the process id of the child process,
911 * then getting window handle hWnd of that process (using EnumChildWindows),
912 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
914 * Unfortunately, I don't know how to get the process id from the
915 * handle. OpenProcess will get an handle (not a window handle)
916 * from the process ID; it will not get a window handle from the
917 * process ID. (How could it? A process can have more than one
920 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
921 * running in the same console; that's not necessarily the case for
922 * us, as we might not be running in a console.
923 * And this also will require to have the process id.
925 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
930 #endif /* HAVE_LIBPCAP */