It ain't Wireshark unless we can capture.

Implement basic capture start and stop. Add a lot of menu items and
enable and disable them when appropriate. Rename a few variables.

Next step: Let the user select an interface (we just use the default for
now).

svn path=/trunk/; revision=44714
This commit is contained in:
Gerald Combs 2012-08-31 22:25:51 +00:00
parent 94cbe0ce2c
commit 5c715fcc19
9 changed files with 1148 additions and 252 deletions

View File

@ -50,9 +50,9 @@ InterfaceTree::InterfaceTree(QWidget *parent) :
setColumnCount(2);
setAccessibleName(tr("Welcome screen list"));
m_statCache = NULL;
m_statTimer = new QTimer(this);
connect(m_statTimer, SIGNAL(timeout()), this, SLOT(updateStatistics()));
stat_cache_ = NULL;
stat_timer_ = new QTimer(this);
connect(stat_timer_, SIGNAL(timeout()), this, SLOT(updateStatistics()));
setItemDelegateForColumn(1, new SparkLineDelegate());
@ -104,9 +104,9 @@ InterfaceTree::InterfaceTree(QWidget *parent) :
InterfaceTree::~InterfaceTree() {
QTreeWidgetItemIterator iter(this);
if (m_statCache) {
capture_stat_stop(m_statCache);
m_statCache = NULL;
if (stat_cache_) {
capture_stat_stop(stat_cache_);
stat_cache_ = NULL;
}
while (*iter) {
@ -119,20 +119,22 @@ InterfaceTree::~InterfaceTree() {
}
}
#include <QDebug>
void InterfaceTree::hideEvent(QHideEvent *evt) {
Q_UNUSED(evt);
m_statTimer->stop();
if (m_statCache) {
capture_stat_stop(m_statCache);
m_statCache = NULL;
qDebug() << "==== stat cache stop";
stat_timer_->stop();
if (stat_cache_) {
capture_stat_stop(stat_cache_);
stat_cache_ = NULL;
}
}
void InterfaceTree::showEvent(QShowEvent *evt) {
Q_UNUSED(evt);
m_statTimer->start(1000);
stat_timer_->start(1000);
}
void InterfaceTree::updateStatistics(void) {
@ -140,12 +142,13 @@ void InterfaceTree::updateStatistics(void) {
guint diff, if_idx;
struct pcap_stat stats;
if (!m_statCache) {
if (!stat_cache_) {
// Start gathering statistics using dumpcap
// We crash (on OS X at least) if we try to do this from ::showEvent.
m_statCache = capture_stat_start(&global_capture_opts);
qDebug() << "==== stat cache start";
stat_cache_ = capture_stat_start(&global_capture_opts);
}
if (!m_statCache) return;
if (!stat_cache_) return;
QTreeWidgetItemIterator iter(this);
while (*iter) {
@ -158,7 +161,7 @@ void InterfaceTree::updateStatistics(void) {
continue;
diff = 0;
if (capture_stats(m_statCache, device.name, &stats)) {
if (capture_stats(stat_cache_, device.name, &stats)) {
if ((int)(stats.ps_recv - device.last_packets) >= 0) {
diff = stats.ps_recv - device.last_packets;
}

View File

@ -49,8 +49,8 @@ protected:
void showEvent(QShowEvent *evt);
private:
if_stat_cache_t *m_statCache;
QTimer *m_statTimer;
if_stat_cache_t *stat_cache_;
QTimer *stat_timer_;
signals:

View File

@ -142,6 +142,7 @@ static gboolean console_wait; /* "Press any key..." */
//static void destroy_console(void);
static gboolean stdin_capture = FALSE; /* Don't grab stdin & stdout if TRUE */
#endif
static void console_log_handler(const char *log_domain,
GLogLevelFlags log_level, const char *message, gpointer user_data);
@ -151,40 +152,11 @@ void create_console(void);
extern capture_options global_capture_opts;
#endif
// Copied from ui/gtk/gui_utils.c
void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb)
static void
main_capture_callback(gint event, capture_options *capture_opts, gpointer user_data )
{
Q_UNUSED(source);
Q_UNUSED(user_data);
Q_UNUSED(child_process);
Q_UNUSED(input_cb);
// static pipe_input_t pipe_input;
// pipe_input.source = source;
// pipe_input.child_process = child_process;
// pipe_input.user_data = user_data;
// pipe_input.input_cb = input_cb;
g_log(NULL, G_LOG_LEVEL_DEBUG, "FIX: pipe_input_set_handler");
//#ifdef _WIN32
// /* Tricky to use pipes in win9x, as no concept of wait. NT can
// do this but that doesn't cover all win32 platforms. GTK can do
// this but doesn't seem to work over processes. Attempt to do
// something similar here, start a timer and check for data on every
// timeout. */
// /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/
// pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input);
//#else
// pipe_input.channel = g_io_channel_unix_new(source);
// g_io_channel_set_encoding(pipe_input.channel, NULL, NULL);
// pipe_input.pipe_input_id = g_io_add_watch_full(pipe_input.channel,
// G_PRIORITY_HIGH,
// G_IO_IN|G_IO_ERR|G_IO_HUP,
// pipe_input_cb,
// &pipe_input,
// NULL);
//#endif
wsApp->captureCallback(event, capture_opts);
}
static void
@ -515,7 +487,7 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
{
Q_UNUSED(user_data);
QString level;
QDateTime qt = QDateTime::currentDateTime();
QString hmsz = QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
// xxx qtshark: We want all of the messages for now.
// /* ignore log message, if log_level isn't interesting based
@ -550,13 +522,11 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
level = "Dbg ";
break;
default:
level = "unknown log_level %u";
level.arg(log_level);
qDebug() << level;
qDebug("%s unknown log_level %u", hmsz.toUtf8().constData(), log_level);
g_assert_not_reached();
}
qDebug() << qt.toString() << log_domain << " " << level << message;
qDebug("%s %s %s %s", hmsz.toUtf8().constData(), log_domain, level.toUtf8().constData(), message);
}
// xxx based from ../gtk/main.c:get_gtk_compiled_info
@ -879,6 +849,9 @@ int main(int argc, char *argv[])
}
}
#ifdef HAVE_LIBPCAP
capture_callback_add(main_capture_callback, NULL);
#endif
cf_callback_add(main_cf_callback, NULL);
/* Arrange that if we have no console window, and a GLib message logging
@ -1145,6 +1118,7 @@ int main(int argc, char *argv[])
w = new(MainWindow);
w->show();
g_main_loop_new(NULL, FALSE);
return a.exec();
}

View File

@ -44,9 +44,15 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="InterfaceTree" name="interfaceTree">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
@ -69,7 +75,7 @@
</widget>
<widget class="QListWidget" name="recentList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>

File diff suppressed because it is too large Load Diff

View File

@ -32,8 +32,21 @@
#include "file.h"
#include "ui/ui_util.h"
#ifdef HAVE_LIBPCAP
#include "capture_opts.h"
#endif
#include <QMainWindow>
#include <QSplitter>
#ifdef _WIN32
# include <QTimer>
#else
# include <QSocketNotifier>
#endif
#include "main_welcome.h"
#include "packet_list.h"
#include "display_filter_combo.h"
@ -52,37 +65,83 @@ class MainWindow : public QMainWindow
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setPipeInputHandler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb);
protected:
bool eventFilter(QObject *obj, QEvent *event);
void keyPressEvent(QKeyEvent *event);
void closeEvent (QCloseEvent *event);
private:
Ui::MainWindow *main_ui_;
QMenu *open_recent_menu_;
QSplitter *splitter_v_;
QSplitter *packet_splitter_;
MainWelcome *main_welcome_;
DisplayFilterCombo *df_combo_box_;
capture_file *cap_file_;
PacketList *packet_list_;
QWidget *previous_focus_;
bool capture_stopping_;
// Pipe input
gint pipe_source_;
gpointer pipe_user_data_;
int *pipe_child_process_;
pipe_input_cb_t pipe_input_cb_;
#ifdef _WIN32
QTimer *pipe_timer_;
#else
QSocketNotifier *pipe_notifier_;
#endif
void openCaptureFile(QString& cfPath = *new QString());
void saveCapture(capture_file *cf, bool close_capture);
bool testCaptureFileClose(capture_file *cf, bool from_quit = false, QString& before_what = *new QString());
void captureStop(capture_file *cf);
void setMenusForCaptureFile(bool force_disable = false);
void setMenusForCaptureInProgress(bool capture_in_progress = false);
void setMenusForCaptureStopping();
// xxx set_menus_for_captured_packets
// xxx set_menus_for_selected_packet
void updateForUnsavedChanges();
void setForCaptureInProgress(gboolean capture_in_progress = false);
signals:
void showProgress(progdlg_t **dlg_p, bool animate, const QString message, bool terminate_is_stop, bool *stop_flag, float pct);
public slots:
#ifdef HAVE_LIBPCAP
void captureCapturePrepared(capture_options *capture_opts);
void captureCaptureUpdateStarted(capture_options *capture_opts);
void captureCaptureUpdateFinished(capture_options *capture_opts);
void captureCaptureFixedStarted(capture_options *capture_opts);
void captureCaptureFixedFinished(capture_options *capture_opts);
void captureCaptureStopping(capture_options *capture_opts);
void captureCaptureFailed(capture_options *capture_opts);
#endif
void captureFileReadStarted(const capture_file *cf);
void captureFileReadFinished(const capture_file *cf);
void captureFileClosing(const capture_file *cf);
void captureFileClosed(const capture_file *cf);
private slots:
void startCapture();
#ifdef _WIN32
void pipeTimeout();
#else
void pipeActivated(int source);
void pipeNotifierDestroyed();
#endif
void stopCapture();
void updateRecentFiles();
void recentActionTriggered();
void openRecentCaptureFile(QString& cfPath = *new QString());
void on_actionFileOpen_triggered();
void on_actionFileClose_triggered();
void recentActionTriggered();
void on_actionGoGoToPacket_triggered();
void resetPreviousFocus();
@ -95,6 +154,8 @@ private slots:
void on_goToCancel_clicked();
void on_goToGo_clicked();
void on_goToLineEdit_returnPressed();
void on_actionStartCapture_triggered();
void on_actionStopCapture_triggered();
};

View File

@ -103,10 +103,33 @@
</property>
<addaction name="actionDummyNoFilesFound"/>
</widget>
<widget class="QMenu" name="menuFile_Set">
<property name="title">
<string>File Set</string>
</property>
<addaction name="actionList_Files"/>
<addaction name="actionNext_File"/>
<addaction name="actionPrevious_File"/>
</widget>
<addaction name="actionFileOpen"/>
<addaction name="menuOpenRecentCaptureFile"/>
<addaction name="separator"/>
<addaction name="actionFileMerge"/>
<addaction name="actionFileImport"/>
<addaction name="actionFileClose"/>
<addaction name="separator"/>
<addaction name="actionFileSave"/>
<addaction name="actionFileSaveAs"/>
<addaction name="separator"/>
<addaction name="menuFile_Set"/>
<addaction name="separator"/>
<addaction name="actionFileExportPackets"/>
<addaction name="actionFileExportPacketDissections"/>
<addaction name="actionFileExportPacketBytes"/>
<addaction name="actionFileExportSSLSessionKeys"/>
<addaction name="actionFileExportObjects"/>
<addaction name="separator"/>
<addaction name="actionFilePrint"/>
<addaction name="separator"/>
<addaction name="actionFileQuit"/>
</widget>
<widget class="QMenu" name="menuEdit">
@ -118,9 +141,13 @@
<property name="title">
<string>Capture</string>
</property>
<addaction name="actionInterfaces"/>
<addaction name="actionCaptureInterfaces"/>
<addaction name="actionCaptureOptions"/>
<addaction name="actionStartCapture"/>
<addaction name="actionStopCapture"/>
<addaction name="actionCaptureRestart"/>
<addaction name="actionCaptureCaptureFilters"/>
<addaction name="actionCaptureRefreshInterfaces"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
@ -172,6 +199,8 @@
<addaction name="actionViewExpandSubtrees"/>
<addaction name="actionViewExpandAll"/>
<addaction name="actionViewCollapseAll"/>
<addaction name="separator"/>
<addaction name="actionViewReload"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
@ -246,9 +275,15 @@
<string>Ctrl+Q</string>
</property>
</action>
<action name="actionInterfaces">
<action name="actionCaptureInterfaces">
<property name="text">
<string>Interfaces</string>
<string>&amp;Interfaces...</string>
</property>
<property name="toolTip">
<string>Show interface details</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionStartCapture">
@ -261,13 +296,13 @@
<normalon>:/toolbar/main/capture_start_active_24.png</normalon>:/toolbar/main/capture_start_24.png</iconset>
</property>
<property name="text">
<string>Start</string>
<string>&amp;Start</string>
</property>
<property name="toolTip">
<string>Start capturing packets</string>
</property>
<property name="shortcut">
<string>Ctrl+K</string>
<string>Ctrl+E</string>
</property>
</action>
<action name="actionStopCapture">
@ -276,11 +311,14 @@
<normaloff>:/toolbar/main/capture_stop_24.png</normaloff>:/toolbar/main/capture_stop_24.png</iconset>
</property>
<property name="text">
<string>Stop</string>
<string>S&amp;top</string>
</property>
<property name="toolTip">
<string>Stop capturing packets</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
<action name="actionFileClose">
<property name="text">
@ -503,6 +541,147 @@
<string>Ctrl+G</string>
</property>
</action>
<action name="actionFileMerge">
<property name="text">
<string>&amp;Merge...</string>
</property>
<property name="toolTip">
<string>Merge one or more files</string>
</property>
</action>
<action name="actionFileImport">
<property name="text">
<string>&amp;Import...</string>
</property>
<property name="toolTip">
<string>Import a file</string>
</property>
</action>
<action name="actionFileSave">
<property name="text">
<string>&amp;Save</string>
</property>
<property name="toolTip">
<string>Save the current file</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionFileSaveAs">
<property name="text">
<string>Save &amp;As...</string>
</property>
<property name="toolTip">
<string>Save as a different file</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="actionFileExportPackets">
<property name="text">
<string>Export Packets...</string>
</property>
<property name="toolTip">
<string>Export specified packets</string>
</property>
</action>
<action name="actionFileExportPacketDissections">
<property name="text">
<string>Export Packet Dissections...</string>
</property>
</action>
<action name="actionFileExportPacketBytes">
<property name="text">
<string>Export Packet &amp;Bytes...</string>
</property>
<property name="shortcut">
<string>Ctrl+H</string>
</property>
</action>
<action name="actionFileExportSSLSessionKeys">
<property name="text">
<string>Export SSL Session Keys...</string>
</property>
</action>
<action name="actionFileExportObjects">
<property name="text">
<string>Export Objects...</string>
</property>
</action>
<action name="actionFilePrint">
<property name="text">
<string>&amp;Print...</string>
</property>
<property name="shortcut">
<string>Ctrl+P</string>
</property>
</action>
<action name="actionList_Files">
<property name="text">
<string>List Files</string>
</property>
</action>
<action name="actionNext_File">
<property name="text">
<string>Next File</string>
</property>
</action>
<action name="actionPrevious_File">
<property name="text">
<string>Previous File</string>
</property>
</action>
<action name="actionViewReload">
<property name="text">
<string>&amp;Reload</string>
</property>
<property name="toolTip">
<string>Reload the current file</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="actionCaptureOptions">
<property name="text">
<string>&amp;Options...</string>
</property>
<property name="toolTip">
<string>Capture options</string>
</property>
<property name="shortcut">
<string>Ctrl+K</string>
</property>
</action>
<action name="actionCaptureCaptureFilters">
<property name="text">
<string>Capture &amp;Filters...</string>
</property>
<property name="toolTip">
<string>Capture filters</string>
</property>
</action>
<action name="actionCaptureRefreshInterfaces">
<property name="text">
<string>Refresh Interfaces</string>
</property>
<property name="toolTip">
<string>Refresh interfaces</string>
</property>
</action>
<action name="actionCaptureRestart">
<property name="text">
<string>&amp;Restart</string>
</property>
<property name="toolTip">
<string>Restart current capture</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -23,15 +23,11 @@
#include "wireshark_application.h"
#include "config.h"
#include "glib.h"
#include <epan/prefs.h>
#include "qt_ui_utils.h"
#include "file.h"
#include "capture.h"
#include "log.h"
#include "recent_file_status.h"
@ -188,6 +184,51 @@ void WiresharkApplication::refreshRecentFiles(void) {
}
}
void WiresharkApplication::captureCallback(int event, capture_options * capture_opts)
{
switch(event) {
case(capture_cb_capture_prepared):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture prepared");
emit captureCapturePrepared(capture_opts);
break;
case(capture_cb_capture_update_started):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update started");
emit captureCaptureUpdateStarted(capture_opts);
break;
case(capture_cb_capture_update_continue):
/*g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update continue");*/
break;
case(capture_cb_capture_update_finished):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture update finished");
emit captureCaptureUpdateFinished(capture_opts);
break;
case(capture_cb_capture_fixed_started):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed started");
emit captureCaptureFixedStarted(capture_opts);
break;
case(capture_cb_capture_fixed_continue):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed continue");
break;
case(capture_cb_capture_fixed_finished):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture fixed finished");
emit captureCaptureFixedFinished(capture_opts);
break;
case(capture_cb_capture_stopping):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture stopping");
/* Beware: this state won't be called, if the capture child
* closes the capturing on it's own! */
emit captureCaptureStopping(capture_opts);
break;
case(capture_cb_capture_failed):
g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_DEBUG, "Callback: capture failed");
emit captureCaptureFailed(capture_opts);
break;
default:
g_warning("main_capture_callback: event %u unknown", event);
g_assert_not_reached();
}
}
void WiresharkApplication::captureFileCallback(int event, void * data)
{
capture_file *cf = (capture_file *) data;
@ -294,9 +335,9 @@ WiresharkApplication::WiresharkApplication(int &argc, char **argv) :
}
#endif // Q_WS_WIN
recentTimer = new QTimer(this);
connect(recentTimer, SIGNAL(timeout()), this, SLOT(refreshRecentFiles()));
recentTimer->start(2000);
recent_timer_ = new QTimer(this);
connect(recent_timer_, SIGNAL(timeout()), this, SLOT(refreshRecentFiles()));
recent_timer_->start(2000);
}
QList<recent_item_status *> WiresharkApplication::recent_item_list() const {

View File

@ -28,6 +28,7 @@
#include <glib.h>
#include "capture_opts.h"
#include "file.h"
#include <QApplication>
@ -55,14 +56,28 @@ public:
explicit WiresharkApplication(int &argc, char **argv);
QList<recent_item_status *> recent_item_list() const;
void addRecentItem(const QString &filename, qint64 size, bool accessible);
#ifdef HAVE_LIBPCAP
void captureCallback(int event, capture_options * capture_opts);
#endif
void captureFileCallback(int event, void * data);
private:
QTimer *recentTimer;
QTimer *recent_timer_;
signals:
void updateRecentItemStatus(const QString &filename, qint64 size, bool accessible);
#ifdef HAVE_LIBPCAP
// XXX It might make more sense to move these to main.cpp or main_window.cpp or their own class.
void captureCapturePrepared(capture_options *capture_opts);
void captureCaptureUpdateStarted(capture_options *capture_opts);
void captureCaptureUpdateFinished(capture_options *capture_opts);
void captureCaptureFixedStarted(capture_options *capture_opts);
void captureCaptureFixedFinished(capture_options *capture_opts);
void captureCaptureStopping(capture_options *capture_opts);
void captureCaptureFailed(capture_options *capture_opts);
#endif
void captureFileReadStarted(const capture_file *cf);
void captureFileReadFinished(const capture_file *cf);
void captureFileClosing(const capture_file *cf);