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);*/
157 /* read a message from the sending pipe in the standard format
158 (1-byte message indicator, 3-byte message length (excluding length
159 and indicator field), and the rest is the message) */
161 pipe_read_block(int pipe, char *indicator, int len, char *msg) {
168 /* read header (indicator and 3-byte length) */
172 newly = read(pipe, &header[offset], required);
175 /*g_warning("read %d header empty (capture closed)", pipe);*/
180 /*g_warning("read %d header error: %s", pipe, strerror(errno));*/
188 /* convert header values */
189 *indicator = header[0];
190 required = header[1]<<16 | header[2]<<8 | header[3];
192 /* only indicator with no value? */
194 /*g_warning("read %d indicator: %c empty value", pipe, *indicator);*/
198 g_assert(required <= len);
204 newly = read(pipe, &msg[offset], required);
207 /*g_warning("read %d value error, indicator: %u", pipe, *indicator);*/
215 /*g_warning("read %d ok indicator: %c len: %u msg: %s", pipe, *indicator, len, msg);*/
220 sync_pipe_packet_count_to_parent(int packet_count)
222 char tmp[SP_DECISIZE+1+1];
224 g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
226 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_packet_count_to_parent: %s", tmp);
228 pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
232 sync_pipe_filename_to_parent(const char *filename)
234 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_filename_to_parent: %s", filename);
236 pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
240 sync_pipe_errmsg_to_parent(const char *errmsg)
242 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
244 pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
248 sync_pipe_drops_to_parent(int drops)
250 char tmp[SP_DECISIZE+1+1];
253 g_snprintf(tmp, sizeof(tmp), "%d", drops);
255 g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_drops_to_parent: %s", tmp);
257 pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
264 signal_pipe_capquit_to_child(capture_options *capture_opts)
267 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
269 pipe_write_block(capture_opts->signal_pipe_fd, SP_QUIT, 0, NULL);
274 /* Add a string pointer to a NULL-terminated array of string pointers. */
276 sync_pipe_add_arg(const char **args, int *argc, const char *arg)
278 /* Grow the array; "*argc" currently contains the number of string
279 pointers, *not* counting the NULL pointer at the end, so we have
280 to add 2 in order to get the new size of the array, including the
281 new pointer and the terminating NULL pointer. */
282 args = g_realloc( (gpointer) args, (*argc + 2) * sizeof (char *));
284 /* Stuff the pointer into the penultimate element of the array, which
285 is the one at the index specified by "*argc". */
288 /* Now bump the count. */
291 /* We overwrite the NULL pointer; put it back right after the
300 #define ARGV_NUMBER_LEN 24
303 sync_pipe_start(capture_options *capture_opts) {
304 char ssnap[ARGV_NUMBER_LEN];
305 char scount[ARGV_NUMBER_LEN];
306 char sfilesize[ARGV_NUMBER_LEN];
307 char sfile_duration[ARGV_NUMBER_LEN];
308 char sring_num_files[ARGV_NUMBER_LEN];
309 char sautostop_files[ARGV_NUMBER_LEN];
310 char sautostop_filesize[ARGV_NUMBER_LEN];
311 char sautostop_duration[ARGV_NUMBER_LEN];
313 char buffer_size[ARGV_NUMBER_LEN];
314 char sync_pipe_fd[ARGV_NUMBER_LEN];
315 char signal_pipe_fd[ARGV_NUMBER_LEN];
317 char *savefilestring;
318 int signal_pipe[2]; /* pipe used to send messages from parent to child (currently only stop) */
324 enum PIPES { PIPE_READ, PIPE_WRITE }; /* Constants 0 and 1 for PIPE_READ and PIPE_WRITE */
325 int sync_pipe[2]; /* pipe used to send messages from child to parent */
328 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_start");
329 capture_opts_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, capture_opts);
331 capture_opts->fork_child = -1;
333 /* Allocate the string pointer array with enough space for the
334 terminating NULL pointer. */
336 argv = g_malloc(sizeof (char *));
339 /* Now add those arguments used on all platforms. */
340 argv = sync_pipe_add_arg(argv, &argc, CHILD_NAME);
342 argv = sync_pipe_add_arg(argv, &argc, "-i");
343 argv = sync_pipe_add_arg(argv, &argc, capture_opts->iface);
345 if (capture_opts->has_snaplen) {
346 argv = sync_pipe_add_arg(argv, &argc, "-s");
347 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->snaplen);
348 argv = sync_pipe_add_arg(argv, &argc, ssnap);
351 if (capture_opts->linktype != -1) {
352 argv = sync_pipe_add_arg(argv, &argc, "-y");
353 #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME
354 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%s",pcap_datalink_val_to_name(capture_opts->linktype));
356 /* XXX - just treat it as a number */
357 g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->linktype);
359 argv = sync_pipe_add_arg(argv, &argc, ssnap);
362 if(capture_opts->multi_files_on) {
363 if (capture_opts->has_autostop_filesize) {
364 argv = sync_pipe_add_arg(argv, &argc, "-b");
365 g_snprintf(sfilesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
366 argv = sync_pipe_add_arg(argv, &argc, sfilesize);
369 if (capture_opts->has_file_duration) {
370 argv = sync_pipe_add_arg(argv, &argc, "-b");
371 g_snprintf(sfile_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->file_duration);
372 argv = sync_pipe_add_arg(argv, &argc, sfile_duration);
375 if (capture_opts->has_ring_num_files) {
376 argv = sync_pipe_add_arg(argv, &argc, "-b");
377 g_snprintf(sring_num_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->ring_num_files);
378 argv = sync_pipe_add_arg(argv, &argc, sring_num_files);
381 if (capture_opts->has_autostop_files) {
382 argv = sync_pipe_add_arg(argv, &argc, "-a");
383 g_snprintf(sautostop_files, ARGV_NUMBER_LEN, "files:%d",capture_opts->autostop_files);
384 argv = sync_pipe_add_arg(argv, &argc, sautostop_files);
387 if (capture_opts->has_autostop_filesize) {
388 argv = sync_pipe_add_arg(argv, &argc, "-a");
389 g_snprintf(sautostop_filesize, ARGV_NUMBER_LEN, "filesize:%d",capture_opts->autostop_filesize);
390 argv = sync_pipe_add_arg(argv, &argc, sautostop_filesize);
394 if (capture_opts->has_autostop_packets) {
395 argv = sync_pipe_add_arg(argv, &argc, "-c");
396 g_snprintf(scount, ARGV_NUMBER_LEN, "%d",capture_opts->autostop_packets);
397 argv = sync_pipe_add_arg(argv, &argc, scount);
400 if (capture_opts->has_autostop_duration) {
401 argv = sync_pipe_add_arg(argv, &argc, "-a");
402 g_snprintf(sautostop_duration, ARGV_NUMBER_LEN, "duration:%d",capture_opts->autostop_duration);
403 argv = sync_pipe_add_arg(argv, &argc, sautostop_duration);
406 if (!capture_opts->promisc_mode)
407 argv = sync_pipe_add_arg(argv, &argc, "-p");
410 /* Create a pipe for the child process */
411 /* (inrease this value if you have trouble while fast capture file switches) */
412 if(_pipe(sync_pipe, 5120, O_BINARY) < 0) {
413 /* Couldn't create the pipe between parent and child. */
414 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
416 g_free( (gpointer) argv);
420 /* Create a pipe for the parent process */
421 if(_pipe(signal_pipe, 512, O_BINARY) < 0) {
422 /* Couldn't create the signal pipe between parent and child. */
423 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create signal pipe: %s",
425 eth_close(sync_pipe[PIPE_READ]);
426 eth_close(sync_pipe[PIPE_WRITE]);
427 g_free( (gpointer) argv);
431 capture_opts->signal_pipe_fd = signal_pipe[PIPE_WRITE];
433 argv = sync_pipe_add_arg(argv, &argc, "-B");
434 g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d",capture_opts->buffer_size);
435 argv = sync_pipe_add_arg(argv, &argc, buffer_size);
437 /* Convert sync pipe write handle to a string and pass to child */
438 argv = sync_pipe_add_arg(argv, &argc, "-Z");
439 g_snprintf(sync_pipe_fd, ARGV_NUMBER_LEN, "sync:%d",sync_pipe[PIPE_WRITE]);
440 argv = sync_pipe_add_arg(argv, &argc, sync_pipe_fd);
442 /* Convert signal pipe read handle to a string and pass to child */
443 argv = sync_pipe_add_arg(argv, &argc, "-Z");
444 g_snprintf(signal_pipe_fd, ARGV_NUMBER_LEN, "signal:%d",signal_pipe[PIPE_READ]);
445 argv = sync_pipe_add_arg(argv, &argc, signal_pipe_fd);
447 /* Convert filter string to a quote delimited string and pass to child */
449 if (capture_opts->cfilter != NULL && strlen(capture_opts->cfilter) != 0) {
450 argv = sync_pipe_add_arg(argv, &argc, "-f");
451 filterstring = g_strdup_printf("\"%s\"", capture_opts->cfilter);
452 argv = sync_pipe_add_arg(argv, &argc, filterstring);
455 /* Convert save file name to a quote delimited string and pass to child */
456 savefilestring = NULL;
457 if(capture_opts->save_file) {
458 argv = sync_pipe_add_arg(argv, &argc, "-w");
459 savefilestring = g_strdup_printf("\"%s\"", capture_opts->save_file);
460 argv = sync_pipe_add_arg(argv, &argc, savefilestring);
466 /* XXX - experiment to use dumpcap as the capture child */
467 /* currently not working, so commented out for now ... */
471 /* take the ethereal programs path and replace ethereal with dumpcap */
472 dirname = get_dirname(g_strdup(ethereal_path));
473 exename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "dumpcap", dirname);
477 capture_opts->fork_child = spawnvp(_P_NOWAIT, exename, argv);
481 capture_opts->fork_child = spawnvp(_P_NOWAIT, ethereal_path, argv);
483 g_free(filterstring);
486 g_free(savefilestring);
489 /* child own's the read side now, close our handle */
490 eth_close(signal_pipe[PIPE_READ]);
492 if (pipe(sync_pipe) < 0) {
493 /* Couldn't create the pipe between parent and child. */
494 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "Couldn't create sync pipe: %s",
500 if (capture_opts->cfilter != NULL && capture_opts->cfilter != 0) {
501 argv = sync_pipe_add_arg(argv, &argc, "-f");
502 argv = sync_pipe_add_arg(argv, &argc, capture_opts->cfilter);
505 if(capture_opts->save_file) {
506 argv = sync_pipe_add_arg(argv, &argc, "-w");
507 argv = sync_pipe_add_arg(argv, &argc, capture_opts->save_file);
510 if ((capture_opts->fork_child = fork()) == 0) {
512 * Child process - run Ethereal with the right arguments to make
513 * it just pop up the live capture dialog box and capture with
514 * the specified capture parameters, writing to the specified file.
516 * args: -i interface specification
518 * -c count to capture
521 * -f "filter expression"
524 dup(sync_pipe[PIPE_WRITE]);
525 eth_close(sync_pipe[PIPE_READ]);
526 execvp(ethereal_path, argv);
527 g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
528 ethereal_path, strerror(errno));
529 sync_pipe_errmsg_to_parent(errmsg);
531 /* Exit with "_exit()", so that we don't close the connection
532 to the X server (and cause stuff buffered up by our parent but
533 not yet sent to be sent, as that stuff should only be sent by
539 /* Parent process - read messages from the child process over the
541 g_free( (gpointer) argv); /* free up arg array */
543 /* Close the write side of the pipe, so that only the child has it
544 open, and thus it completely closes, and thus returns to us
545 an EOF indication, if the child closes it (either deliberately
546 or by exiting abnormally). */
547 eth_close(sync_pipe[PIPE_WRITE]);
549 if (capture_opts->fork_child == -1) {
550 /* We couldn't even create the child process. */
551 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
552 "Couldn't create child process: %s", strerror(errno));
553 eth_close(sync_pipe[PIPE_READ]);
555 eth_close(signal_pipe[PIPE_WRITE]);
560 /* we might wait for a moment till child is ready, so update screen now */
561 main_window_update();
563 /* We were able to set up to read the capture file;
564 arrange that our callback be called whenever it's possible
565 to read from the sync pipe, so that it's called when
566 the child process wants to tell us something. */
568 /* we have a running capture, now wait for the real capture filename */
569 pipe_input_set_handler(sync_pipe[PIPE_READ], (gpointer) capture_opts,
570 &capture_opts->fork_child, sync_pipe_input_cb);
575 /* There's stuff to read from the sync pipe, meaning the child has sent
576 us a message, or the sync pipe has closed, meaning the child has
577 closed it (perhaps because it exited). */
579 sync_pipe_input_cb(gint source, gpointer user_data)
581 capture_options *capture_opts = (capture_options *)user_data;
582 char buffer[SP_MAX_MSG_LEN+1];
587 nread = pipe_read_block(source, &indicator, SP_MAX_MSG_LEN, buffer);
589 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: child has closed sync_pipe");
591 /* The child has closed the sync pipe, meaning it's not going to be
592 capturing any more packets. Pick up its exit status, and
593 complain if it did anything other than exit with status 0. */
594 sync_pipe_wait_for_child(capture_opts);
597 eth_close(capture_opts->signal_pipe_fd);
599 capture_input_closed(capture_opts);
605 if(!capture_input_new_file(capture_opts, buffer)) {
606 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
608 /* We weren't able to open the new capture file; user has been
609 alerted. Close the sync pipe. */
612 /* the child has send us a filename which we couldn't open.
613 this probably means, the child is creating files faster than we can handle it.
614 this should only be the case for very fast file switches
615 we can't do much more than telling the child to stop
616 (this is the "emergency brake" if user e.g. wants to switch files every second) */
617 sync_pipe_stop(capture_opts);
620 case SP_PACKET_COUNT:
621 nread = atoi(buffer);
622 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", nread);
623 capture_input_new_packets(capture_opts, nread);
626 capture_input_error_message(capture_opts, buffer);
627 /* the capture child will close the sync_pipe, nothing to do for now */
630 capture_input_drops(capture_opts, atoi(buffer));
633 g_assert_not_reached();
641 /* the child process is going down, wait until it's completely terminated */
643 sync_pipe_wait_for_child(capture_options *capture_opts)
648 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: wait till child closed");
649 g_assert(capture_opts->fork_child != -1);
652 /* XXX - analyze the wait status and display more information
654 XXX - set "fork_child" to -1 if we find it exited? */
655 if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) {
656 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
657 "Child capture process stopped unexpectedly");
660 if (wait(&wstatus) != -1) {
661 if (WIFEXITED(wstatus)) {
662 /* The child exited; display its exit status, if it seems uncommon (0=ok, 1=error) */
663 /* the child will inform us about errors through the sync_pipe, which will popup */
664 /* an error message, so don't popup another one */
666 /* XXX - if there are situations where the child won't send us such an error message, */
667 /* this should be fixed in the child and not here! */
668 if (WEXITSTATUS(wstatus) != 0 && WEXITSTATUS(wstatus) != 1) {
669 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
670 "Child capture process exited: exit status %d",
671 WEXITSTATUS(wstatus));
673 } else if (WIFSTOPPED(wstatus)) {
674 /* It stopped, rather than exiting. "Should not happen." */
675 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
676 "Child capture process stopped: %s",
677 sync_pipe_signame(WSTOPSIG(wstatus)));
678 } else if (WIFSIGNALED(wstatus)) {
679 /* It died with a signal. */
680 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
681 "Child capture process died: %s%s",
682 sync_pipe_signame(WTERMSIG(wstatus)),
683 WCOREDUMP(wstatus) ? " - core dumped" : "");
685 /* What? It had to either have exited, or stopped, or died with
686 a signal; what happened here? */
687 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
688 "Child capture process died: wait status %#o", wstatus);
692 /* No more child process. */
693 capture_opts->fork_child = -1;
696 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed");
701 /* convert signal to corresponding name */
703 sync_pipe_signame(int sig)
706 static char sigmsg_buf[6+1+3+1];
715 sigmsg = "Interrupted";
723 sigmsg = "Illegal instruction";
727 sigmsg = "Trace trap";
735 sigmsg = "Arithmetic exception";
743 sigmsg = "Bus error";
747 sigmsg = "Segmentation violation";
750 /* http://metalab.unc.edu/pub/Linux/docs/HOWTO/GCC-HOWTO
751 Linux is POSIX compliant. These are not POSIX-defined signals ---
752 ISO/IEC 9945-1:1990 (IEEE Std 1003.1-1990), paragraph B.3.3.1.1 sez:
754 ``The signals SIGBUS, SIGEMT, SIGIOT, SIGTRAP, and SIGSYS
755 were omitted from POSIX.1 because their behavior is
756 implementation dependent and could not be adequately catego-
757 rized. Conforming implementations may deliver these sig-
758 nals, but must document the circumstances under which they
759 are delivered and note any restrictions concerning their
762 So we only check for SIGSYS on those systems that happen to
763 implement them (a system can be POSIX-compliant and implement
764 them, it's just that POSIX doesn't *require* a POSIX-compliant
765 system to implement them).
770 sigmsg = "Bad system call";
775 sigmsg = "Broken pipe";
779 sigmsg = "Alarm clock";
783 sigmsg = "Terminated";
787 /* XXX - returning a static buffer is ok in the context we use it here */
788 g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig);
797 /* user wants to stop the capture run */
799 sync_pipe_stop(capture_options *capture_opts)
801 /* XXX - in which cases this will be 0? */
802 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
804 /* send the SIGUSR1 signal to close the capture child gracefully. */
805 kill(capture_opts->fork_child, SIGUSR1);
807 /* Win32 doesn't have the kill() system call, use the special signal pipe
808 instead to close the capture child gracefully. */
809 signal_pipe_capquit_to_child(capture_opts);
815 /* Ethereal has to exit, force the capture child to close */
817 sync_pipe_kill(capture_options *capture_opts)
819 /* XXX - in which cases this will be 0? */
820 if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) {
822 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */
824 /* XXX: this is not the preferred method of closing a process!
825 * the clean way would be getting the process id of the child process,
826 * then getting window handle hWnd of that process (using EnumChildWindows),
827 * and then do a SendMessage(hWnd, WM_CLOSE, 0, 0)
829 * Unfortunately, I don't know how to get the process id from the
830 * handle. OpenProcess will get an handle (not a window handle)
831 * from the process ID; it will not get a window handle from the
832 * process ID. (How could it? A process can have more than one
835 * Hint: GenerateConsoleCtrlEvent() will only work if both processes are
836 * running in the same console; that's not necessarily the case for
837 * us, as we might not be running in a console.
838 * And this also will require to have the process id.
840 TerminateProcess((HANDLE) (capture_opts->fork_child), 0);
845 #endif /* HAVE_LIBPCAP */