diff options
author | Ulf Lamping <ulf.lamping@web.de> | 2006-03-24 02:23:48 +0000 |
---|---|---|
committer | Ulf Lamping <ulf.lamping@web.de> | 2006-03-24 02:23:48 +0000 |
commit | fe3c3029aaccd6b5a8fe7774d7902188a03c2c94 (patch) | |
tree | 26aaef12624b268826efd4255bc4d8c1f91b1278 /capture_sync.c | |
parent | e43c4e50c901e652ea61d3cf3d8834b384181fc3 (diff) |
Various code cleanup in the capture pipe stuff
svn path=/trunk/; revision=17714
Diffstat (limited to 'capture_sync.c')
-rw-r--r-- | capture_sync.c | 363 |
1 files changed, 140 insertions, 223 deletions
diff --git a/capture_sync.c b/capture_sync.c index 3572023ad8..27fd5b73ac 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -101,7 +101,6 @@ #endif -/*#define DEBUG_DUMPCAP*/ #ifndef _WIN32 static const char *sync_pipe_signame(int); @@ -111,207 +110,10 @@ static const char *sync_pipe_signame(int); static gboolean sync_pipe_input_cb(gint source, gpointer user_data); static void sync_pipe_wait_for_child(capture_options *capture_opts); -/* - * Maximum length of sync pipe message data. Must be < 2^24, as the - * message length is 3 bytes. - * XXX - this must be large enough to handle a Really Big Filter - * Expression, as the error message for an incorrect filter expression - * is a bit larger than the filter expression. - */ -#define SP_MAX_MSG_LEN 4096 - - -/* write a message to the recipient pipe in the standard format - (3 digit message length (excluding length and indicator field), - 1 byte message indicator and the rest is the message). - If msg is NULL, the message has only a length and indicator. - Otherwise, if secondary_msg isn't NULL, send both msg and - secondary_msg as null-terminated strings, otherwise just send - msg as a null-terminated string and follow it with an empty string. */ -static void -pipe_write_block(int pipe, char indicator, const char *msg, - const char *secondary_msg) -{ - guchar header[3+1]; /* indicator + 3-byte len */ - int ret; - size_t len, secondary_len, total_len; - - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d enter", pipe); - - len = 0; - secondary_len = 0; - total_len = 0; - if(msg != NULL) { - len = strlen(msg) + 1; /* include the terminating '\0' */ - total_len = len; - if(secondary_msg == NULL) - secondary_msg = ""; /* default to an empty string */ - secondary_len = strlen(secondary_msg) + 1; - total_len += secondary_len; - } - g_assert(indicator < '0' || indicator > '9'); - g_assert(total_len <= SP_MAX_MSG_LEN); - - /* write header (indicator + 3-byte len) */ - header[0] = indicator; - header[1] = (total_len >> 16) & 0xFF; - header[2] = (total_len >> 8) & 0xFF; - header[3] = (total_len >> 0) & 0xFF; - - ret = write(pipe, header, sizeof header); - if(ret == -1) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING, - "write %d header: error %s", pipe, strerror(errno)); - return; - } - - /* write value (if we have one) */ - if(len) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, - "write %d indicator: %c value len: %lu msg: \"%s\" secondary len: %lu secondary msg: \"%s\"", pipe, indicator, - (unsigned long)len, msg, (unsigned long)secondary_len, - secondary_msg); - ret = write(pipe, msg, len); - if(ret == -1) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING, - "write %d value: error %s", pipe, strerror(errno)); - return; - } - ret = write(pipe, msg, secondary_len); - if(ret == -1) { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING, - "write %d value: error %s", pipe, strerror(errno)); - return; - } - } else { - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, - "write %d indicator: %c no value", pipe, indicator); - } - - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d leave", pipe); -} - - -#ifndef _WIN32 -void -sync_pipe_errmsg_to_parent(const char *error_msg, - const char *secondary_error_msg) -{ - g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", error_msg); - - pipe_write_block(1, SP_ERROR_MSG, error_msg, secondary_error_msg); -} -#endif - - -#ifdef _WIN32 -static void -signal_pipe_capquit_to_child(capture_options *capture_opts) -{ - - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child"); - - pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, NULL, NULL); -} -#endif - -static int -pipe_read_bytes(int pipe, char *bytes, int required) { - int newly; - int offset = 0; - - - while(required) { - newly = read(pipe, &bytes[offset], required); - if (newly == 0) { - /* EOF */ - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read from pipe %d: EOF (capture closed?)", pipe); - return offset; - } - if (newly < 0) { - /* error */ - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read from pipe %d: error(%u): %s", pipe, errno, strerror(errno)); - return newly; - } - - required -= newly; - offset += newly; - } - - return offset; -} - -/* convert header values (indicator and 4-byte length) */ -static void -pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) { - - g_assert(header_len == 4); - - /* convert header values */ - *indicator = header[0]; - *block_len = header[1]<<16 | header[2]<<8 | header[3]; -} - -/* read a message from the sending pipe in the standard format - (1-byte message indicator, 3-byte message length (excluding length - and indicator field), and the rest is the message) */ -static int -pipe_read_block(int pipe, char *indicator, int len, char *msg) { - int required; - int newly; - guchar header[4]; - - - /* read header (indicator and 3-byte length) */ - newly = pipe_read_bytes(pipe, header, 4); - if(newly != 4) { - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read %d failed to read header: %u", pipe, newly); - return -1; - } - - /* convert header values */ - pipe_convert_header(header, 4, indicator, &required); - - /* only indicator with no value? */ - if(required == 0) { - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read %d indicator: %c empty value", pipe, *indicator); - return 4; - } - - /* does the data fit into the given buffer? */ - if(required > len) { - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read %d length error, required %d > len %d, indicator: %u", - pipe, required, len, *indicator); - - /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */ - memcpy(msg, header, sizeof(header)); - newly = read(pipe, &msg[sizeof(header)], len-sizeof(header)); - g_warning("Unknown message from dumpcap, try to show it as a string: %s", msg); - return -1; - } - len = required; - - /* read the actual block data */ - newly = pipe_read_bytes(pipe, msg, required); - if(newly != required) { - g_warning("Unknown message from dumpcap, try to show it as a string: %s", msg); - return -1; - } - - g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, - "read %d ok indicator: %c len: %u msg: %s", pipe, *indicator, - len, msg); - return newly + 4; -} - -/* Add a string pointer to a NULL-terminated array of string pointers. */ +/* Append an arg (realloc) to an argc/argv array */ +/* (add a string pointer to a NULL-terminated array of string pointers) */ static const char ** sync_pipe_add_arg(const char **args, int *argc, const char *arg) { @@ -408,6 +210,7 @@ protect_arg (const gchar *argv) #define ARGV_NUMBER_LEN 24 +/* a new capture run: start a new dumpcap task and hand over parameters through command line */ gboolean sync_pipe_start(capture_options *capture_opts) { char ssnap[ARGV_NUMBER_LEN]; @@ -452,7 +255,7 @@ sync_pipe_start(capture_options *capture_opts) { argv = g_malloc(sizeof (char *)); *argv = NULL; - /* take ethereal's absolute program path and replace ethereal with dumpcap */ + /* take ethereal's absolute program path and replace "ethereal" with "dumpcap" */ exename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "dumpcap", get_progfile_dir()); @@ -473,7 +276,7 @@ sync_pipe_start(capture_options *capture_opts) { #ifdef HAVE_PCAP_DATALINK_VAL_TO_NAME g_snprintf(ssnap, ARGV_NUMBER_LEN, "%s",linktype_val_to_name(capture_opts->linktype)); #else - /* XXX - just treat it as a number */ + /* we can't get the type name, just treat it as a number */ g_snprintf(ssnap, ARGV_NUMBER_LEN, "%d",capture_opts->linktype); #endif argv = sync_pipe_add_arg(argv, &argc, ssnap); @@ -632,13 +435,6 @@ sync_pipe_start(capture_options *capture_opts) { * Child process - run Ethereal with the right arguments to make * it just pop up the live capture dialog box and capture with * the specified capture parameters, writing to the specified file. - * - * args: -i interface specification - * -w file to write - * -c count to capture - * -s snaplen - * -m / -b fonts - * -f "filter expression" */ eth_close(1); dup(sync_pipe[PIPE_WRITE]); @@ -700,6 +496,105 @@ sync_pipe_start(capture_options *capture_opts) { return TRUE; } + + +/* read a number of bytes from a pipe */ +/* (blocks until enough bytes read or an error occurs) */ +static int +pipe_read_bytes(int pipe, char *bytes, int required) { + int newly; + int offset = 0; + + + while(required) { + newly = read(pipe, &bytes[offset], required); + if (newly == 0) { + /* EOF */ + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read from pipe %d: EOF (capture closed?)", pipe); + return offset; + } + if (newly < 0) { + /* error */ + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read from pipe %d: error(%u): %s", pipe, errno, strerror(errno)); + return newly; + } + + required -= newly; + offset += newly; + } + + return offset; +} + +/* convert header values (indicator and 4-byte length) */ +static void +pipe_convert_header(const guchar *header, int header_len, char *indicator, int *block_len) { + + g_assert(header_len == 4); + + /* convert header values */ + *indicator = header[0]; + *block_len = header[1]<<16 | header[2]<<8 | header[3]; +} + +/* read a message from the sending pipe in the standard format + (1-byte message indicator, 3-byte message length (excluding length + and indicator field), and the rest is the message) */ +static int +pipe_read_block(int pipe, char *indicator, int len, char *msg) { + int required; + int newly; + guchar header[4]; + + + /* read header (indicator and 3-byte length) */ + newly = pipe_read_bytes(pipe, header, 4); + if(newly != 4) { + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read %d failed to read header: %u", pipe, newly); + return -1; + } + + /* convert header values */ + pipe_convert_header(header, 4, indicator, &required); + + /* only indicator with no value? */ + if(required == 0) { + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read %d indicator: %c empty value", pipe, *indicator); + return 4; + } + + /* does the data fit into the given buffer? */ + if(required > len) { + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read %d length error, required %d > len %d, indicator: %u", + pipe, required, len, *indicator); + + /* we have a problem here, try to read some more bytes from the pipe to debug where the problem really is */ + memcpy(msg, header, sizeof(header)); + newly = read(pipe, &msg[sizeof(header)], len-sizeof(header)); + g_warning("Unknown message from dumpcap, try to show it as a string: %s", msg); + return -1; + } + len = required; + + /* read the actual block data */ + newly = pipe_read_bytes(pipe, msg, required); + if(newly != required) { + g_warning("Unknown message from dumpcap, try to show it as a string: %s", msg); + return -1; + } + + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, + "read %d ok indicator: %c len: %u msg: %s", pipe, *indicator, + len, msg); + return newly + 4; +} + + /* There's stuff to read from the sync pipe, meaning the child has sent us a message, or the sync pipe has closed, meaning the child has closed it (perhaps because it exited). */ @@ -729,8 +624,11 @@ 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. - XXX - what if we got an error from the sync pipe? Do we have - to kill the child? */ + We don't have to worry about killing the child, if the sync pipe + returned an error. Usually this error is caused as the child killed itself + while going down. Even in the rare cases that this isn't the case, + the child will get an error when writing to the broken pipe the next time, + cleaning itself up then. */ sync_pipe_wait_for_child(capture_opts); #ifdef _WIN32 @@ -740,6 +638,7 @@ sync_pipe_input_cb(gint source, gpointer user_data) return FALSE; } + /* we got a valid message block from the child, process it */ switch(indicator) { case SP_FILE: if(!capture_input_new_file(capture_opts, buffer)) { @@ -801,12 +700,9 @@ sync_pipe_wait_for_child(capture_options *capture_opts) g_assert(capture_opts->fork_child != -1); #ifdef _WIN32 - /* XXX - analyze the wait status and display more information - in the dialog box? - XXX - set "fork_child" to -1 if we find it exited? */ if (_cwait(&wstatus, capture_opts->fork_child, _WAIT_CHILD) == -1) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Child capture process stopped unexpectedly"); + "Child capture process stopped unexpectedly (errno:%u)", errno); } #else if (wait(&wstatus) != -1) { @@ -815,7 +711,7 @@ sync_pipe_wait_for_child(capture_options *capture_opts) /* the child will inform us about errors through the sync_pipe, which will popup */ /* an error message, so don't popup another one */ - /* XXX - if there are situations where the child won't send us such an error message, */ + /* If there are situations where the child won't send us such an error message, */ /* this should be fixed in the child and not here! */ if (WEXITSTATUS(wstatus) != 0 && WEXITSTATUS(wstatus) != 1) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, @@ -840,10 +736,10 @@ sync_pipe_wait_for_child(capture_options *capture_opts) "Child capture process died: wait status %#o", wstatus); } } +#endif /* No more child process. */ capture_opts->fork_child = -1; -#endif g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_wait_for_child: capture child closed"); } @@ -936,7 +832,7 @@ sync_pipe_signame(int sig) break; default: - /* XXX - returning a static buffer is ok in the context we use it here */ + /* Returning a static buffer is ok in the context we use it here */ g_snprintf(sigmsg_buf, sizeof sigmsg_buf, "Signal %d", sig); sigmsg = sigmsg_buf; break; @@ -946,12 +842,34 @@ sync_pipe_signame(int sig) #endif +#ifdef _WIN32 +/* tell the child through the signal pipe that we want to quit the capture */ +static void +signal_pipe_capquit_to_child(capture_options *capture_opts) +{ + const char quit_msg[] = "QUIT"; + int ret; + + + g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child"); + + /* it doesn't matter *what* we send here, the first byte will stop the capture */ + /* simply sending a "QUIT" string */ + /*pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, quit_msg);*/ + ret = write(capture_opts->signal_pipe_write_fd, quit_msg, sizeof quit_msg); + if(ret == -1) { + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING, + "signal_pipe_capquit_to_child: %d header: error %s", capture_opts->signal_pipe_write_fd, strerror(errno)); + } +} +#endif + + /* user wants to stop the capture run */ void 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) { + if (capture_opts->fork_child != -1) { #ifndef _WIN32 /* send the SIGUSR1 signal to close the capture child gracefully. */ kill(capture_opts->fork_child, SIGUSR1); @@ -968,12 +886,11 @@ sync_pipe_stop(capture_options *capture_opts) void sync_pipe_kill(capture_options *capture_opts) { - /* XXX - in which cases this will be 0? */ - if (capture_opts->fork_child != -1 && capture_opts->fork_child != 0) { + if (capture_opts->fork_child != -1) { #ifndef _WIN32 kill(capture_opts->fork_child, SIGTERM); /* SIGTERM so it can clean up if necessary */ #else - /* XXX: this is not the preferred method of closing a process! + /* Remark: 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) |