commit 7e8d8308e35df91d2f1afdf94c93a2d14f3e5b16 Author: Srivats P. Date: Sat May 3 14:37:10 2008 +0000 Initial Import diff --git a/client/about.ui b/client/about.ui new file mode 100644 index 0000000..2256d60 --- /dev/null +++ b/client/about.ui @@ -0,0 +1,88 @@ + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + QFrame::Box + + + QFrame::Raised + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:29pt; font-weight:600;">Ostinato</span></p></body></html> + + + Qt::AlignCenter + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/client/hexlineedit.cpp b/client/hexlineedit.cpp new file mode 100644 index 0000000..a983bfd --- /dev/null +++ b/client/hexlineedit.cpp @@ -0,0 +1,69 @@ +#include "hexlineedit.h" +#include "qdebug.h" + +QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets); +HexLineEdit::HexLineEdit( QWidget * parent) + : QLineEdit(parent) +{ + //QLineEdit::QLineEdit(parent); +} + +void HexLineEdit::focusOutEvent( QFocusEvent *e ) +{ +#if 0 + const QValidator *v = validator(); + if ( v ) + { + int curpos = cursorPosition(); + QString str = text(); + if ( v->validate( str, curpos ) == QValidator::Acceptable ) + { + if ( curpos != cursorPosition() ) + setCursorPosition( curpos ); + if ( str != text() ) + setText( str ); + } + else + { + if ( curpos != cursorPosition() ) + setCursorPosition( curpos ); + str = text(); + v->fixup( str ); + if ( str != text() ) + { + setText( str ); + } + } + } + QLineEdit::focusOutEvent( e ); + emit focusOut(); +#else + bool isOk; + ulong num; + QString str; + + qDebug("before = %s\n", text().toAscii().data()); + num = text().remove(QChar(' ')).toULong(&isOk, 16); + setText(uintToHexStr(num, str, 4)); + qDebug("after = %s\n", text().toAscii().data()); + qDebug("after2 = %s\n", str.toAscii().data()); +#endif +} + +#if 0 +void HexLineEdit::focusInEvent( QFocusEvent *e ) +{ + QLineEdit::focusInEvent( e ); + emit focusIn(); +} + +void HexLineEdit::keyPressEvent( QKeyEvent *e ) +{ + QLineEdit::keyPressEvent( e ); + if ( e->key() == Key_Enter || e->key() == Key_Return ) + { + setSelection( 0, text().length() ); + } +} +#endif + diff --git a/client/hexlineedit.h b/client/hexlineedit.h new file mode 100644 index 0000000..7c5811e --- /dev/null +++ b/client/hexlineedit.h @@ -0,0 +1,24 @@ +#ifndef _HEXLINEEDIT +#define _HEXLINEEDIT + +#include + +class HexLineEdit : public QLineEdit +{ + Q_OBJECT +public: + // Constructors + HexLineEdit ( QWidget * parent); + +protected: + void focusOutEvent( QFocusEvent *e ); + //void focusInEvent( QFocusEvent *e ); + //void keyPressEvent( QKeyEvent *e ); + +signals: + //void focusIn(); + void focusOut(); +}; + +#endif + diff --git a/client/icons/bullet_error.png b/client/icons/bullet_error.png new file mode 100644 index 0000000..bca2b49 Binary files /dev/null and b/client/icons/bullet_error.png differ diff --git a/client/icons/bullet_green.png b/client/icons/bullet_green.png new file mode 100644 index 0000000..058ad26 Binary files /dev/null and b/client/icons/bullet_green.png differ diff --git a/client/icons/bullet_orange.png b/client/icons/bullet_orange.png new file mode 100644 index 0000000..fa63024 Binary files /dev/null and b/client/icons/bullet_orange.png differ diff --git a/client/icons/bullet_red.png b/client/icons/bullet_red.png new file mode 100644 index 0000000..0cd8031 Binary files /dev/null and b/client/icons/bullet_red.png differ diff --git a/client/icons/bullet_yellow.png b/client/icons/bullet_yellow.png new file mode 100644 index 0000000..6469cea Binary files /dev/null and b/client/icons/bullet_yellow.png differ diff --git a/client/icons/control_play.png b/client/icons/control_play.png new file mode 100644 index 0000000..0846555 Binary files /dev/null and b/client/icons/control_play.png differ diff --git a/client/icons/control_stop.png b/client/icons/control_stop.png new file mode 100644 index 0000000..893bb60 Binary files /dev/null and b/client/icons/control_stop.png differ diff --git a/client/icons/gaps.png b/client/icons/gaps.png new file mode 100644 index 0000000..17d7926 Binary files /dev/null and b/client/icons/gaps.png differ diff --git a/client/icons/magnifier.png b/client/icons/magnifier.png new file mode 100644 index 0000000..cf3d97f Binary files /dev/null and b/client/icons/magnifier.png differ diff --git a/client/icons/portgroup_add.png b/client/icons/portgroup_add.png new file mode 100644 index 0000000..db604ee Binary files /dev/null and b/client/icons/portgroup_add.png differ diff --git a/client/icons/portgroup_connect.png b/client/icons/portgroup_connect.png new file mode 100644 index 0000000..024138e Binary files /dev/null and b/client/icons/portgroup_connect.png differ diff --git a/client/icons/portgroup_delete.png b/client/icons/portgroup_delete.png new file mode 100644 index 0000000..5e9b268 Binary files /dev/null and b/client/icons/portgroup_delete.png differ diff --git a/client/icons/portgroup_disconnect.png b/client/icons/portgroup_disconnect.png new file mode 100644 index 0000000..b335cb1 Binary files /dev/null and b/client/icons/portgroup_disconnect.png differ diff --git a/client/icons/sound_mute.png b/client/icons/sound_mute.png new file mode 100644 index 0000000..b652d2a Binary files /dev/null and b/client/icons/sound_mute.png differ diff --git a/client/icons/sound_none.png b/client/icons/sound_none.png new file mode 100644 index 0000000..b497ebd Binary files /dev/null and b/client/icons/sound_none.png differ diff --git a/client/icons/stream_add.png b/client/icons/stream_add.png new file mode 100644 index 0000000..04f22ba Binary files /dev/null and b/client/icons/stream_add.png differ diff --git a/client/icons/stream_delete.png b/client/icons/stream_delete.png new file mode 100644 index 0000000..8ce71c4 Binary files /dev/null and b/client/icons/stream_delete.png differ diff --git a/client/icons/stream_edit.png b/client/icons/stream_edit.png new file mode 100644 index 0000000..47b75a4 Binary files /dev/null and b/client/icons/stream_edit.png differ diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 0000000..34a9f8c --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,11 @@ +#include +#include "mainwindow.h" + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + MainWindow mainWin; + + mainWin.show(); + return app.exec(); +} diff --git a/client/mainwindow.cpp b/client/mainwindow.cpp new file mode 100644 index 0000000..7eef2f3 --- /dev/null +++ b/client/mainwindow.cpp @@ -0,0 +1,30 @@ +#include +#include "mainwindow.h" +#include "portswindow.h" +#include "portstatswindow.h" +#include "portgrouplist.h" + +PortGroupList *pgl; + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow (parent) +{ + pgl = new PortGroupList; + + PortsWindow *portsWindow = new PortsWindow(pgl, this); + PortStatsWindow *statsWindow = new PortStatsWindow(pgl, this); + QDockWidget *dock = new QDockWidget(tr("Ports"), this); + QDockWidget *dock2 = new QDockWidget(tr("Stats"), this); + + setupUi(this); + + dock->setWidget(portsWindow); + addDockWidget(Qt::TopDockWidgetArea, dock); + dock2->setWidget(statsWindow); + addDockWidget(Qt::BottomDockWidgetArea, dock2); +} + +void MainWindow::on_actionPreferences_triggered() +{ +} + diff --git a/client/mainwindow.h b/client/mainwindow.h new file mode 100644 index 0000000..da412ec --- /dev/null +++ b/client/mainwindow.h @@ -0,0 +1,18 @@ +#ifndef _MAIN_WINDOW_H +#define _MAIN_WINDOW_H + +#include +#include "ui_mainwindow.h" + +class MainWindow : public QMainWindow, private Ui::MainWindow +{ + Q_OBJECT +public: + MainWindow(QWidget *parent = 0); + +public slots: + void on_actionPreferences_triggered(); +}; + +#endif + diff --git a/client/mainwindow.ui b/client/mainwindow.ui new file mode 100644 index 0000000..5d43edb --- /dev/null +++ b/client/mainwindow.ui @@ -0,0 +1,159 @@ + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 0 + 0 + 800 + 21 + + + + + File + + + + + + View + + + + + + Window + + + + + + + + + + + + Help + + + + + + + + + + + + Open Config + + + + + Save Config + + + + + Save Config As ... + + + + + Open Capture + + + + + Save Capture + + + + + Save Capture As ... + + + + + E&xit + + + + + Copy Port Config + + + + + Paste Port Config + + + + + Preferences + + + + + Minimize + + + + + Maximize/Restore + + + + + Minimize All + + + + + Maximize/Restoe All + + + + + Arrange All - Cascade + + + + + Arrange All - Tile + + + + + Dock + + + + + Help + + + + + About + + + + + + diff --git a/client/modeltest.cpp b/client/modeltest.cpp new file mode 100644 index 0000000..58685b0 --- /dev/null +++ b/client/modeltest.cpp @@ -0,0 +1,542 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Concurrent project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include + +#include "modeltest.h" + +Q_DECLARE_METATYPE(QModelIndex) + +/*! + Connect to all of the models signals. Whenever anything happens recheck everything. +*/ +ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false) +{ + Q_ASSERT(model); + + connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(layoutAboutToBeChanged ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(layoutChanged ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(modelReset ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + + // Special checks for inserting/removing + connect(model, SIGNAL(layoutAboutToBeChanged()), + this, SLOT(layoutAboutToBeChanged())); + connect(model, SIGNAL(layoutChanged()), + this, SLOT(layoutChanged())); + + connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(rowsInserted(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(rowsRemoved(const QModelIndex &, int, int))); + + runAllTests(); +} + +void ModelTest::runAllTests() +{ + if (fetchingMore) + return; + nonDestructiveBasicTest(); + rowCount(); + columnCount(); + hasIndex(); + index(); + parent(); + data(); +} + +/*! + nonDestructiveBasicTest tries to call a number of the basic functions (not all) + to make sure the model doesn't outright segfault, testing the functions that makes sense. +*/ +void ModelTest::nonDestructiveBasicTest() +{ + Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex()); + model->canFetchMore(QModelIndex()); + Q_ASSERT(model->columnCount(QModelIndex()) >= 0); + Q_ASSERT(model->data(QModelIndex()) == QVariant()); + fetchingMore = true; + model->fetchMore(QModelIndex()); + fetchingMore = false; + Qt::ItemFlags flags = model->flags(QModelIndex()); + Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0); + model->hasChildren(QModelIndex()); + model->hasIndex(0, 0); + model->headerData(0, Qt::Horizontal); + model->index(0, 0); + Q_ASSERT(model->index(-1, -1) == QModelIndex()); + model->itemData(QModelIndex()); + QVariant cache; + model->match(QModelIndex(), -1, cache); + model->mimeTypes(); + Q_ASSERT(model->parent(QModelIndex()) == QModelIndex()); + Q_ASSERT(model->rowCount() >= 0); + QVariant variant; + model->setData(QModelIndex(), variant, -1); + model->setHeaderData(-1, Qt::Horizontal, QVariant()); + model->setHeaderData(0, Qt::Horizontal, QVariant()); + model->setHeaderData(999999, Qt::Horizontal, QVariant()); + QMap roles; + model->sibling(0, 0, QModelIndex()); + model->span(QModelIndex()); + model->supportedDropActions(); +} + +/*! + Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() + + Models that are dynamically populated are not as fully tested here. + */ +void ModelTest::rowCount() +{ + // check top row + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + int rows = model->rowCount(topIndex); + Q_ASSERT(rows >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(topIndex) == true); + + QModelIndex secondLevelIndex = model->index(0, 0, topIndex); + if (secondLevelIndex.isValid()) { // not the top level + // check a row count where parent is valid + rows = model->rowCount(secondLevelIndex); + Q_ASSERT(rows >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(secondLevelIndex) == true); + } + + // The models rowCount() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() + */ +void ModelTest::columnCount() +{ + // check top row + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + Q_ASSERT(model->columnCount(topIndex) >= 0); + + // check a column count where parent is valid + QModelIndex childIndex = model->index(0, 0, topIndex); + if (childIndex.isValid()) + Q_ASSERT(model->columnCount(childIndex) >= 0); + + // columnCount() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::hasIndex() + */ +void ModelTest::hasIndex() +{ + // Make sure that invalid values returns an invalid index + Q_ASSERT(model->hasIndex(-2, -2) == false); + Q_ASSERT(model->hasIndex(-2, 0) == false); + Q_ASSERT(model->hasIndex(0, -2) == false); + + int rows = model->rowCount(); + int columns = model->columnCount(); + + // check out of bounds + Q_ASSERT(model->hasIndex(rows, columns) == false); + Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false); + + if (rows > 0) + Q_ASSERT(model->hasIndex(0, 0) == true); + + // hasIndex() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::index() + */ +void ModelTest::index() +{ + // Make sure that invalid values returns an invalid index + Q_ASSERT(model->index(-2, -2) == QModelIndex()); + Q_ASSERT(model->index(-2, 0) == QModelIndex()); + Q_ASSERT(model->index(0, -2) == QModelIndex()); + + int rows = model->rowCount(); + int columns = model->columnCount(); + + if (rows == 0) + return; + + // Catch off by one errors + Q_ASSERT(model->index(rows, columns) == QModelIndex()); + Q_ASSERT(model->index(0, 0).isValid() == true); + + // Make sure that the same index is *always* returned + QModelIndex a = model->index(0, 0); + QModelIndex b = model->index(0, 0); + Q_ASSERT(a == b); + + // index() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::parent() + */ +void ModelTest::parent() +{ + // Make sure the model wont crash and will return an invalid QModelIndex + // when asked for the parent of an invalid index. + Q_ASSERT(model->parent(QModelIndex()) == QModelIndex()); + + if (model->rowCount() == 0) + return; + + // Column 0 | Column 1 | + // QModelIndex() | | + // \- topIndex | topIndex1 | + // \- childIndex | childIndex1 | + + // Common error test #1, make sure that a top level index has a parent + // that is a invalid QModelIndex. + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + Q_ASSERT(model->parent(topIndex) == QModelIndex()); + + // Common error test #2, make sure that a second level index has a parent + // that is the first level index. + if (model->rowCount(topIndex) > 0) { + QModelIndex childIndex = model->index(0, 0, topIndex); + qDebug("topIndex RCI %x %x %llx", topIndex.row(), topIndex.column(), topIndex.internalId()); + qDebug("topIndex I %llx", topIndex.internalId()); + qDebug("childIndex RCI %x %x %llx", childIndex.row(), childIndex.column(), childIndex.internalId()); + Q_ASSERT(model->parent(childIndex) == topIndex); + } + + // Common error test #3, the second column should NOT have the same children + // as the first column in a row. + // Usually the second column shouldn't have children. + QModelIndex topIndex1 = model->index(0, 1, QModelIndex()); + if (model->rowCount(topIndex1) > 0) { + QModelIndex childIndex = model->index(0, 0, topIndex); + QModelIndex childIndex1 = model->index(0, 0, topIndex1); + Q_ASSERT(childIndex != childIndex1); + } + + // Full test, walk n levels deep through the model making sure that all + // parent's children correctly specify their parent. + checkChildren(QModelIndex()); +} + +/*! + Called from the parent() test. + + A model that returns an index of parent X should also return X when asking + for the parent of the index. + + This recursive function does pretty extensive testing on the whole model in an + effort to catch edge cases. + + This function assumes that rowCount(), columnCount() and index() already work. + If they have a bug it will point it out, but the above tests should have already + found the basic bugs because it is easier to figure out the problem in + those tests then this one. + */ +void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth) +{ + // First just try walking back up the tree. + QModelIndex p = parent; + while (p.isValid()) + p = p.parent(); + + // For models that are dynamically populated + if (model->canFetchMore(parent)) { + fetchingMore = true; + model->fetchMore(parent); + fetchingMore = false; + } + + int rows = model->rowCount(parent); + int columns = model->columnCount(parent); + + if (rows > 0) + Q_ASSERT(model->hasChildren(parent)); + + // Some further testing against rows(), columns(), and hasChildren() + Q_ASSERT(rows >= 0); + Q_ASSERT(columns >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(parent) == true); + + //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows + // << "columns:" << columns << "parent column:" << parent.column(); + + Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false); + for (int r = 0; r < rows; ++r) { + if (model->canFetchMore(parent)) { + fetchingMore = true; + model->fetchMore(parent); + fetchingMore = false; + } + Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false); + for (int c = 0; c < columns; ++c) { + Q_ASSERT(model->hasIndex(r, c, parent) == true); + QModelIndex index = model->index(r, c, parent); + // rowCount() and columnCount() said that it existed... + Q_ASSERT(index.isValid() == true); + + // index() should always return the same index when called twice in a row + QModelIndex modifiedIndex = model->index(r, c, parent); + Q_ASSERT(index == modifiedIndex); + + // Make sure we get the same index if we request it twice in a row + QModelIndex a = model->index(r, c, parent); + QModelIndex b = model->index(r, c, parent); + Q_ASSERT(a == b); + + // Some basic checking on the index that is returned + Q_ASSERT(index.model() == model); + Q_ASSERT(index.row() == r); + Q_ASSERT(index.column() == c); + // While you can technically return a QVariant usually this is a sign + // of an bug in data() Disable if this really is ok in your model. + //Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true); + + // If the next test fails here is some somewhat useful debug you play with. + /* + if (model->parent(index) != parent) { + qDebug() << r << c << currentDepth << model->data(index).toString() + << model->data(parent).toString(); + qDebug() << index << parent << model->parent(index); + // And a view that you can even use to show the model. + //QTreeView view; + //view.setModel(model); + //view.show(); + }*/ + + // Check that we can get back our real parent. + QModelIndex p = model->parent(index); + //qDebug() << "child:" << index; + //qDebug() << p; + //qDebug() << parent; + Q_ASSERT(model->parent(index) == parent); + + // recursively go down the children + if (model->hasChildren(index) && currentDepth < 10 ) { + //qDebug() << r << c << "has children" << model->rowCount(index); + checkChildren(index, ++currentDepth); + }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ + + // make sure that after testing the children that the index doesn't change. + QModelIndex newerIndex = model->index(r, c, parent); + Q_ASSERT(index == newerIndex); + } + } +} + +/*! + Tests model's implementation of QAbstractItemModel::data() + */ +void ModelTest::data() +{ + // Invalid index should return an invalid qvariant + Q_ASSERT(!model->data(QModelIndex()).isValid()); + + if (model->rowCount() == 0) + return; + + // A valid index should have a valid QVariant data + Q_ASSERT(model->index(0, 0).isValid()); + + // shouldn't be able to set data on an invalid index + Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false); + + // General Purpose roles that should return a QString + QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole); + if (variant.isValid()) { + Q_ASSERT(qVariantCanConvert(variant)); + } + variant = model->data(model->index(0, 0), Qt::StatusTipRole); + if (variant.isValid()) { + Q_ASSERT(qVariantCanConvert(variant)); + } + variant = model->data(model->index(0, 0), Qt::WhatsThisRole); + if (variant.isValid()) { + Q_ASSERT(qVariantCanConvert(variant)); + } + + // General Purpose roles that should return a QSize + variant = model->data(model->index(0, 0), Qt::SizeHintRole); + if (variant.isValid()) { + Q_ASSERT(qVariantCanConvert(variant)); + } + + // General Purpose roles that should return a QFont + QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole); + if (fontVariant.isValid()) { + Q_ASSERT(qVariantCanConvert(fontVariant)); + } + + // Check that the alignment is one we know about + QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole); + if (textAlignmentVariant.isValid()) { + int alignment = textAlignmentVariant.toInt(); + Q_ASSERT(alignment == Qt::AlignLeft || + alignment == Qt::AlignRight || + alignment == Qt::AlignHCenter || + alignment == Qt::AlignJustify || + alignment == Qt::AlignTop || + alignment == Qt::AlignBottom || + alignment == Qt::AlignVCenter || + alignment == Qt::AlignCenter || + alignment == Qt::AlignAbsolute || + alignment == Qt::AlignLeading || + alignment == Qt::AlignTrailing); + } + + // General Purpose roles that should return a QColor + QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole); + if (colorVariant.isValid()) { + Q_ASSERT(qVariantCanConvert(colorVariant)); + } + + colorVariant = model->data(model->index(0, 0), Qt::TextColorRole); + if (colorVariant.isValid()) { + Q_ASSERT(qVariantCanConvert(colorVariant)); + } + + // Check that the "check state" is one we know about. + QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole); + if (checkStateVariant.isValid()) { + int state = checkStateVariant.toInt(); + Q_ASSERT(state == Qt::Unchecked || + state == Qt::PartiallyChecked || + state == Qt::Checked); + } +} + +/*! + Store what is about to be inserted to make sure it actually happens + + \sa rowsInserted() + */ +void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_UNUSED(end); + Changing c; + c.parent = parent; + c.oldSize = model->rowCount(parent); + c.last = model->data(model->index(start - 1, 0, parent)); + c.next = model->data(model->index(start, 0, parent)); + insert.push(c); +} + +/*! + Confirm that what was said was going to happen actually did + + \sa rowsAboutToBeInserted() + */ +void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end) +{ + Changing c = insert.pop(); + Q_ASSERT(c.parent == parent); + Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent)); + Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent))); + /* + if (c.next != model->data(model->index(end + 1, 0, c.parent))) { + qDebug() << start << end; + for (int i=0; i < model->rowCount(); ++i) + qDebug() << model->index(i, 0).data().toString(); + qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); + } + */ + Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent))); +} + +void ModelTest::layoutAboutToBeChanged() +{ + for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i) + changing.append(QPersistentModelIndex(model->index(i, 0))); +} + +void ModelTest::layoutChanged() +{ + for (int i = 0; i < changing.count(); ++i) { + QPersistentModelIndex p = changing[i]; + Q_ASSERT(p == model->index(p.row(), p.column(), p.parent())); + } + changing.clear(); +} + +/*! + Store what is about to be inserted to make sure it actually happens + + \sa rowsRemoved() + */ +void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Changing c; + c.parent = parent; + c.oldSize = model->rowCount(parent); + c.last = model->data(model->index(start - 1, 0, parent)); + c.next = model->data(model->index(end + 1, 0, parent)); + remove.push(c); +} + +/*! + Confirm that what was said was going to happen actually did + + \sa rowsAboutToBeRemoved() + */ +void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end) +{ + Changing c = remove.pop(); + Q_ASSERT(c.parent == parent); + Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent)); + Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent))); + Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent))); +} + diff --git a/client/modeltest.h b/client/modeltest.h new file mode 100644 index 0000000..38b6b2b --- /dev/null +++ b/client/modeltest.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Concurrent project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef MODELTEST_H +#define MODELTEST_H + +#include +#include +#include + +class ModelTest : public QObject +{ + Q_OBJECT + +public: + ModelTest(QAbstractItemModel *model, QObject *parent = 0); + +private Q_SLOTS: + void nonDestructiveBasicTest(); + void rowCount(); + void columnCount(); + void hasIndex(); + void index(); + void parent(); + void data(); + +protected Q_SLOTS: + void runAllTests(); + void layoutAboutToBeChanged(); + void layoutChanged(); + void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void rowsInserted(const QModelIndex & parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void rowsRemoved(const QModelIndex & parent, int start, int end); + +private: + void checkChildren(const QModelIndex &parent, int currentDepth = 0); + + QAbstractItemModel *model; + + struct Changing + { + QModelIndex parent; + int oldSize; + QVariant last; + QVariant next; + }; + QStack insert; + QStack remove; + + bool fetchingMore; + + QList changing; +}; + +#endif diff --git a/client/modeltest.pri b/client/modeltest.pri new file mode 100644 index 0000000..358a077 --- /dev/null +++ b/client/modeltest.pri @@ -0,0 +1,4 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +SOURCES += $$PWD/modeltest.cpp +HEADERS += $$PWD/modeltest.h diff --git a/client/mythread.cpp b/client/mythread.cpp new file mode 100644 index 0000000..69fe660 --- /dev/null +++ b/client/mythread.cpp @@ -0,0 +1,24 @@ +#include "mythread.h" + + void MyThread::run() + { + int i, j; + + for (i=0; i + +#define NumPorts 2 +#define NumStats 8 + + class MyThread : public QThread + { + Q_OBJECT + + public: + void run(); + + signals: + void portStatsUpdate(int port, void *stats); + + private: + int stats[2][8]; + }; + +#endif diff --git a/client/ostinato.pro b/client/ostinato.pro new file mode 100644 index 0000000..3d27500 --- /dev/null +++ b/client/ostinato.pro @@ -0,0 +1,42 @@ +TEMPLATE = app +CONFIG += qt debug +QT += network +RESOURCES += ostinato.qrc +HEADERS += \ + hexlineedit.h \ + mainwindow.h \ + mythread.h \ + port.h \ + portgroup.h \ + portgrouplist.h \ + portmodel.h \ + portstatsmodel.h \ + portstatswindow.h \ + portswindow.h \ + streamconfigdialog.h \ + streammodel.h + +FORMS += \ + mainwindow.ui \ + portstatswindow.ui \ + portswindow.ui \ + streamconfigdialog.ui + +SOURCES += \ + stream.cpp \ + hexlineedit.cpp \ + main.cpp \ + mainwindow.cpp \ + mythread.cpp \ + port.cpp \ + portgroup.cpp \ + portgrouplist.cpp \ + portmodel.cpp \ + portstatsmodel.cpp \ + portstatswindow.cpp \ + portswindow.cpp \ + streamconfigdialog.cpp \ + streammodel.cpp + +# TODO(LOW): Test only +include(modeltest.pri) diff --git a/client/ostinato.qrc b/client/ostinato.qrc new file mode 100644 index 0000000..59f4930 --- /dev/null +++ b/client/ostinato.qrc @@ -0,0 +1,21 @@ + + + icons/bullet_error.png + icons/bullet_green.png + icons/bullet_orange.png + icons/bullet_red.png + icons/bullet_yellow.png + icons/control_play.png + icons/control_stop.png + icons/magnifier.png + icons/portgroup_add.png + icons/portgroup_connect.png + icons/portgroup_delete.png + icons/portgroup_disconnect.png + icons/sound_mute.png + icons/sound_none.png + icons/stream_add.png + icons/stream_delete.png + icons/stream_edit.png + + diff --git a/client/port.cpp b/client/port.cpp new file mode 100644 index 0000000..755e52e --- /dev/null +++ b/client/port.cpp @@ -0,0 +1,24 @@ +#include "port.h" + +Port::Port(quint32 id, quint32 portGroupId) +{ + mPortId = id; + mPortGroupId = portGroupId; + + mAdminStatus = AdminDisable; + mOperStatus = OperDown; + mControlMode = ControlShared; + + // FIXME(HI): TEST only + for(int i = 0; i < 10; i++) + mPortStats[i] = mPortGroupId*10000+mPortId*100+i; +} + +void Port::insertDummyStreams() +{ + mStreams.append(*(new Stream)); + mStreams[0].setName(QString("%1:%2:0").arg(portGroupId()).arg(id())); + mStreams.append(*(new Stream)); + mStreams[1].setName(QString("%1:%2:1").arg(portGroupId()).arg(id())); +} + diff --git a/client/port.h b/client/port.h new file mode 100644 index 0000000..13795ff --- /dev/null +++ b/client/port.h @@ -0,0 +1,55 @@ +#ifndef _PORT_H +#define _PORT_H + +#include +#include +#include +#include "stream.h" + +class Port { + + friend class StreamModel; + friend class PortStatsModel; + +public: + enum AdminStatus { AdminDisable, AdminEnable }; + enum OperStatus { OperDown, OperUp }; + enum ControlMode { ControlShared, ControlExclusive }; + +private: + quint32 mPortId; + quint32 mPortGroupId; + QList mStreams; + QString mName; + QString mDescription; + QString mUserAlias; // user defined + AdminStatus mAdminStatus; + OperStatus mOperStatus; + ControlMode mControlMode; + + quint32 mPortStats[10]; // FIXME(HI):Hardcoding + +public: + // FIXME(HIGH): default args is a hack for QList operations on Port + Port(quint32 id = 0xFFFFFFFF, quint32 pgId = 0xFFFFFFFF); + + quint32 id() const { return mPortId; } + quint32 portGroupId() const { return mPortGroupId; } + const QString& name() const { return mName; } + const QString& description() const { return mDescription; } + const QString& userAlias() const { return mUserAlias; } + + void setName(QString &name) { mName = name; } + void setName(const char* name) { mName = QString(name); } + void setDescription(QString &description) { mDescription = description; } + void setDescription(const char *description) + { mDescription = QString(description); } + + //void setAdminEnable(AdminStatus status) { mAdminStatus = status; } + void setAlias(QString &alias) { mUserAlias = alias; } + //void setExclusive(bool flag); + // FIXME(HIGH): Only for testing + void insertDummyStreams(); +}; + +#endif diff --git a/client/portgroup.cpp b/client/portgroup.cpp new file mode 100644 index 0000000..b7f8eb3 --- /dev/null +++ b/client/portgroup.cpp @@ -0,0 +1,169 @@ +#include "portgroup.h" +#include "../common/protocol.h" + +quint32 PortGroup::mPortGroupAllocId = 0; + +PortGroup::PortGroup(QHostAddress ip, quint16 port) +{ + // Allocate an id for self + mPortGroupId = PortGroup::mPortGroupAllocId++; + + // Init attributes for which we values were passed to us + mServerAddress = ip; + mServerPort = port; + + // Init remaining attributes with defaults + mpSocket = new QTcpSocket(this); + + // TODO: consider using QT's signal-slot autoconnect + connect(mpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(on_mpSocket_stateChanged())); + connect(mpSocket, SIGNAL(connected()), this, SLOT(when_connected())); + connect(mpSocket, SIGNAL(disconnected()), this, SLOT(when_disconnected())); + connect(mpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(when_error(QAbstractSocket::SocketError))); + connect(mpSocket, SIGNAL(readyRead()), this, SLOT(when_dataAvail())); +} + +PortGroup::~PortGroup() +{ + qDebug("PortGroup Destructor"); + // Disconnect and free TCP mpSocketet etc. + PortGroup::disconnectFromHost(); + delete mpSocket; +} + +void PortGroup::connectToHost(QHostAddress ip, quint16 port) +{ + mServerAddress = ip; + mServerPort = port; + + PortGroup::connectToHost(); +} + +void PortGroup::connectToHost() +{ + qDebug("PortGroup::connectToHost()"); + mpSocket->connectToHost(mServerAddress, mServerPort); +} + +void PortGroup::disconnectFromHost() +{ + mpSocket->disconnectFromHost(); +} + +// -------------------------------------------- +// Private Methods +// -------------------------------------------- +void PortGroup::ProcessMsg(const char *msg, quint32 size) +{ + tCommHdr *hdr; + // TODO: For now, assuming we'll get a complete msg + // but need to fix this as this is a TCP stream + + hdr = (tCommHdr*) msg; + + if (hdr->ver != 1) // FIXME:hardcoding + { + qDebug("Rcvd msg with invalid version %d\n", hdr->ver); + goto _exit; + } + + qDebug("msgType - %x\n", NTOHS(hdr->msgType)); + switch (NTOHS(hdr->msgType)) + { + case e_MT_CapabilityInfo: + ProcessCapabilityInfo(msg+sizeof(tCommHdr), + NTOHS(hdr->msgLen)-sizeof(tCommHdr)); + break; + + default: + qDebug("Rcvd msg with unrecognized msgType %d\n", NTOHS(hdr->msgType)); + } + +_exit: + return; +} + +void PortGroup::ProcessCapabilityInfo(const char *msg, qint32 size) +{ + tTlvPortCapability *cap = (tTlvPortCapability*) msg; + Port *p; + + emit portListAboutToBeChanged(mPortGroupId); + + while (size) + { + qDebug("size = %d, tlvType = %d, tlvLen = %d\n", + size, NTOHS(cap->tlvType), NTOHS(cap->tlvLen)); + if (NTOHS(cap->tlvType) != e_TT_PortCapability) + { + qDebug("Unrecognized TLV Type %d\n", NTOHS(cap->tlvType)); + goto _next; + } + + p = new Port(NTOHL(cap->port), mPortGroupId); + p->setName(cap->name); + p->setDescription(cap->desc); + p->insertDummyStreams(); // FIXME: only for testing + qDebug("before port append\n"); + mPorts.append(*p); + +_next: + size -= NTOHS(cap->tlvLen); + cap = (tTlvPortCapability*)((char *)(cap) + NTOHS(cap->tlvLen)); + } + + emit portListChanged(mPortGroupId); + + return; +} + +// ------------------------------------------------ +// Slots +// ------------------------------------------------ +void PortGroup::on_mpSocket_stateChanged() +{ + qDebug("state changed"); + emit portGroupDataChanged(this); +} + +void PortGroup::when_connected() +{ + qDebug("connected\n"); + + emit portGroupDataChanged(this); + + // Ask for Port Capability + tCommHdr pkt; + pkt.ver = 1; + pkt.resv1 = 0; + pkt.resv2 = 0; + pkt.msgType = HTONS(e_MT_CapabilityReq); + pkt.msgLen = HTONS(8); + + mpSocket->write((char*) &pkt, sizeof(pkt)); +} + +void PortGroup::when_disconnected() +{ + qDebug("disconnected\n"); + emit portListAboutToBeChanged(mPortGroupId); + mPorts.clear(); + emit portListChanged(mPortGroupId); + emit portGroupDataChanged(this); +} + +void PortGroup::when_error(QAbstractSocket::SocketError socketError) +{ + qDebug("error\n"); + emit portGroupDataChanged(this); +} + +void PortGroup::when_dataAvail() +{ + qDebug("dataAvail\n"); + + QByteArray msg = mpSocket->read(1024); // FIXME: hardcoding + ProcessMsg(msg.constData(), msg.size()); +} + + diff --git a/client/portgroup.h b/client/portgroup.h new file mode 100644 index 0000000..8f5c1e3 --- /dev/null +++ b/client/portgroup.h @@ -0,0 +1,66 @@ +#ifndef _PORT_GROUP_H +#define _PORT_GROUP_H + +#include "port.h" +#include +#include + +/* TODO +HIGH +MED +LOW +- Allow hostnames in addition to IP Address as "server address" +*/ + +#define DEFAULT_SERVER_PORT 7878 + +class PortGroup : public QObject { + Q_OBJECT + +private: + quint32 mPortGroupId; + static quint32 mPortGroupAllocId; + QString mUserAlias; // user defined + + QTcpSocket *mpSocket; + QHostAddress mServerAddress; + quint16 mServerPort; +public: // FIXME(HIGH): member access + QList mPorts; + +public: + PortGroup(QHostAddress ip = QHostAddress::LocalHost, + quint16 port = DEFAULT_SERVER_PORT); + ~PortGroup(); + + void connectToHost(); + void connectToHost(QHostAddress ip, quint16 port); + void disconnectFromHost(); + + int numPorts() const { return mPorts.size(); } + quint32 id() const { return mPortGroupId; } + const QHostAddress& serverAddress() const { return mServerAddress; } + quint16 serverPort() const { return mServerPort; } + const QString& userAlias() const { return mUserAlias; } + QAbstractSocket::SocketState state() const { return mpSocket->state(); } + + void setUserAlias(QString alias) { mUserAlias = alias; }; + +signals: + void portGroupDataChanged(PortGroup* portGroup); + void portListAboutToBeChanged(quint32 portGroupId); + void portListChanged(quint32 portGroupId); + +private slots: + void on_mpSocket_stateChanged(); + void when_connected(); + void when_disconnected(); + void when_error(QAbstractSocket::SocketError socketError); + void when_dataAvail(); + +private: + void ProcessCapabilityInfo(const char *msg, qint32 size); + void ProcessMsg(const char *msg, quint32 size); +}; + +#endif diff --git a/client/portgrouplist.cpp b/client/portgrouplist.cpp new file mode 100644 index 0000000..06df02d --- /dev/null +++ b/client/portgrouplist.cpp @@ -0,0 +1,108 @@ +#include "portgrouplist.h" + +// TODO(LOW): Remove +#include + +PortGroupList::PortGroupList() + : mPortGroupListModel(this), + mStreamListModel(this), + mPortStatsModel(this, this) +{ + PortGroup *pg; + + // TODO(LOW): Remove + new ModelTest(getStreamModel()); + new ModelTest(getPortModel()); + new ModelTest(getPortStatsModel()); + + // Add the "Local" Port Group + pg = new PortGroup; + addPortGroup(*pg); +} + +bool PortGroupList::isPortGroup(const QModelIndex& index) +{ + return mPortGroupListModel.isPortGroup(index); +} + +bool PortGroupList::isPort(const QModelIndex& index) +{ + return mPortGroupListModel.isPort(index); +} + +PortGroup& PortGroupList::portGroup(const QModelIndex& index) +{ + if (mPortGroupListModel.isPortGroup(index)) + { + //return *(mPortGroups[mPortGroupListModel.portGroupId(index)]); + return *(mPortGroups[index.row()]); + } +#if 0 // FIXME(MED) + else + return NULL; +#endif +} + +Port& PortGroupList::port(const QModelIndex& index) +{ + if (mPortGroupListModel.isPort(index)) + { + return (mPortGroups.at(index.parent().row())-> + mPorts[index.row()]); + } +#if 0 // FIXME(MED) + else + return NULL; +#endif +} + +void PortGroupList::addPortGroup(PortGroup &portGroup) +{ + mPortGroupListModel.portGroupAboutToBeAppended(); + + connect(&portGroup, SIGNAL(portGroupDataChanged(PortGroup*)), + &mPortGroupListModel, SLOT(when_portGroupDataChanged(PortGroup*))); +#if 0 + connect(&portGroup, SIGNAL(portListAboutToBeChanged(quint32)), + &mPortGroupListModel, SLOT(triggerLayoutAboutToBeChanged())); + connect(&portGroup, SIGNAL(portListChanged(quint32)), + &mPortGroupListModel, SLOT(triggerLayoutChanged())); +#endif + connect(&portGroup, SIGNAL(portListChanged(quint32)), + &mPortGroupListModel, SLOT(when_portListChanged())); + + connect(&portGroup, SIGNAL(portListChanged(quint32)), + &mPortStatsModel, SLOT(when_portListChanged())); + + mPortGroups.append(&portGroup); + portGroup.connectToHost(); + + mPortGroupListModel.portGroupAppended(); + + mPortStatsModel.when_portListChanged(); +} + +void PortGroupList::removePortGroup(PortGroup &portGroup) +{ + mPortGroupListModel.portGroupAboutToBeRemoved(&portGroup); + + PortGroup* pg = mPortGroups.takeAt(mPortGroups.indexOf(&portGroup)); + qDebug("after takeAt()"); + mPortGroupListModel.portGroupRemoved(); + + delete pg; + + mPortStatsModel.when_portListChanged(); +} + +//.................... +// Private Methods +//.................... +int PortGroupList::indexOfPortGroup(quint32 portGroupId) +{ + for (int i = 0; i < mPortGroups.size(); i++) { + if (mPortGroups.value(i)->id() == portGroupId) + return i; + } + return -1; +} diff --git a/client/portgrouplist.h b/client/portgrouplist.h new file mode 100644 index 0000000..1e5add9 --- /dev/null +++ b/client/portgrouplist.h @@ -0,0 +1,47 @@ +#ifndef _PORT_GROUP_LIST_H +#define _PORT_GROUP_LIST_H + +#include "portgroup.h" +#include +#include +#include "portmodel.h" +#include "streammodel.h" +#include "portstatsmodel.h" + +class PortModel; +class StreamModel; + +class PortGroupList : public QObject { + + Q_OBJECT + + friend class PortModel; + friend class StreamModel; + friend class PortStatsModel; + + QList mPortGroups; + PortModel mPortGroupListModel; + StreamModel mStreamListModel; + PortStatsModel mPortStatsModel; + +// Methods +public: + PortGroupList::PortGroupList(); + + PortModel* getPortModel() { return &mPortGroupListModel; } + PortStatsModel* getPortStatsModel() { return &mPortStatsModel; } + StreamModel* getStreamModel() { return &mStreamListModel; } + bool isPortGroup(const QModelIndex& index); + bool isPort(const QModelIndex& index); + PortGroup& portGroup(const QModelIndex& index); + Port& port(const QModelIndex& index); + + void addPortGroup(PortGroup &portGroup); + void removePortGroup(PortGroup &portGroup); + +private: + int indexOfPortGroup(quint32 portGroupId); + +}; + +#endif diff --git a/client/portgrouplistmodel.h b/client/portgrouplistmodel.h new file mode 100644 index 0000000..4242539 --- /dev/null +++ b/client/portgrouplistmodel.h @@ -0,0 +1,55 @@ +#ifndef _PORT_GROUP_LIST_H +#define _PORT_GROUP_LIST_H + +#include "portgroup.h" +#include + +/* ----------------------------------------------------------- +** NOTE: FILE NOT USED 'COZ MOC DOESN'T SUPPORT NESTED CLASSES +*-------------------------------------------------------------*/ + + +class PortGroupList; + +class PortGroupList : public QObject { + + Q_OBJECT + + class PortListModel : public QAbstractItemModel + { + // This is currently a read only model + Q_OBJECT + + PortGroupList *pgl; // FIXME(HIGH): rename member + + public: + PortListModel(PortGroupList *p, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const; + QModelIndex parent(const QModelIndex &index) const; + + friend class PortGroupList; // FIXME(MED): Review need for friend + }; + + friend class PortListModel; + + QList mPortGroups; + PortListModel mPortGroupListModel; + +// Methods +public: + PortGroupList::PortGroupList(); + QAbstractItemModel* getModel(); + int addPortGroup(PortGroup &portGroup); + int removePortGroup(PortGroup &portGroup); + +private slots: + void when_portlist_dataChanged(); +}; + +#endif diff --git a/client/portlistmodel.cpp b/client/portlistmodel.cpp new file mode 100644 index 0000000..df53fb9 --- /dev/null +++ b/client/portlistmodel.cpp @@ -0,0 +1,191 @@ +#include "portlistmodel.h" + +----------------------- +This file is not used +----------------------- + +PortListModel::PortListModel(QObject *parent) + : QAbstractItemModel(parent) +{ + portList = new QList; + +#if 0 // FIXME: Dummy data only for testing; to be removed + PortGroup pg; + + pg.name = "A"; + pg.isLocal = TRUE; + pg.numPorts = 3; + pg.port = new Port[pg.numPorts]; + pg.port[0].portId = 0; + pg.port[0].name = "A0"; + pg.port[0].desc = "a0a0a0a0a0a0"; + pg.port[1].portId = 1; + pg.port[1].name = "A1"; + pg.port[1].desc = "a1a1a1a1a1a1"; + pg.port[2].portId = 2; + pg.port[2].name = "A2"; + pg.port[2].desc = "a2a2a2a2a2a2"; + + portList->append(pg); + + pg.name = "B"; + pg.isLocal = FALSE; + pg.numPorts = 2; + pg.port = new Port[pg.numPorts]; + pg.port[0].portId = 0; + pg.port[0].name = "B0"; + pg.port[0].desc = "b0b0b0b0b0b0"; + pg.port[1].portId = 1; + pg.port[1].name = "B1"; + pg.port[1].desc = "b1b1b1b1b1b1"; + + portList->append(pg); +#endif + // Do I need to do anything here? +} + +int PortListModel::rowCount(const QModelIndex &parent) const +{ + // qDebug("RowCount Enter\n"); + if (!parent.isValid()) + { + // Top Level Item + // qDebug("RowCount top\n"); + // qDebug("RowCount Exit: %d\n", portList->size()); + return portList->size(); + } + // qDebug("RowCount non top %d, %d, %llx\n", + // parent.row(), parent.column(), parent.internalId()); + + quint16 p = parent.internalId() & 0xFFFF; + if (p == 0xFFFF) + { + // qDebug("RowCount Exit: %d\n", portList->at(parent.row()).numPorts); + return portList->at(parent.row()).numPorts; + } + else + { + // Leaf Item + return 0; + } +} + +int PortListModel::columnCount(const QModelIndex &parent ) const +{ + return 1; // FIXME: hardcoding +} + +Qt::ItemFlags PortListModel::flags(const QModelIndex &index) const +{ + return QAbstractItemModel::flags(index); // FIXME: no need for this func +} +QVariant PortListModel::data(const QModelIndex &index, int role) const +{ + //qDebug("Enter PortListModel data\n"); + // Check for a valid index + if (!index.isValid()) + return QVariant(); + + + // Check role + if ((role == Qt::DisplayRole)) + { +#if 0 // Only for debug + qDebug("Exit PortListModel data\n"); + return "Testing"; // FIXME: for dbg only +#endif + + QModelIndex parent = index.parent(); + + if (!parent.isValid()) + { + // Top Level Item + return QString("%1 (%2) [%3]"). + arg(portList->at(index.row()).name). + arg(portList->at(index.row()).isLocal == TRUE? "LOCAL" : "REMOTE"). + arg(portList->at(index.row()).numPorts); + } + return QString("%1: %2 (%3)"). + arg(portList->at(parent.row()).port[index.row()].portId). + arg(portList->at(parent.row()).port[index.row()].name). + arg(portList->at(parent.row()).port[index.row()].desc); + } + else + return QVariant(); +} + +QVariant PortListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return QVariant(); + else + return QString("%1").arg(section+1); +} + +QModelIndex PortListModel::index (int row, int col, + const QModelIndex & parent) const +{ +#if 0 + if (!hasIndex(row, col, parent)) + return QModelIndex(); +#endif + + //qDebug("index: R=%d, C=%d, PR=%d, PC=%d, PID=%llx\n", + // row, col, parent.row(), parent.column(), parent.internalId()); + + if (!parent.isValid()) + { + // Top Level Item + quint16 pg = row, p = 0xFFFF; + quint32 id = (pg << 16) | p; + //qDebug("index (top) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id); + + return createIndex(row, col, id); + } + else + { + quint16 pg = parent.row(), p = row; + quint32 id = (pg << 16) | p; + //qDebug("index (nontop) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id); + + return createIndex(row, col, id); + } +} + +QModelIndex PortListModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + //qDebug("parent: R=%d, C=%d ID=%llx\n", + // index.row(), index.column(), index.internalId()); + + quint16 pg = index.internalId() >> 16; + quint16 p = index.internalId() & 0x0000FFFF; + + //qDebug("parent dbg: PG=%d, P=%d\n", pg, p); + + if (p == 0xFFFF) + { + //qDebug("parent ret: NULL\n"); + // Top Level Item - PG + return QModelIndex(); + } + + quint32 id = (pg << 16) | 0xFFFF; + //qDebug("parent ret: R=%d, C=%d, ID=%x\n", + // pg, 0, id); + + return createIndex(pg, 0, id); + +} + +void PortListModel::doRefresh() +{ + emit layoutChanged(); +} + + diff --git a/client/portlistmodel.h b/client/portlistmodel.h new file mode 100644 index 0000000..45a07bc --- /dev/null +++ b/client/portlistmodel.h @@ -0,0 +1,37 @@ +#ifndef _PORT_LIST_MODEL_H +#define _PORT_LIST_MODEL_H + + + ----------------- + This file is not used + ------------------ + +#include +#include +#include "portgroup.h" + +static QStringList PortListCols = (QStringList() + << "Name" +); + +class PortListModel : public QAbstractItemModel +{ + Q_OBJECT + + public: + //PortListModel(QObject *parent = 0) : QAbstractItemModel(parent) {} + PortListModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const; + QModelIndex parent(const QModelIndex &index) const; + + void doRefresh(); // FIXME: temp till model exports functions to insert rows + QList *portList; // FIXME: this shd be private +}; + +#endif diff --git a/client/portmodel.cpp b/client/portmodel.cpp new file mode 100644 index 0000000..61f9be8 --- /dev/null +++ b/client/portmodel.cpp @@ -0,0 +1,314 @@ +#include "portmodel.h" +#include "portgrouplist.h" +#include + +#if 0 +#define DBG0(x) qDebug(x) +#define DBG1(x, p1) qDebug(x, (p1)) +#else +#define DBG0(x) {} +#define DBG1(x, p1) {} +#endif + +PortModel::PortModel(PortGroupList *p, QObject *parent) + : QAbstractItemModel(parent) +{ + pgl = p; +} + +int PortModel::rowCount(const QModelIndex &parent) const +{ + // qDebug("RowCount Enter\n"); + if (!parent.isValid()) + { + // Top Level Item + //qDebug("RowCount (Top) Exit: %d\n", pgl->mPortGroups.size()); + return pgl->mPortGroups.size(); + } + // qDebug("RowCount non top %d, %d, %llx\n", + // parent.row(), parent.column(), parent.internalId()); + + quint16 pg = (parent.internalId() >> 16) & 0xFFFF; + quint16 p = parent.internalId() & 0xFFFF; + if (p == 0xFFFF) + { +#if 0 // wrong code? + int count = 0; + foreach(PortGroup *pg, pgl->mPortGroups) + { + count += pg->numPorts(); + } + //qDebug("RowCount (Mid) Exit: %d\n", count); + return count; +#endif + if (parent.column() == 0) + return pgl->mPortGroups.value(pgl->indexOfPortGroup(pg))->numPorts(); + else + return 0; + } + else + { + // Leaf Item + return 0; + } +} + +int PortModel::columnCount(const QModelIndex &parent ) const +{ + return 1; // FIXME: hardcoding +} + +Qt::ItemFlags PortModel::flags(const QModelIndex &index) const +{ + return QAbstractItemModel::flags(index); // FIXME: no need for this func +} +QVariant PortModel::data(const QModelIndex &index, int role) const +{ + + DBG0("Enter PortModel data\n"); + + // Check for a valid index + if (!index.isValid()) + return QVariant(); + + DBG1("PortModel::data(index).row = %d", index.row()); + DBG1("PortModel::data(index).column = %0d", index.column()); + DBG1("PortModel::data(index).internalId = %08llx", index.internalId()); + + QModelIndex parent = index.parent(); + + if (!parent.isValid()) + { + // Top Level Item - PortGroup + if ((role == Qt::DisplayRole)) + { + DBG0("Exit PortModel data 1\n"); + return QString("Port Group %1: %2 [%3:%4] (%5)"). + arg(pgl->mPortGroups.at(index.row())->id()). + arg(pgl->mPortGroups.at(index.row())->userAlias()). + arg(pgl->mPortGroups.at(index.row())->serverAddress().toString()). + arg(pgl->mPortGroups.at(index.row())->serverPort()). + arg(pgl->mPortGroups.value(index.row())->numPorts()); + } + else if ((role == Qt::DecorationRole)) + { + DBG0("Exit PortModel data 2\n"); + switch(pgl->mPortGroups.at(index.row())->state()) + { + case QAbstractSocket::UnconnectedState: + return QIcon(":/icons/bullet_red.png"); + + case QAbstractSocket::HostLookupState: + return QIcon(":/icons/bullet_yellow.png"); + + case QAbstractSocket::ConnectingState: + case QAbstractSocket::ClosingState: + return QIcon(":/icons/bullet_orange.png"); + + case QAbstractSocket::ConnectedState: + return QIcon(":/icons/bullet_green.png"); + + + case QAbstractSocket::BoundState: + case QAbstractSocket::ListeningState: + default: + return QIcon(":/icons/bullet_error.png"); + } + } + else + { + DBG0("Exit PortModel data 3\n"); + return QVariant(); + } + } + else + { + // Non Top Level - Port + if ((role == Qt::DisplayRole)) + { + DBG0("Exit PortModel data 4\n"); + if (pgl->mPortGroups.at(parent.row())->numPorts() == 0) + return QVariant(); + + return QString("Port %1: %2 [%3] (%4)"). + arg(pgl->mPortGroups.at( + parent.row())->mPorts[index.row()].id()). + arg(pgl->mPortGroups.at( + parent.row())->mPorts[index.row()].name()). + arg(QHostAddress("0.0.0.0").toString()). // FIXME(LOW) + arg(pgl->mPortGroups.at( + parent.row())->mPorts[index.row()].description()); + } + else if ((role == Qt::DecorationRole)) + { + DBG0("Exit PortModel data 5\n"); + if (pgl->mPortGroups.at(parent.row())->numPorts() == 0) + return QVariant(); + return QIcon(":/icons/bullet_green.png"); + } + else + { + DBG0("Exit PortModel data 6\n"); + return QVariant(); + } + } +} + +QVariant PortModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return QVariant(); + else + return QString("Name"); +} + +QModelIndex PortModel::index (int row, int col, + const QModelIndex & parent) const +{ + if (!hasIndex(row, col, parent)) + return QModelIndex(); + + //qDebug("index: R=%d, C=%d, PR=%d, PC=%d, PID=%llx\n", + // row, col, parent.row(), parent.column(), parent.internalId()); + + if (!parent.isValid()) + { + // Top Level Item + quint16 pg = pgl->mPortGroups.value(row)->id(), p = 0xFFFF; + quint32 id = (pg << 16) | p; + //qDebug("index (top) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id); + + return createIndex(row, col, id); + } + else + { + quint16 pg = parent.internalId() >> 16; + quint16 p = pgl->mPortGroups.value(parent.row())->mPorts.value(row).id(); + quint32 id = (pg << 16) | p; + //qDebug("index (nontop) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id); + + return createIndex(row, col, id); + } +} + +QModelIndex PortModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + //qDebug("parent: R=%d, C=%d ID=%llx\n", + // index.row(), index.column(), index.internalId()); + + quint16 pg = index.internalId() >> 16; + quint16 p = index.internalId() & 0x0000FFFF; + + //qDebug("parent dbg: PG=%d, P=%d\n", pg, p); + + if (p == 0xFFFF) + { + //qDebug("parent ret: NULL\n"); + // Top Level Item - PG + return QModelIndex(); + } + + quint32 id = (pg << 16) | 0xFFFF; + //qDebug("parent ret: R=%d, C=%d, ID=%x\n", pg, 0, id); + + return createIndex(pgl->indexOfPortGroup(pg), 0, id); + +} + +bool PortModel::isPortGroup(const QModelIndex& index) +{ + if ((index.internalId() & 0xFFFF) == 0xFFFF) + return true; + else + return false; +} + +bool PortModel::isPort(const QModelIndex& index) +{ + if ((index.internalId() & 0xFFFF) != 0xFFFF) + return true; + else + return false; +} + +quint32 PortModel::portGroupId(const QModelIndex& index) +{ + return (index.internalId()) >> 16 & 0xFFFF; +} + +quint32 PortModel::portId(const QModelIndex& index) +{ + return (index.internalId()) & 0xFFFF; +} + + + +// ---------------------------------------------- +// Slots +// ---------------------------------------------- +void PortModel::when_portGroupDataChanged(PortGroup* portGroup) +{ + QModelIndex index; + + if (!pgl->mPortGroups.contains(portGroup)) + { + qDebug("when_portGroupDataChanged(): pg not in list - do nothing"); + return; + } + + qDebug("when_portGroupDataChanged pgid = %d", portGroup->id()); + qDebug("when_portGroupDataChanged idx = %d", pgl->mPortGroups.indexOf(portGroup)); + + index = createIndex(pgl->mPortGroups.indexOf(portGroup), 0, + (portGroup->id() << 16) | 0xFFFF); + emit dataChanged(index, index); +} + +void PortModel::portGroupAboutToBeAppended() +{ + int row; + + row = pgl->mPortGroups.size(); + beginInsertRows(QModelIndex(), row, row); +} + +void PortModel::portGroupAppended() +{ + endInsertRows(); +} + +void PortModel::portGroupAboutToBeRemoved(PortGroup *portGroup) +{ + int row; + + row = pgl->mPortGroups.indexOf(portGroup); + beginRemoveRows(QModelIndex(), row, row); +} + +void PortModel::portGroupRemoved() +{ + endRemoveRows(); +} + +#if 0 +void PortModel::triggerLayoutAboutToBeChanged() +{ + emit layoutAboutToBeChanged(); +} + +void PortModel::triggerLayoutChanged() +{ + emit layoutChanged(); +} +#endif + +void PortModel::when_portListChanged() +{ + reset(); +} diff --git a/client/portmodel.h b/client/portmodel.h new file mode 100644 index 0000000..b68acdc --- /dev/null +++ b/client/portmodel.h @@ -0,0 +1,51 @@ +#ifndef _PORT_MODEL_H +#define _PORT_MODEL_H + +#include + +class PortGroupList; +class PortGroup; + +class PortModel : public QAbstractItemModel +{ + Q_OBJECT + + friend class PortGroupList; + + PortGroupList *pgl; + + public: + PortModel(PortGroupList *p, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const; + QModelIndex parent(const QModelIndex &index) const; + + bool isPortGroup(const QModelIndex& index); + bool isPort(const QModelIndex& index); + quint32 portGroupId(const QModelIndex& index); + quint32 portId(const QModelIndex& index); + + +private slots: + void when_portGroupDataChanged(PortGroup *portGroup); + + void portGroupAboutToBeAppended(); + void portGroupAppended(); + void portGroupAboutToBeRemoved(PortGroup *portGroup); + void portGroupRemoved(); + + void when_portListChanged(); + +#if 0 + void triggerLayoutAboutToBeChanged(); + void triggerLayoutChanged(); +#endif + +}; + +#endif diff --git a/client/portstatsfilter.ui b/client/portstatsfilter.ui new file mode 100644 index 0000000..3dae66d --- /dev/null +++ b/client/portstatsfilter.ui @@ -0,0 +1,124 @@ + + Dialog + + + + 0 + 0 + 402 + 275 + + + + Dialog + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + > + + + + + + + < + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + lvAllPorts + tbFilterIn + tbFilterOut + lvFilteredPorts + buttonBox + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/client/portstatsfilterdialog.cpp b/client/portstatsfilterdialog.cpp new file mode 100644 index 0000000..8845dd2 --- /dev/null +++ b/client/portstatsfilterdialog.cpp @@ -0,0 +1,9 @@ +#include "portstatsfilterdialog.h" + +PortStatsFilterDialog::PortStatsFilterDialog(AbstractItemModel *allPortsModel, + QWidget *parent) +{ + setupUi(this); + + lvAllPorts->setModel(allPortsModel); +} diff --git a/client/portstatsfilterdialog.h b/client/portstatsfilterdialog.h new file mode 100644 index 0000000..c180f34 --- /dev/null +++ b/client/portstatsfilterdialog.h @@ -0,0 +1,19 @@ +#ifndef _PORT_STATS_FILTER_DIALOG_H +#define _PORT_STATS_FILTER_DIALOG_H + +#include +#include +#include "ui_portstatsfilterdialog.h" +#include "portgrouplist.h" + +class PortStatsFilterDialog : public QDialog, public Ui::PortStatsFilterDialog +{ + Q_OBJECT + +public: + PortStatsFilterDialog(AbstractItemModel *allPortsModel, + QWidget *parent = 0); +}; + +#endif + diff --git a/client/portstatsmodel.cpp b/client/portstatsmodel.cpp new file mode 100644 index 0000000..c67c7e4 --- /dev/null +++ b/client/portstatsmodel.cpp @@ -0,0 +1,119 @@ +#include "portstatsmodel.h" +#include "portgrouplist.h" + +PortStatsModel::PortStatsModel(PortGroupList *p, QObject *parent) + : QAbstractTableModel(parent) +{ + pgl = p; +} + +int PortStatsModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + if (numPorts.isEmpty()) + return 0; + + if (numPorts.last() == 0) + return 0; + + return (int) e_STAT_MAX; +} + +int PortStatsModel::columnCount(const QModelIndex &parent ) const +{ + if (parent.isValid()) + return 0; + else + if (numPorts.isEmpty()) + return 0; + else + return numPorts.last(); +} + +QVariant PortStatsModel::data(const QModelIndex &index, int role) const +{ + int pgidx, pidx, portNum; + + // Check for a valid index + if (!index.isValid()) + return QVariant(); + + // Check for row/column limits + if (index.row() >= e_STAT_MAX) + return QVariant(); + + if (numPorts.isEmpty()) + return QVariant(); + + if (index.column() >= (numPorts.last())) + return QVariant(); + + // TODO(LOW): Optimize using binary search: see qLowerBound() + portNum = index.column() + 1; + for (pgidx = 0; pgidx < numPorts.size(); pgidx++) + if (portNum <= numPorts.at(pgidx)) + break; + + if (pgidx) + { + if (numPorts.at(pgidx -1)) + pidx = (portNum - 1) % numPorts.at(pgidx - 1); + else + pidx = portNum - 1; + } + else + pidx = portNum - 1; + + //qDebug("PSM: %d - %d, %d", index.column(), pgidx, pidx); + + // Check role + if (role == Qt::DisplayRole) + return pgl->mPortGroups.at(pgidx)->mPorts.at(pidx).mPortStats[index.row()]; + else + return QVariant(); + +} + +QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return QString("Port %1").arg(section); + else + return PortStatName.at(section); +} + +// +// Slots +// +void PortStatsModel::when_portListChanged() +{ + int i, count = 0; + + // recalc numPorts + while (numPorts.size()) + numPorts.removeFirst(); + + for (i = 0; i < pgl->mPortGroups.size(); i++) + { + count += pgl->mPortGroups.at(i)->numPorts(); + numPorts.append(count); + } + + reset(); +} + +void PortStatsModel::on_portStatsUpdate(int port, void*stats) +{ + // FIXME(MED): update only the changed port not all + QModelIndex topLeft = index(port, 0, QModelIndex()); + QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex()); + + emit dataChanged(topLeft, bottomRight); +} + + diff --git a/client/portstatsmodel.h b/client/portstatsmodel.h new file mode 100644 index 0000000..6bf5c5a --- /dev/null +++ b/client/portstatsmodel.h @@ -0,0 +1,59 @@ +#ifndef _PORT_STATS_MODEL_H +#define _PORT_STATS_MODEL_H + +#include +#include + +typedef enum { + e_STAT_FRAMES_RCVD = 0, + e_STAT_FRAMES_SENT, + e_STAT_FRAME_SEND_RATE, + e_STAT_FRAME_RECV_RATE, + e_STAT_BYTES_RCVD, + e_STAT_BYTES_SENT, + e_STAT_BYTE_SEND_RATE, + e_STAT_BYTE_RECV_RATE, + e_STAT_MAX +} PortStat; + +static QStringList PortStatName = (QStringList() + << "Frames Received" + << "Frames Sent" + << "Frame Send Rate (fps)" + << "Frame Receive Rate (fps)" + << "Bytes Received" + << "Bytes Sent" + << "Byte Send Rate (Bps)" + << "Byte Receive Rate (Bps)" +); + +class PortGroupList; + +class PortStatsModel : public QAbstractTableModel +{ + Q_OBJECT + + PortGroupList *pgl; + + public: + PortStatsModel(PortGroupList *p, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + public slots: + void when_portListChanged(); + void on_portStatsUpdate(int port, void*stats); + + private: + // numPorts stores the num of ports per portgroup + // in the same order as the portgroups are index in the pgl + // Also it stores them as cumulative totals + QList numPorts; + +}; + +#endif diff --git a/client/portstatswindow.cpp b/client/portstatswindow.cpp new file mode 100644 index 0000000..594209e --- /dev/null +++ b/client/portstatswindow.cpp @@ -0,0 +1,15 @@ +#include "portstatswindow.h" +#include "portstatsmodel.h" + +//PortStatsWindow::PortStatsWindow(QWidget *parent) : QDialog (parent) +PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent) +{ + setupUi(this); + + tvPortStats->setModel(pgl->getPortStatsModel()); + +} + +PortStatsWindow::~PortStatsWindow() +{ +} diff --git a/client/portstatswindow.h b/client/portstatswindow.h new file mode 100644 index 0000000..2cec09a --- /dev/null +++ b/client/portstatswindow.h @@ -0,0 +1,21 @@ +#ifndef _PORT_STATS_WINDOW_H +#define _PORT_STATS_WINDOW_H + +#include +#include +#include "ui_portstatswindow.h" +#include "portgrouplist.h" + +class PortStatsWindow : public QDialog, public Ui::PortStatsWindow +{ + Q_OBJECT + +public: + PortStatsWindow(PortGroupList *pgl, QWidget *parent = 0); + ~PortStatsWindow(); +private: + QAbstractItemModel *model; +}; + +#endif + diff --git a/client/portstatswindow.ui b/client/portstatswindow.ui new file mode 100644 index 0000000..f3dff15 --- /dev/null +++ b/client/portstatswindow.ui @@ -0,0 +1,133 @@ + + PortStatsWindow + + + + 0 + 0 + 502 + 415 + + + + Form + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Start Transmit + + + Stop Transmit + + + Start Transmit + + + :/icons/control_play.png + + + + + + + Stop Transmit + + + Stop Transmit + + + Stop Trasmit + + + :/icons/control_stop.png + + + + + + + Clear + + + + + + + Clear All + + + + + + + Start Capture + + + :/icons/sound_none.png + + + + + + + Stop Capture + + + :/icons/sound_mute.png + + + + + + + View Capture + + + :/icons/magnifier.png + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + diff --git a/client/portswindow.cpp b/client/portswindow.cpp new file mode 100644 index 0000000..c316b0d --- /dev/null +++ b/client/portswindow.cpp @@ -0,0 +1,320 @@ +#include "portswindow.h" +#include "streamlistmodel.h" +#include "streamconfigdialog.h" +#include +#include + +PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) +{ + //slm = new StreamListModel(); + //plm = new PortGroupList(); + plm = pgl; + + setupUi(this); + + tvPortList->addAction(actionNew_Port_Group); + tvPortList->addAction(actionDelete_Port_Group); + tvPortList->addAction(actionConnect_Port_Group); + tvPortList->addAction(actionDisconnect_Port_Group); + + tvStreamList->addAction(actionNew_Stream); + tvStreamList->addAction(actionDelete_Stream); + + tvStreamList->setModel(plm->getStreamModel()); + tvPortList->setModel(plm->getPortModel()); + + connect( plm->getPortModel(), + SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(when_portModel_dataChanged(const QModelIndex&, + const QModelIndex&))); + connect( tvPortList->selectionModel(), + SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(when_portView_currentChanged(const QModelIndex&, + const QModelIndex&))); + connect( tvStreamList->selectionModel(), + SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), + this, SLOT(when_streamView_currentChanged(const QModelIndex&, + const QModelIndex&))); + connect( tvStreamList->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), + this, SLOT(when_streamView_selectionChanged())); + connect( tvPortList->selectionModel(), + SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), + plm->getStreamModel(), SLOT(setCurrentPortIndex(const QModelIndex&))); +} + +PortsWindow::~PortsWindow() +{ + delete plm; +} + +void PortsWindow::on_tvStreamList_activated(const QModelIndex & index) +{ + StreamConfigDialog *scd; + + if (!index.isValid()) + { + qDebug("%s: invalid index", __FUNCTION__); + return; + } + // FIXME(MED): This way of passing params must be changed + scd = new StreamConfigDialog(plm->getStreamModel()->currentPortStreamList(), + (uint) index.row(), this); + qDebug("stream list activated\n"); + scd->exec(); // TODO: chk retval + delete scd; +} + +void PortsWindow::when_portView_currentChanged(const QModelIndex& current, + const QModelIndex& previous) +{ + updatePortViewActions(current); + + if (!current.isValid()) + { + qDebug("setting stacked widget to blank page"); + swDetail->setCurrentIndex(2); // blank page + } + else + { + if (plm->isPortGroup(current)) + { + swDetail->setCurrentIndex(1); // portGroup detail page + } + else if (plm->isPort(current)) + { + swDetail->setCurrentIndex(0); // port detail page + } + } +} + +void PortsWindow::when_streamView_currentChanged(const QModelIndex& current, + const QModelIndex& previous) +{ + qDebug("stream view current changed"); + updateStreamViewActions(); +} + +void PortsWindow::when_streamView_selectionChanged() +{ + qDebug("stream view selection changed"); + updateStreamViewActions(); +} + +void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ +#if 0 // not sure why the >= <= operators are not overloaded in QModelIndex + if ((tvPortList->currentIndex() >= topLeft) && + (tvPortList->currentIndex() <= bottomRight)) +#endif + if ((topLeft < tvPortList->currentIndex()) || + (topLeft == tvPortList->currentIndex()) && + ((tvPortList->currentIndex() < bottomRight)) || + (tvPortList->currentIndex() == bottomRight)) + { + updatePortViewActions(tvPortList->currentIndex()); + } + +} + +#if 0 +void PortsWindow::updateStreamViewActions(const QModelIndex& current) +{ + if (current.isValid()) + actionDelete_Stream->setEnabled(true); + else + actionDelete_Stream->setDisabled(true); +} +#endif + +void PortsWindow::updateStreamViewActions() +{ + if (tvStreamList->selectionModel()->hasSelection()) + { + qDebug("Has selection %d", + tvStreamList->selectionModel()->selection().size()); + // If more than one non-contiguous ranges selected, disable "New" + if (tvStreamList->selectionModel()->selection().size() > 1) + actionNew_Stream->setDisabled(true); + else + actionNew_Stream->setEnabled(true); + + // Delete is always enabled as long as we have a selection + actionDelete_Stream->setEnabled(true); + } + else + { + qDebug("No selection"); + actionNew_Stream->setEnabled(true); + actionDelete_Stream->setDisabled(true); + } +} + +void PortsWindow::updatePortViewActions(const QModelIndex& current) +{ + if (!current.isValid()) + { + qDebug("current is now invalid"); + actionDelete_Port_Group->setDisabled(true); + actionConnect_Port_Group->setDisabled(true); + actionDisconnect_Port_Group->setDisabled(true); + + goto _EXIT; + } + + qDebug("currentChanged %llx", current.internalId()); + + if (plm->isPortGroup(current)) + { + actionDelete_Port_Group->setEnabled(true); + switch(plm->portGroup(current).state()) + { + case QAbstractSocket::UnconnectedState: + case QAbstractSocket::ClosingState: + qDebug("state = unconnected|closing"); + actionConnect_Port_Group->setEnabled(true); + actionDisconnect_Port_Group->setDisabled(true); + break; + + case QAbstractSocket::HostLookupState: + case QAbstractSocket::ConnectingState: + case QAbstractSocket::ConnectedState: + qDebug("state = lookup|connecting|connected"); + actionConnect_Port_Group->setDisabled(true); + actionDisconnect_Port_Group->setEnabled(true); + break; + + + case QAbstractSocket::BoundState: + case QAbstractSocket::ListeningState: + default: + // FIXME(LOW): indicate error + qDebug("unexpected state"); + break; + } + } + else if (plm->isPort(current)) + { + actionDelete_Port_Group->setEnabled(false); + actionConnect_Port_Group->setEnabled(false); + actionDisconnect_Port_Group->setEnabled(false); + } + +_EXIT: + return; +} + +void PortsWindow::on_pbApply_clicked() +{ +{ + // TODO (LOW): This block is for testing only + QModelIndex current = tvPortList->selectionModel()->currentIndex(); + + if (current.isValid()) + qDebug("current = %llx", current.internalId()); + else + qDebug("current is invalid"); +} +} + +void PortsWindow::on_actionNew_Port_Group_triggered() +{ + bool ok; + QString text = QInputDialog::getText(this, + "Add Port Group", "Port Group Address (IP[:Port])", + QLineEdit::Normal, lastNewPortGroup, &ok); + + if (ok) + { + QStringList addr = text.split(":"); + if (addr.size() == 1) // Port unspecified + addr.append(QString().setNum(DEFAULT_SERVER_PORT)); + PortGroup *pg = new PortGroup(QHostAddress(addr[0]),addr[1].toUShort()); + plm->addPortGroup(*pg); + lastNewPortGroup = text; + } +} + +void PortsWindow::on_actionDelete_Port_Group_triggered() +{ + QModelIndex current = tvPortList->selectionModel()->currentIndex(); + + if (current.isValid()) + plm->removePortGroup(plm->portGroup(current)); +} + +void PortsWindow::on_actionConnect_Port_Group_triggered() +{ + QModelIndex current = tvPortList->selectionModel()->currentIndex(); + + if (current.isValid()) + plm->portGroup(current).connectToHost(); +} + +void PortsWindow::on_actionDisconnect_Port_Group_triggered() +{ + QModelIndex current = tvPortList->selectionModel()->currentIndex(); + + if (current.isValid()) + plm->portGroup(current).disconnectFromHost(); +} +#if 0 +void PortsWindow::on_actionNew_Stream_triggered() +{ + qDebug("New Stream Action"); + + int row = 0; + + if (tvStreamList->currentIndex().isValid()) + row = tvStreamList->currentIndex().row(); + plm->getStreamModel()->insertRows(row, 1); +} + +void PortsWindow::on_actionDelete_Stream_triggered() +{ + qDebug("Delete Stream Action"); + if (tvStreamList->currentIndex().isValid()) + plm->getStreamModel()->removeRows(tvStreamList->currentIndex().row(), 1); +} +#endif + +void PortsWindow::on_actionNew_Stream_triggered() +{ + qDebug("New Stream Action"); + + // In case nothing is selected, insert 1 row at the top + int row = 0, count = 1; + + // In case we have a single range selected; insert as many rows as + // in the singe selected range before the top of the selected range + if (tvStreamList->selectionModel()->selection().size() == 1) + { + row = tvStreamList->selectionModel()->selection().at(0).top(); + count = tvStreamList->selectionModel()->selection().at(0).height(); + } + + plm->getStreamModel()->insertRows(row, count); +} + +void PortsWindow::on_actionDelete_Stream_triggered() +{ + qDebug("Delete Stream Action"); + + QModelIndex index; + + if (tvStreamList->selectionModel()->hasSelection()) + { + qDebug("SelectedIndexes %d", + tvStreamList->selectionModel()->selectedRows().size()); + while(tvStreamList->selectionModel()->selectedRows().size()) + { + index = tvStreamList->selectionModel()->selectedRows().at(0); + plm->getStreamModel()->removeRows(index.row(), 1); + } + } + else + qDebug("No selection"); +} + + diff --git a/client/portswindow.h b/client/portswindow.h new file mode 100644 index 0000000..2a26c2b --- /dev/null +++ b/client/portswindow.h @@ -0,0 +1,56 @@ +#ifndef _PORTS_WINDOW_H +#define _PORTS_WINDOW_H + +#include +#include +#include "ui_portswindow.h" +#include "portgrouplist.h" + +/* TODO +HIGH +MED +LOW +*/ + + +class PortsWindow : public QWidget, private Ui::PortsWindow +{ + Q_OBJECT + + //QAbstractItemModel *slm; // stream list model + PortGroupList *plm; + +public: + PortsWindow(PortGroupList *pgl, QWidget *parent = 0); + ~PortsWindow(); + +private: + QString lastNewPortGroup; + + void updatePortViewActions(const QModelIndex& current); + //void updateStreamViewActions(const QModelIndex& current); + void updateStreamViewActions(); + +private slots: + void on_tvStreamList_activated(const QModelIndex & index); + void when_portView_currentChanged(const QModelIndex& current, + const QModelIndex& previous); + void when_streamView_currentChanged(const QModelIndex& current, + const QModelIndex& previous); + void when_streamView_selectionChanged(); + void when_portModel_dataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight); + + void on_pbApply_clicked(); + + void on_actionNew_Port_Group_triggered(); + void on_actionDelete_Port_Group_triggered(); + void on_actionConnect_Port_Group_triggered(); + void on_actionDisconnect_Port_Group_triggered(); + + void on_actionNew_Stream_triggered(); + void on_actionDelete_Stream_triggered(); +}; + +#endif + diff --git a/client/portswindow.ui b/client/portswindow.ui new file mode 100644 index 0000000..04349d2 --- /dev/null +++ b/client/portswindow.ui @@ -0,0 +1,214 @@ + + PortsWindow + + + + 0 + 0 + 689 + 320 + + + + Form + + + + + + Qt::Horizontal + + + + Qt::ActionsContextMenu + + + QAbstractItemView::SingleSelection + + + + + 0 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Apply + + + + + + + + + + + Qt::Horizontal + + + + 31 + 41 + + + + + + + + Capacity + + + + + + + + + + Aggr fps + + + + + + + + + + % age + + + + + + + + + + Aggr bps + + + + + + + + + + + + 0 + + + + Control + + + + + + Qt::ActionsContextMenu + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + + + + + + + + + + + + + Port Group Detail + + + + + + + + + + + + + :/icons/portgroup_add.png + + + New Port Group + + + + + :/icons/portgroup_delete.png + + + Delete Port Group + + + + + :/icons/portgroup_connect.png + + + Connect Port Group + + + + + :/icons/portgroup_disconnect.png + + + Disconnect Port Group + + + + + :/icons/stream_add.png + + + New Stream + + + + + :/icons/stream_delete.png + + + Delete Stream + + + + + + + + diff --git a/client/stream.cpp b/client/stream.cpp new file mode 100644 index 0000000..980d26c --- /dev/null +++ b/client/stream.cpp @@ -0,0 +1,123 @@ +#include + +Stream::Stream() +{ + // Default constructor + InitDefaultMeta(); + InitDefaultProto(); + InitDefaultL2(); + InitDefaultL3(); + InitDefaultL4(); +} + +void Stream::InitDefaultMeta() +{ + // TODO(LOW): Use #defines + meta.patternMode = e_dp_fixed; + meta.pattern = 0x00000000; + meta.dataStartOfs = 0; // FIXME(HIGH): this has to calculated + meta.lenMode = e_fl_fixed; + meta.frameLen = 64; + meta.frameLenMin = 64; + meta.frameLenMax = 1518; +} + +void Stream::InitDefaultProto() +{ + // TODO(LOW): Use #defines + proto.ft = e_ft_eth_2; + proto.dsap = 0x00; + proto.ssap = 0x00; + proto.ctl = 0x00; + proto.ouiMsb = 0x00; + proto.ouiLshw = 0x0000; + + proto.protoMask = PM_L3_PROTO_NONE | PM_L4_PROTO_NONE; + proto.etherType = ETH_TYP_IP; + proto.ipProto = IP_PROTO_TCP; +} + + +void Stream::InitDefaultL2() +{ + // TODO(LOW): Use #defines + l2.eth.dstMacMshw = 0x0000; + l2.eth.dstMacLsw = 0x00000001; + l2.eth.dstMacMode = e_mm_fixed; + l2.eth.dstMacCount = 16; + l2.eth.dstMacStep = 1; + + l2.eth.srcMacMshw = 0x0000; + l2.eth.srcMacLsw = 0x00000002; + l2.eth.srcMacMode = e_mm_fixed; + l2.eth.srcMacCount = 16; + l2.eth.srcMacStep = 1; + + l2.eth.vlanMask = VM_UNTAGGED; + l2.eth.ctpid = 0x8100; + l2.eth.cvlanPrio = 0; + l2.eth.cvlanCfi = 0; + l2.eth.cvlanId = 2; + l2.eth.stpid = 0x88a8; + l2.eth.svlanPrio = 0; + l2.eth.svlanCfi = 0; + l2.eth.svlanId = 2; +} + +void Stream::InitDefaultL3() +{ + InitDefaultL3Ip(); +} + +void Stream::InitDefaultL3Ip() +{ + l3.ip.ipMask = STREAM_DEF_IP_MASK; + l3.ip.ver = STREAM_DEF_L3_IP_VER; + l3.ip.hdrLen = STREAM_DEF_L3_IP_HDR_LEN; + l3.ip.tos = STREAM_DEF_L3_IP_TOS; + l3.ip.totLen = STREAM_DEF_L3_IP_TOT_LEN; + l3.ip.id = STREAM_DEF_L3_IP_ID; + l3.ip.flags = STREAM_DEF_L3_IP_FLAGS; + l3.ip.fragOfs = STREAM_DEF_L3_IP_FRAG_OFS; + l3.ip.ttl = STREAM_DEF_L3_IP_TTL; + l3.ip.proto = STREAM_DEF_L3_IP_PROTO; + l3.ip.cksum = STREAM_DEF_L3_IP_CKSUM; + l3.ip.srcIp = STREAM_DEF_L3_IP_SRC_IP; + l3.ip.srcIpMode = STREAM_DEF_L3_IP_SRC_IP_MODE; + l3.ip.srcIpCount = STREAM_DEF_L3_IP_SRC_IP_COUNT; + l3.ip.srcIpMask = STREAM_DEF_L3_IP_SRC_IP_MASK; + l3.ip.dstIp = STREAM_DEF_L3_IP_DST_IP; + l3.ip.dstIpMode = STREAM_DEF_L3_IP_DST_IP_MODE; + l3.ip.dstIpCount = STREAM_DEF_L3_IP_DST_IP_COUNT; + l3.ip.dstIpMask = STREAM_DEF_L3_IP_DST_IP_MASK; +} + +void Stream::InitDefaultL4() +{ + InitDefaultL4Tcp(); + InitDefaultL4Udp(); +} + +void Stream::InitDefaultL4Tcp() +{ + l4.tcp.tcpMask = STREAM_DEF_L4_TCP_TCP_MASK; + l4.tcp.srcPort = STREAM_DEF_L4_TCP_SRC_PORT; + l4.tcp.dstPort = STREAM_DEF_L4_TCP_DST_PORT; + l4.tcp.seqNum = STREAM_DEF_L4_TCP_SEQ_NUM; + l4.tcp.ackNum = STREAM_DEF_L4_TCP_ACK_NUM; + l4.tcp.hdrLen = STREAM_DEF_L4_TCP_HDR_LEN; + l4.tcp.rsvd = STREAM_DEF_L4_TCP_RSVD; + l4.tcp.flags = STREAM_DEF_L4_TCP_FLAGS; + l4.tcp.window = STREAM_DEF_L4_TCP_WINDOW; + l4.tcp.cksum = STREAM_DEF_L4_TCP_CKSUM; + l4.tcp.urgPtr = STREAM_DEF_L4_TCP_URG_PTR; +} + +void Stream::InitDefaultL4Udp() +{ + l4.udp.udpMask = STREAM_DEF_L4_UDP_UDP_MASK; + l4.udp.srcPort = STREAM_DEF_L4_UDP_SRC_PORT; + l4.udp.dstPort = STREAM_DEF_L4_UDP_DST_PORT; + l4.udp.totLen = STREAM_DEF_L4_UDP_TOT_LEN; + l4.udp.cksum = STREAM_DEF_L4_UDP_CKSUM; +} diff --git a/client/stream.h b/client/stream.h new file mode 100644 index 0000000..c1f9d5f --- /dev/null +++ b/client/stream.h @@ -0,0 +1,307 @@ +#ifndef _STREAM_H +#define _STREAM_H + +#include +#include + +class StreamConfigDialog; +class StreamModel; + +class Stream { + + friend class StreamConfigDialog; + friend class StreamModel; + + enum FrameType { + e_ft_none, + e_ft_eth_2, + e_ft_802_3_raw, + e_ft_802_3_llc, + e_ft_snap + }; + + enum DataPatternMode { + e_dp_fixed, + e_dp_inc, + e_dp_dec, + e_dp_random + }; + + enum FrameLengthMode { + e_fl_fixed, + e_fl_inc, + e_fl_dec, + e_fl_random + }; + + enum MacAddrMode { + e_mm_fixed, + e_mm_inc, + e_mm_dec, + }; + + enum IpAddrMode { + e_im_fixed, + e_im_inc_host, + e_im_dec_host, + e_im_random_host + }; + + // Meta Data + struct { + // Data Pattern + DataPatternMode patternMode; + quint32 pattern; + quint16 dataStartOfs; + + // Frame Length (includes CRC) + FrameLengthMode lenMode; + quint16 frameLen; + quint16 frameLenMin; + quint16 frameLenMax; + } meta; + + // Protocols + struct { + FrameType ft; + + quint8 dsap; + quint8 ssap; + quint8 ctl; + quint8 ouiMsb; + quint16 ouiLshw; + + quint16 protoMask; +#define PM_L3_PROTO_NONE 0x0001 +#define PM_L3_PROTO_OTHER 0x0002 +#define PM_L4_PROTO_NONE 0x0004 +#define PM_L4_PROTO_OTHER 0x0008 + + quint16 etherType; +#define ETH_TYP_IP 0x0800 +#define ETH_TYP_ARP 0x0806 + + quint16 ipProto; +#define IP_PROTO_ICMP 0x01 +#define IP_PROTO_IGMP 0x02 +#define IP_PROTO_TCP 0x06 +#define IP_PROTO_UDP 0x11 + } proto; + + // L2 + struct { + // Ethernet + struct { + // Dst Mac + quint16 dstMacMshw; + quint32 dstMacLsw; + MacAddrMode dstMacMode; + quint16 dstMacCount; + quint16 dstMacStep; + + // srcMac + quint16 srcMacMshw; + quint32 srcMacLsw; + MacAddrMode srcMacMode; + quint16 srcMacCount; + quint16 srcMacStep; + + + quint16 vlanMask; +#define VM_UNTAGGED 0x0000 +#define VM_CVLAN_TAGGED 0x0001 +#define VM_CVLAN_TPID_OVERRIDE 0x0002 +#define VM_SVLAN_TAGGED 0x0100 +#define VM_SVLAN_TPID_OVERRIDE 0x0200 + + quint16 ctpid; + quint16 cvlanPrio : 3; + quint16 cvlanCfi : 1; + quint16 cvlanId : 13; + quint16 stpid; + quint16 svlanPrio : 3; + quint16 svlanCfi : 1; + quint16 svlanId : 13; + } eth; + } l2; + + struct { + // IP + struct { + quint8 ipMask; +#define IM_OVERRIDE_VERSION 0x01 +#define IM_OVERRIDE_HDRLEN 0x02 +#define IM_OVERRIDE_TOTLEN 0x04 +#define IM_OVERRIDE_CKSUM 0x08 +#define STREAM_DEF_IP_MASK 0x00 + + quint8 ver : 4; +#define STREAM_DEF_L3_IP_VER 0x4 + + quint8 hdrLen : 4; +#define STREAM_DEF_L3_IP_HDR_LEN 0x5 + + quint8 tos; +#define STREAM_DEF_L3_IP_TOS 0x00 + + quint16 totLen; +#define STREAM_DEF_L3_IP_TOT_LEN 0x00 + + quint16 id; +#define STREAM_DEF_L3_IP_ID 0x1234 + + quint16 flags : 3; +#define IP_FLAG_UNUSED 0x1 +#define IP_FLAG_DF 0x2 +#define IP_FLAG_MF 0x4 +#define STREAM_DEF_L3_IP_FLAGS 0x00 + + quint16 fragOfs : 13; +#define STREAM_DEF_L3_IP_FRAG_OFS 0x0000 + + quint8 ttl; +#define STREAM_DEF_L3_IP_TTL 0x7F + + quint8 proto; +#define STREAM_DEF_L3_IP_PROTO 0x00 + + quint16 cksum; +#define STREAM_DEF_L3_IP_CKSUM 0x0000 + + // Source IP + quint32 srcIp; +#define STREAM_DEF_L3_IP_SRC_IP 0x02020202 + + IpAddrMode srcIpMode; +#define STREAM_DEF_L3_IP_SRC_IP_MODE e_im_fixed + + quint16 srcIpCount; +#define STREAM_DEF_L3_IP_SRC_IP_COUNT 16 + + quint32 srcIpMask; +#define STREAM_DEF_L3_IP_SRC_IP_MASK 0xFFFFFFFF + + // Destination IP + quint32 dstIp; +#define STREAM_DEF_L3_IP_DST_IP 0x01010101 + + IpAddrMode dstIpMode; +#define STREAM_DEF_L3_IP_DST_IP_MODE e_im_fixed + + quint16 dstIpCount; +#define STREAM_DEF_L3_IP_DST_IP_COUNT 16 + + quint32 dstIpMask; +#define STREAM_DEF_L3_IP_DST_IP_MASK 0xFFFFFFFF + + // TODO: Options + } ip; + + // TODO: ARP + struct { + } arp; + } l3; + + // L4 + struct { + // TCP + struct { + quint32 tcpMask; +#define TM_OVERRIDE_HDRLEN 0x1 +#define TM_OVERRIDE_CKSUM 0x2 +#define STREAM_DEF_L4_TCP_TCP_MASK 0x00; + + quint16 srcPort; +#define STREAM_DEF_L4_TCP_SRC_PORT 8902; + + quint16 dstPort; +#define STREAM_DEF_L4_TCP_DST_PORT 80 + + quint32 seqNum; +#define STREAM_DEF_L4_TCP_SEQ_NUM 129018 + + quint32 ackNum; +#define STREAM_DEF_L4_TCP_ACK_NUM 98223 + + quint8 hdrLen : 4; +#define STREAM_DEF_L4_TCP_HDR_LEN 0x5 + + quint8 rsvd : 4; +#define STREAM_DEF_L4_TCP_RSVD 0x0 + + quint8 flags; +#define TCP_FLAG_URG 0x01 +#define TCP_FLAG_ACK 0x02 +#define TCP_FLAG_PSH 0x04 +#define TCP_FLAG_RST 0x08 +#define TCP_FLAG_SYN 0x10 +#define TCP_FLAG_FIN 0x20 +#define STREAM_DEF_L4_TCP_FLAGS 0x00 + + + quint16 window; +#define STREAM_DEF_L4_TCP_WINDOW 1024 + + quint16 cksum; +#define STREAM_DEF_L4_TCP_CKSUM 0x0000 + + quint16 urgPtr; +#define STREAM_DEF_L4_TCP_URG_PTR 0x0000 + } tcp; + + // UDP + struct { + quint32 udpMask; +#define UM_OVERRIDE_TOTLEN 0x01 +#define UM_OVERRIDE_CKSUM 0x02 +#define STREAM_DEF_L4_UDP_UDP_MASK 0x00 + + quint16 srcPort; +#define STREAM_DEF_L4_UDP_SRC_PORT 8902 + + quint16 dstPort; +#define STREAM_DEF_L4_UDP_DST_PORT 80 + + quint16 totLen; +#define STREAM_DEF_L4_UDP_TOT_LEN 0x0000 + + quint16 cksum; +#define STREAM_DEF_L4_UDP_CKSUM 0x0000 + } udp; + + // TODO: ICMP + struct { + } icmp; + + // TODO: IGMP + struct { + } igmp; + } l4; + + QString mName; + bool mIsEnabled; + +// ------------------------------------------------------- +// Methods +// ------------------------------------------------------- +public: + Stream(); + int enable(bool flag); + const QString& name() const { return mName; } + bool isEnabled() const { return mIsEnabled; } + + void setName(QString name) { mName = name; } + void setEnabled(bool isEnabled) { mIsEnabled = isEnabled; } + +private: + void InitDefaultMeta(); + void InitDefaultProto(); + void InitDefaultL2(); + void InitDefaultL3(); + void InitDefaultL3Ip(); + void InitDefaultL4(); + void InitDefaultL4Tcp(); + void InitDefaultL4Udp(); +}; + +#endif diff --git a/client/streamconfigdialog.cpp b/client/streamconfigdialog.cpp new file mode 100644 index 0000000..f29592f --- /dev/null +++ b/client/streamconfigdialog.cpp @@ -0,0 +1,677 @@ +#include +#include "streamconfigdialog.h" +#include "stream.h" + +StreamConfigDialog::StreamConfigDialog(QList *streamList, + uint streamIndex, QWidget *parent) : QDialog (parent) +{ + setupUi(this); + setupUiExtra(); + + // FIXME(MED): Assumption that streamlist and streamIndex are valid + mpStreamList = streamList; + mCurrentStreamIndex = streamIndex; + LoadCurrentStream(); + + qDebug("stream %p %d/%d loaded", + mpStreamList, mCurrentStreamIndex, mpStreamList->size()); + +// FIXME(MED): Enable this navigation +#if 0 + pbPrev->setDisabled((currStreamIdx == 0)); + pbNext->setDisabled((currStreamIdx == 2)); +#endif +} + +void StreamConfigDialog::setupUiExtra() +{ + QRegExp reHex2B("[0-9,a-f,A-F]{1,4}"); + QRegExp reHex4B("[0-9,a-f,A-F]{1,8}"); + QRegExp reMac("([0-9,a-f,A-F]{2,2}[:-]){5,5}[0-9,a-f,A-F]{2,2}"); + + // Setup default stuff that cannot be done in designer + twProto->setTabEnabled(2, FALSE); + twProto->setTabEnabled(3, FALSE); + + /* + ** Setup Validators + */ + // Meta Data + lePktLen->setValidator(new QIntValidator(MIN_PKT_LEN, MAX_PKT_LEN, this)); + + // L2 Ethernet + leDstMac->setValidator(new QRegExpValidator(reMac, this)); + leSrcMac->setValidator(new QRegExpValidator(reMac, this)); + leDstMacCount->setValidator(new QIntValidator(1, MAX_MAC_ITER_COUNT, this)); + leSrcMacCount->setValidator(new QIntValidator(1, MAX_MAC_ITER_COUNT, this)); + leCvlanTpid->setValidator(new QRegExpValidator(reHex2B, this)); + leSvlanTpid->setValidator(new QRegExpValidator(reHex2B, this)); + //leEtherType->setValidator(new QRegExpValidator(reHex2B, this)); + + /* + ** Setup Connections + */ + connect(rbSendPackets, SIGNAL(toggled(bool)), + this, SLOT(update_NumPacketsAndNumBursts())); + connect(rbSendBursts, SIGNAL(toggled(bool)), + this, SLOT(update_NumPacketsAndNumBursts())); + connect(rbModeFixed, SIGNAL(toggled(bool)), + this, SLOT(update_NumPacketsAndNumBursts())); + connect(rbModeContinuous, SIGNAL(toggled(bool)), + this, SLOT(update_NumPacketsAndNumBursts())); + + // Show "Packet Config" page by default + twTopLevel->setCurrentIndex(0); +} + +StreamConfigDialog::~StreamConfigDialog() +{ +} + +void StreamConfigDialog::on_cmbDstMacMode_currentIndexChanged(QString mode) +{ + if (mode == "Fixed") + leDstMacCount->setEnabled(FALSE); + else + leDstMacCount->setEnabled(TRUE); +} + +void StreamConfigDialog::on_pbPrev_clicked() +{ +#if 0 + StoreCurrentStream(currStreamIdx); + currStreamIdx--; + LoadCurrentStream(currStreamIdx); + + pbPrev->setDisabled((currStreamIdx == 0)); + pbNext->setDisabled((currStreamIdx == 2)); +#endif +} + +void StreamConfigDialog::on_pbNext_clicked() +{ +#if 0 + StoreCurrentStream(currStreamIdx); + currStreamIdx++; + LoadCurrentStream(currStreamIdx); + + pbPrev->setDisabled((currStreamIdx == 0)); + pbNext->setDisabled((currStreamIdx == 2)); +#endif +} + +void StreamConfigDialog::on_rbFtLlcSnap_toggled(bool checked) +{ + if (checked) + { + leDsap->setText("AA"); + leSsap->setText("AA"); + leControl->setText("03"); + } +} + +void StreamConfigDialog::on_rbL3Ipv4_toggled(bool checked) +{ + if (checked) + { + swL3Proto->setCurrentIndex(0); + twProto->setTabEnabled(2, TRUE); + twProto->setTabText(2, "L3 (IPv4)"); + leType->setText("08 00"); + } + else + { + twProto->setTabEnabled(2, FALSE); + twProto->setTabText(2, "L3"); + } +} + +void StreamConfigDialog::on_rbL3Arp_toggled(bool checked) +{ + if (checked) + { + swL3Proto->setCurrentIndex(1); + twProto->setTabEnabled(2, TRUE); + twProto->setTabText(2, "L3 (ARP)"); + leType->setText("08 06"); + } + else + { + twProto->setTabEnabled(2, FALSE); + twProto->setTabText(2, "L3"); + } +} + +void StreamConfigDialog::on_rbL4Icmp_toggled(bool checked) +{ + QString str; + + if (checked) + { + swL4Proto->setCurrentIndex(2); + twProto->setTabEnabled(3, TRUE); + twProto->setTabText(3, "L4 (ICMP)"); + leIpProto->setText(uintToHexStr(IP_PROTO_ICMP, str, 1)); + } + else + { + twProto->setTabEnabled(3, FALSE); + twProto->setTabText(3, "L4"); + } +} + +void StreamConfigDialog::on_rbL4Igmp_toggled(bool checked) +{ + QString str; + + if (checked) + { + swL4Proto->setCurrentIndex(3); + twProto->setTabEnabled(3, TRUE); + twProto->setTabText(3, "L4 (IGMP)"); + leIpProto->setText(uintToHexStr(IP_PROTO_IGMP, str, 1)); + } + else + { + twProto->setTabEnabled(3, FALSE); + twProto->setTabText(3, "L4"); + } +} + +void StreamConfigDialog::on_rbL4Tcp_toggled(bool checked) +{ + QString str; + + if (checked) + { + swL4Proto->setCurrentIndex(0); + twProto->setTabEnabled(3, TRUE); + twProto->setTabText(3, "L4 (TCP)"); + leIpProto->setText(uintToHexStr(IP_PROTO_TCP, str, 1)); + } + else + { + twProto->setTabEnabled(3, FALSE); + twProto->setTabText(3, "L4"); + } +} + +void StreamConfigDialog::on_rbL4Udp_toggled(bool checked) +{ + QString str; + + if (checked) + { + swL4Proto->setCurrentIndex(1); + twProto->setTabEnabled(3, TRUE); + twProto->setTabText(3, "L4 (UDP)"); + leIpProto->setText(uintToHexStr(IP_PROTO_UDP, str, 1)); + } + else + { + twProto->setTabEnabled(3, FALSE); + twProto->setTabText(3, "L4"); + } +} + +void StreamConfigDialog::on_rbL4Other_toggled(bool checked) +{ + if (checked) + leIpProto->setEnabled(true); + else + leIpProto->setEnabled(false); +} + +void StreamConfigDialog::update_NumPacketsAndNumBursts() +{ + if (rbSendPackets->isChecked() && rbModeFixed->isChecked()) + leNumPackets->setEnabled(true); + else + leNumPackets->setEnabled(false); + + if (rbSendBursts->isChecked() && rbModeFixed->isChecked()) + leNumBursts->setEnabled(true); + else + leNumBursts->setEnabled(false); +} + +QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets) +{ + int i; + QChar zero('0'); + + hexStr = ""; + + for (i = octets; i > 0; i--) + { + ushort byte; + QString str1 = "%1"; + QString str; + + byte = num & 0xff; + str = str1.arg(byte, 2, 16, zero).append(' '); + hexStr.prepend(str); + num = num >> 8; + } + + return hexStr; +} + +#if 0 +void StreamConfigDialog::on_lePattern_editingFinished() +{ + ulong num = 0; + bool isOk; + QString str; + + num = lePattern->text().remove(QChar(' ')).toULong(&isOk, 16); + qDebug("editfinished (%s | %x)\n", lePattern->text().toAscii().data(), num); + lePattern->setText(uintToHexStr(num, str, 4)); + qDebug("editfinished (%s | %x)\n", lePattern->text().toAscii().data(), num); +} +#endif + +void StreamConfigDialog::LoadCurrentStream() +{ + Stream *pStream = &((*mpStreamList)[mCurrentStreamIndex]); + QString str; + + qDebug("loading pStream %p", pStream); + + // Meta Data + { + cmbPatternMode->setCurrentIndex(pStream->meta.patternMode); + lePattern->setText(uintToHexStr(pStream->meta.pattern, str, 4)); + + cmbPktLenMode->setCurrentIndex(pStream->meta.lenMode); + lePktLen->setText(str.setNum(pStream->meta.frameLen)); + lePktLenMin->setText(str.setNum(pStream->meta.frameLenMin)); + lePktLenMax->setText(str.setNum(pStream->meta.frameLenMax)); + } + + // Protocols + { + qDebug("ft = %d\n", pStream->proto.ft); + switch(pStream->proto.ft) + { + case Stream::e_ft_none: + rbFtNone->setChecked(TRUE); + break; + case Stream::e_ft_eth_2: + rbFtEthernet2->setChecked(TRUE); + break; + case Stream::e_ft_802_3_raw: + rbFt802Dot3Raw->setChecked(TRUE); + break; + case Stream::e_ft_802_3_llc: + rbFt802Dot3Llc->setChecked(TRUE); + break; + case Stream::e_ft_snap: + rbFtLlcSnap->setChecked(TRUE); + break; + } + leDsap->setText(uintToHexStr(pStream->proto.dsap, str, 1)); + leSsap->setText(uintToHexStr(pStream->proto.ssap, str, 1)); + leControl->setText(uintToHexStr(pStream->proto.ctl, str, 1)); + leOui->setText(uintToHexStr((pStream->proto.ouiMsb << 16 + pStream->proto.ouiLshw), str, 3)); + + leType->setText(uintToHexStr(pStream->proto.etherType, str, 2)); + + // Check for specific supported protocols first ... + if (pStream->proto.etherType == ETH_TYP_IP) + rbL3Ipv4->setChecked(TRUE); + else if (pStream->proto.etherType == ETH_TYP_ARP) + rbL3Arp->setChecked(TRUE); + + // ... then for None/Other + rbL3None->setChecked((pStream->proto.protoMask & PM_L3_PROTO_NONE) > 0); + rbL3Other->setChecked((pStream->proto.protoMask & PM_L3_PROTO_OTHER) > 0); + + // Check for specific supported protocols first ... + if (pStream->proto.ipProto == IP_PROTO_ICMP) + rbL4Icmp->setChecked(TRUE); + else if (pStream->proto.ipProto == IP_PROTO_IGMP) + rbL4Igmp->setChecked(TRUE); + else if (pStream->proto.ipProto == IP_PROTO_TCP) + rbL4Tcp->setChecked(TRUE); + else if (pStream->proto.ipProto == IP_PROTO_UDP) + rbL4Udp->setChecked(TRUE); + + // ... then for None/Other + rbL4None->setChecked((pStream->proto.protoMask & PM_L4_PROTO_NONE) > 0); + rbL4Other->setChecked((pStream->proto.protoMask & PM_L4_PROTO_OTHER) > 0); + } + + // L2 + { + // L2 | Ethernet + { + leDstMac->setText(uintToHexStr(pStream->l2.eth.dstMacMshw, str, 2) + + uintToHexStr(pStream->l2.eth.dstMacLsw, str, 4)); + cmbDstMacMode->setCurrentIndex(pStream->l2.eth.dstMacMode); + leDstMacCount->setText(str.setNum(pStream->l2.eth.dstMacCount)); + leDstMacStep->setText(str.setNum(pStream->l2.eth.dstMacStep)); + + leSrcMac->setText(uintToHexStr(pStream->l2.eth.srcMacMshw, str, 2) + + uintToHexStr(pStream->l2.eth.srcMacLsw, str, 4)); + cmbSrcMacMode->setCurrentIndex(pStream->l2.eth.srcMacMode); + leSrcMacCount->setText(str.setNum(pStream->l2.eth.srcMacCount)); + leSrcMacStep->setText(str.setNum(pStream->l2.eth.srcMacStep)); + + cmbCvlanPrio->setCurrentIndex(pStream->l2.eth.cvlanPrio); + cmbCvlanCfi->setCurrentIndex(pStream->l2.eth.cvlanCfi); + leCvlanId->setText(str.setNum(pStream->l2.eth.cvlanId)); + leCvlanTpid->setText(str.setNum(pStream->l2.eth.ctpid)); + cbCvlanTpidOverride->setChecked((pStream->l2.eth.vlanMask & VM_CVLAN_TPID_OVERRIDE) > 0); + gbCvlan->setChecked((pStream->l2.eth.vlanMask & VM_CVLAN_TAGGED) > 0); + + cmbSvlanPrio->setCurrentIndex(pStream->l2.eth.svlanPrio); + cmbSvlanCfi->setCurrentIndex(pStream->l2.eth.svlanCfi); + leSvlanId->setText(str.setNum(pStream->l2.eth.svlanId)); + leSvlanTpid->setText(str.setNum(pStream->l2.eth.stpid)); + cbSvlanTpidOverride->setChecked((pStream->l2.eth.vlanMask & VM_SVLAN_TPID_OVERRIDE) > 0); + gbSvlan->setChecked((pStream->l2.eth.vlanMask & VM_SVLAN_TAGGED) > 0); + } + } + + // L3 + { + // L3 | IP + { + leIpVersion->setText(str.setNum(pStream->l3.ip.ver)); + cbIpVersionOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_VERSION) > 0); + leIpHdrLen->setText(str.setNum(pStream->l3.ip.hdrLen)); + cbIpHdrLenOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_HDRLEN) > 0); + + leIpTos->setText(uintToHexStr(pStream->l3.ip.tos, str, 1)); + + leIpLength->setText(str.setNum(pStream->l3.ip.totLen)); + cbIpLengthOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_TOTLEN) > 0); + + leIpId->setText(uintToHexStr(pStream->l3.ip.id, str, 2)); + leIpFragOfs->setText(str.setNum(pStream->l3.ip.fragOfs)); + cbIpFlagsDf->setChecked((pStream->l3.ip.flags & IP_FLAG_DF) > 0); + cbIpFlagsMf->setChecked((pStream->l3.ip.flags & IP_FLAG_MF) > 0); + + leIpTtl->setText(str.setNum(pStream->l3.ip.ttl)); + leIpProto->setText(uintToHexStr(pStream->l3.ip.proto, str, 1)); + + leIpCksum->setText(uintToHexStr(pStream->l3.ip.cksum, str, 2)); + cbIpCksumOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_CKSUM) > 0); + + leIpSrcAddr->setText(QHostAddress(pStream->l3.ip.srcIp).toString()); + cmbIpSrcAddrMode->setCurrentIndex(pStream->l3.ip.srcIpMode); + leIpSrcAddrCount->setText(str.setNum(pStream->l3.ip.srcIpCount)); + leIpSrcAddrMask->setText(QHostAddress(pStream->l3.ip.srcIpMask).toString()); + + leIpDstAddr->setText(QHostAddress(pStream->l3.ip.dstIp).toString()); + cmbIpDstAddrMode->setCurrentIndex(pStream->l3.ip.dstIpMode); + leIpDstAddrCount->setText(str.setNum(pStream->l3.ip.dstIpCount)); + leIpDstAddrMask->setText(QHostAddress(pStream->l3.ip.dstIpMask).toString()); + } + + // L3 | ARP + { + // TODO + } + } + + // L4 + { + // L4 | TCP + { + leTcpSrcPort->setText(str.setNum(pStream->l4.tcp.srcPort)); + leTcpDstPort->setText(str.setNum(pStream->l4.tcp.dstPort)); + + leTcpSeqNum->setText(str.setNum(pStream->l4.tcp.seqNum)); + leTcpAckNum->setText(str.setNum(pStream->l4.tcp.ackNum)); + + leTcpHdrLen->setText(str.setNum(pStream->l4.tcp.hdrLen)); + cbTcpHdrLenOverride->setChecked((pStream->l4.tcp.tcpMask & TM_OVERRIDE_HDRLEN) > 0); + + leTcpWindow->setText(str.setNum(pStream->l4.tcp.window)); + + leTcpCksum->setText(str.setNum(pStream->l4.tcp.cksum)); + cbTcpCksumOverride->setChecked((pStream->l4.tcp.tcpMask & TM_OVERRIDE_CKSUM) > 0); + + leTcpUrgentPointer->setText(str.setNum(pStream->l4.tcp.urgPtr)); + + cbTcpFlagsUrg->setChecked((pStream->l4.tcp.flags & TCP_FLAG_URG) > 0); + cbTcpFlagsAck->setChecked((pStream->l4.tcp.flags & TCP_FLAG_ACK) > 0); + cbTcpFlagsPsh->setChecked((pStream->l4.tcp.flags & TCP_FLAG_PSH) > 0); + cbTcpFlagsRst->setChecked((pStream->l4.tcp.flags & TCP_FLAG_RST) > 0); + cbTcpFlagsSyn->setChecked((pStream->l4.tcp.flags & TCP_FLAG_SYN) > 0); + cbTcpFlagsFin->setChecked((pStream->l4.tcp.flags & TCP_FLAG_FIN) > 0); + } + + // L4 | UDP + { + leUdpSrcPort->setText(str.setNum(pStream->l4.udp.srcPort)); + leUdpDstPort->setText(str.setNum(pStream->l4.udp.dstPort)); + + leUdpLength->setText(str.setNum(pStream->l4.udp.totLen)); + cbUdpLengthOverride->setChecked((pStream->l4.udp.udpMask & UM_OVERRIDE_TOTLEN) > 0); + + leUdpCksum->setText(str.setNum(pStream->l4.udp.cksum)); + cbUdpCksumOverride->setChecked((pStream->l4.udp.udpMask & UM_OVERRIDE_CKSUM) > 0); + } + + // L4 | ICMP + { + // TODO + } + + // L4 | IGMP + { + // TODO + } + } +} + +void StreamConfigDialog::StoreCurrentStream() +{ + Stream *pStream = &(*mpStreamList)[mCurrentStreamIndex]; + QString str; + bool isOk; + + qDebug("storing pStream %p", pStream); + + // Meta Data + pStream->meta.patternMode = (Stream::DataPatternMode) cmbPatternMode->currentIndex(); + pStream->meta.pattern = lePattern->text().remove(QChar(' ')).toULong(&isOk, 16); + + pStream->meta.lenMode = (Stream::FrameLengthMode) cmbPktLenMode->currentIndex(); + pStream->meta.frameLen = lePktLen->text().toULong(&isOk); + pStream->meta.frameLenMin = lePktLenMin->text().toULong(&isOk); + pStream->meta.frameLenMax = lePktLenMax->text().toULong(&isOk); + + // Protocols + { + if (rbFtNone->isChecked()) + pStream->proto.ft = Stream::e_ft_none; + else if (rbFtEthernet2->isChecked()) + pStream->proto.ft = Stream::e_ft_eth_2; + else if (rbFt802Dot3Raw->isChecked()) + pStream->proto.ft = Stream::e_ft_802_3_raw; + else if (rbFt802Dot3Llc->isChecked()) + pStream->proto.ft = Stream::e_ft_802_3_llc; + else if (rbFtLlcSnap->isChecked()) + pStream->proto.ft = Stream::e_ft_snap; + + qDebug("store ft = %d\n", pStream->proto.ft); + + pStream->proto.dsap = leDsap->text().remove(QChar(' ')).toULong(&isOk, 16); + pStream->proto.ssap = leSsap->text().remove(QChar(' ')).toULong(&isOk, 16); + pStream->proto.ctl = leControl->text().remove(QChar(' ')).toULong(&isOk, 16); + pStream->proto.ouiMsb = leOui->text().remove(QChar(' ')).toULong(&isOk, 16) >> 16; + pStream->proto.ouiLshw = 0x0000FFFF & leOui->text().remove(QChar(' ')).toULong(&isOk, 16); + pStream->proto.etherType = leType->text().remove(QChar(' ')).toULong(&isOk, 16); + + pStream->proto.ipProto = leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16); + + // Just check for None/Other - no need to do anything for specific supported protocols + pStream->proto.protoMask = 0; + if (rbL3None->isChecked()) + pStream->proto.protoMask |= PM_L3_PROTO_NONE; + else if (rbL3Other->isChecked()) + pStream->proto.protoMask |= PM_L3_PROTO_OTHER; + + if (rbL4None->isChecked()) + pStream->proto.protoMask |= PM_L4_PROTO_NONE; + else if (rbL4Other->isChecked()) + pStream->proto.protoMask |= PM_L4_PROTO_OTHER; + } + + // L2 + { + // L2 | Ethernet + { + pStream->l2.eth.dstMacMshw = leDstMac->text().remove(QChar(' ')).left(4).toULong(&isOk, 16); + pStream->l2.eth.dstMacLsw = leDstMac->text().remove(QChar(' ')).right(8).toULong(&isOk, 16); + pStream->l2.eth.dstMacMode = (Stream::MacAddrMode) cmbDstMacMode->currentIndex(); + pStream->l2.eth.dstMacCount = leDstMacCount->text().toULong(&isOk); + pStream->l2.eth.dstMacStep = leDstMacStep->text().toULong(&isOk); + + pStream->l2.eth.srcMacMshw = leSrcMac->text().remove(QChar(' ')).left(4).toULong(&isOk, 16); + pStream->l2.eth.srcMacLsw = leSrcMac->text().remove(QChar(' ')).right(8).toULong(&isOk, 16); + pStream->l2.eth.srcMacMode = (Stream::MacAddrMode) cmbSrcMacMode->currentIndex(); + pStream->l2.eth.srcMacCount = leSrcMacCount->text().toULong(&isOk); + pStream->l2.eth.srcMacStep = leSrcMacStep->text().toULong(&isOk); + + pStream->l2.eth.vlanMask = 0; + + pStream->l2.eth.cvlanPrio = cmbCvlanPrio->currentIndex(); + pStream->l2.eth.cvlanCfi = cmbCvlanCfi->currentIndex(); + pStream->l2.eth.cvlanId = leCvlanId->text().toULong(&isOk); + pStream->l2.eth.ctpid = leCvlanTpid->text().remove(QChar(' ')).toULong(&isOk); + if (cbCvlanTpidOverride->isChecked()) + pStream->l2.eth.vlanMask |= VM_CVLAN_TPID_OVERRIDE; + if (gbCvlan->isChecked()) + pStream->l2.eth.vlanMask |= VM_CVLAN_TAGGED; + + pStream->l2.eth.svlanPrio = cmbSvlanPrio->currentIndex(); + pStream->l2.eth.svlanCfi = cmbSvlanCfi->currentIndex(); + pStream->l2.eth.svlanId = leSvlanId->text().toULong(&isOk); + pStream->l2.eth.stpid = leSvlanTpid->text().remove(QChar(' ')).toULong(&isOk); + if (cbSvlanTpidOverride->isChecked()) + pStream->l2.eth.vlanMask |= VM_SVLAN_TPID_OVERRIDE; + if (gbSvlan->isChecked()) + pStream->l2.eth.vlanMask |= VM_SVLAN_TAGGED; + } + } + + // L3 + { + // L3 | IP + { + pStream->l3.ip.ipMask = 0; + + pStream->l3.ip.ver = leIpVersion->text().toULong(&isOk); + if (cbIpVersionOverride->isChecked()) + pStream->l3.ip.ipMask |= IM_OVERRIDE_VERSION; + pStream->l3.ip.hdrLen = leIpHdrLen->text().toULong(&isOk); + if (cbIpHdrLenOverride->isChecked()) + pStream->l3.ip.ipMask |= IM_OVERRIDE_HDRLEN; + + pStream->l3.ip.tos = leIpTos->text().toULong(&isOk, 16); + + pStream->l3.ip.totLen = leIpLength->text().toULong(&isOk); + if (cbIpLengthOverride->isChecked()) + pStream->l3.ip.ipMask |= IM_OVERRIDE_TOTLEN; + + pStream->l3.ip.id = leIpId->text().remove(QChar(' ')).toULong(&isOk, 16); + pStream->l3.ip.fragOfs = leIpFragOfs->text().toULong(&isOk); + if (cbIpFlagsDf->isChecked()) pStream->l3.ip.ipMask |= IP_FLAG_DF; + if (cbIpFlagsMf->isChecked()) pStream->l3.ip.ipMask |= IP_FLAG_MF; + + pStream->l3.ip.ttl = leIpTtl->text().toULong(&isOk); + pStream->l3.ip.proto = leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16); + + pStream->l3.ip.cksum = leIpCksum->text().remove(QChar(' ')).toULong(&isOk); + if (cbIpCksumOverride->isChecked()) + pStream->l3.ip.ipMask |= IM_OVERRIDE_CKSUM; + + pStream->l3.ip.srcIp = QHostAddress(leIpSrcAddr->text()).toIPv4Address(); + pStream->l3.ip.srcIpMode = (Stream::IpAddrMode) cmbIpSrcAddrMode->currentIndex(); + pStream->l3.ip.srcIpCount = leIpSrcAddrCount->text().toULong(&isOk); + pStream->l3.ip.srcIpMask = QHostAddress(leIpSrcAddrMask->text()).toIPv4Address(); + + pStream->l3.ip.dstIp = QHostAddress(leIpDstAddr->text()).toIPv4Address(); + pStream->l3.ip.dstIpMode = (Stream::IpAddrMode) cmbIpDstAddrMode->currentIndex(); + pStream->l3.ip.dstIpCount = leIpDstAddrCount->text().toULong(&isOk); + pStream->l3.ip.dstIpMask = QHostAddress(leIpDstAddrMask->text()).toIPv4Address(); + } + + // L3 | ARP + { + // TODO + } + } + + // L4 + { + // L4 | TCP + { + pStream->l4.tcp.tcpMask = 0; + + pStream->l4.tcp.srcPort = leTcpSrcPort->text().toULong(&isOk); + pStream->l4.tcp.dstPort = leTcpDstPort->text().toULong(&isOk); + + pStream->l4.tcp.seqNum = leTcpSeqNum->text().toULong(&isOk); + pStream->l4.tcp.ackNum = leTcpAckNum->text().toULong(&isOk); + + pStream->l4.tcp.hdrLen = leTcpHdrLen->text().toULong(&isOk); + if (cbTcpHdrLenOverride->isChecked()) + pStream->l4.tcp.tcpMask |= TM_OVERRIDE_HDRLEN; + + pStream->l4.tcp.window = leTcpWindow->text().toULong(&isOk); + + pStream->l4.tcp.cksum = leTcpCksum->text().remove(QChar(' ')).toULong(&isOk); + if (cbTcpCksumOverride->isChecked()) + pStream->l4.tcp.tcpMask |= TM_OVERRIDE_CKSUM; + + pStream->l4.tcp.urgPtr = leTcpUrgentPointer->text().toULong(&isOk); + + pStream->l4.tcp.flags = 0; + if (cbTcpFlagsUrg->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_URG; + if (cbTcpFlagsAck->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_ACK; + if (cbTcpFlagsPsh->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_PSH; + if (cbTcpFlagsRst->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_RST; + if (cbTcpFlagsSyn->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_SYN; + if (cbTcpFlagsFin->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_FIN; + } + + // L4 | UDP + { + pStream->l4.udp.udpMask = 0; + + pStream->l4.udp.srcPort = leUdpSrcPort->text().toULong(&isOk); + pStream->l4.udp.dstPort = leUdpDstPort->text().toULong(&isOk); + + pStream->l4.udp.totLen = leUdpLength->text().toULong(&isOk); + if (cbUdpLengthOverride->isChecked()) pStream->l4.udp.udpMask |= UM_OVERRIDE_TOTLEN; + + pStream->l4.udp.cksum = leUdpCksum->text().remove(QChar(' ')).toULong(&isOk); + if (cbUdpCksumOverride->isChecked()) pStream->l4.udp.udpMask |= UM_OVERRIDE_CKSUM; + } + + // L4 | ICMP + { + // TODO + } + + // L4 | IGMP + { + // TODO + } + } +} +void StreamConfigDialog::on_pbOk_clicked() +{ + // Store dialog contents into stream + StoreCurrentStream(); + qDebug("stream stored"); +} + +//Junk Line for introducing a compiler error + diff --git a/client/streamconfigdialog.h b/client/streamconfigdialog.h new file mode 100644 index 0000000..95e7380 --- /dev/null +++ b/client/streamconfigdialog.h @@ -0,0 +1,58 @@ +#ifndef _STREAM_CONFIG_DIALOG_H +#define _STREAM_CONFIG_DIALOG_H + +#include +#include "ui_streamconfigdialog.h" +#include + +#define MAX_MAC_ITER_COUNT 256 +#define MIN_PKT_LEN 64 +#define MAX_PKT_LEN 1522 + +/* +** TODO +** - Improve HexStr handling +** +*/ + +class StreamConfigDialog : public QDialog, public Ui::StreamConfigDialog +{ + Q_OBJECT +public: + StreamConfigDialog(QList *streamList, uint streamIndex, + QWidget *parent = 0); + ~StreamConfigDialog(); + +private: + QList *mpStreamList; + uint mCurrentStreamIndex; + + void setupUiExtra(); + void LoadCurrentStream(); + void StoreCurrentStream(); + +private slots: + void on_cmbDstMacMode_currentIndexChanged(QString mode); + void on_pbPrev_clicked(); + void on_pbNext_clicked(); + + void on_rbFtLlcSnap_toggled(bool checked); + + void on_rbL3Ipv4_toggled(bool checked); + void on_rbL3Arp_toggled(bool checked); + + void on_rbL4Icmp_toggled(bool checked); + void on_rbL4Igmp_toggled(bool checked); + void on_rbL4Tcp_toggled(bool checked); + void on_rbL4Udp_toggled(bool checked); + void on_rbL4Other_toggled(bool checked); + + void update_NumPacketsAndNumBursts(); + + void on_pbOk_clicked(); +}; + +QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets); + +#endif + diff --git a/client/streamconfigdialog.ui b/client/streamconfigdialog.ui new file mode 100644 index 0000000..85f29e3 --- /dev/null +++ b/client/streamconfigdialog.ui @@ -0,0 +1,3224 @@ + + StreamConfigDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 554 + 521 + + + + Dialog + + + QLineEdit:enabled[inputMask = "HH; "], +QLineEdit:enabled[inputMask = "HH HH; "], +QLineEdit:enabled[inputMask = "HH HH HH; "], +QLineEdit:enabled[inputMask = "HH HH HH HH; "], +QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff } + + + + true + + + + + + + + + 0 + + + + Packet Config + + + + + + Qt::Horizontal + + + + 171 + 20 + + + + + + + + Data Pattern + + + + + + + Fixed + + + + + Increment + + + + + Decrement + + + + + Random + + + + + + + + HH HH HH HH; + + + + + + 11 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Frame Length (including CRC) + + + + + + + Fixed + + + + + Increment + + + + + Decrement + + + + + Random + + + + + + + + Min + + + + + + + 64 + + + 32767 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 64 + + + 32767 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Max + + + + + + + 64 + + + 32767 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 2 + + + + Protocols + + + + + + Frame Type + + + + + + + + + + None + + + false + + + + + + + Ethernet II + + + false + + + + + + + 802.3 Raw + + + + + + + 802.3 LLC + + + true + + + + + + + LLC SNAP + + + + + + + + + Qt::Vertical + + + + + + + + + DSAP + + + + + + + true + + + HH; + + + + + + + SSAP + + + + + + + true + + + HH; + + + + + + + Control + + + + + + + true + + + HH; + + + + + + + OUI + + + + + + + true + + + HH HH HH; + + + + + + + Type + + + + + + + true + + + HH HH; + + + + + + + + + + + + + + L3 + + + + + + None + + + true + + + + + + + IPv4 + + + false + + + + + + + ARP + + + + + + + Other + + + + + + + + + + L4 + + + + + + None + + + true + + + + + + + false + + + ICMP + + + + + + + false + + + IGMP + + + + + + + false + + + TCP + + + + + + + false + + + UDP + + + + + + + false + + + Other + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + L2 + + + + + + Ethernet + + + + + + Destination + + + + + + + HH HH HH HH HH HH; + + + + + + + + + + + Fixed + + + + + Increment + + + + + Decrement + + + + + + + + Count + + + + + + + false + + + 1 + + + 1 + + + + + + + Step + + + + + + + false + + + 1 + + + 1 + + + + + + + Source + + + + + + + HH HH HH HH HH HH; + + + + + + + + + + + Fixed + + + + + Increment + + + + + Decrement + + + + + + + + Count + + + + + + + false + + + 1 + + + + + + + Step + + + + + + + false + + + 1 + + + 1 + + + + + + + + + + VLAN/CVLAN + + + true + + + false + + + + + + Priority + + + + + + + CFI + + + + + + + VLAN + + + + + + + false + + + Override TPID + + + + + + + false + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + + + + false + + + + 0 + + + + + 1 + + + + + + + + false + + + 0 + + + + + + + false + + + HH HH; + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + SVLAN + + + true + + + false + + + + + + Priority + + + + + + + CFI + + + + + + + VLAN + + + + + + + false + + + Override TPID + + + + + + + false + + + + 0 + + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + + + + false + + + + 0 + + + + + 1 + + + + + + + + false + + + 0 + + + + + + + false + + + HH HH; + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + L3 + + + + + + 0 + + + + + + + + + Override Version + + + + + + + false + + + 4 + + + + + + + Override Header Length + + + + + + + false + + + 5 + + + + + + + TOS/DSCP + + + + + + + HH; + + + + + + + + + + false + + + ... + + + + + + + Override Length + + + + + + + false + + + + + + + Identification + + + + + + + HH HH; + + + + + + + + + Qt::Vertical + + + + + + + + + Fragment Offset + + + + + + + + + + Don't Fragment + + + + + + + More Fragments + + + + + + + Time To Live (TTL) + + + + + + + 64 + + + + + + + Protocol + + + + + + + false + + + + + + + + + + Override Checksum + + + + + + + false + + + HH HH; + + + + + + + + + + + + false + + + + + + Mode + + + + + + + Count + + + + + + + Mask + + + + + + + Source + + + + + + + 009.009.009.009; + + + ... + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + Fixed + + + + + Increment Host + + + + + Decrement Host + + + + + Random Host + + + + + + + + + + + + + + + 255.255.255.255 + + + + + + + Destination + + + + + + + 000.000.000.000; + + + ... + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + Fixed + + + + + Increment Host + + + + + Decrement Host + + + + + Random Host + + + + + + + + + + + + + + + 255.255.255.255 + + + + + + + + + + + + Options + + + + + + + false + + + TODO + + + + + + + false + + + ... + + + + + + + + + Qt::Vertical + + + + 470 + 16 + + + + + + + + + + + 105 + 100 + 296 + 76 + + + + ARP : TODO + + + Qt::AlignCenter + + + + + + + + + + L4 + + + + + + 1 + + + + + + + + + Source Port + + + + + + + + + + Destination Port + + + + + + + + + + Sequence Number + + + + + + + + + + Acknowledgement Number + + + + + + + + + + Override Header Length (x4) + + + + + + + false + + + + + + + Window + + + + + + + + + + Override Checksum + + + + + + + false + + + HH HH; + + + + + + + Urgent Pointer + + + + + + + + + + + + Qt::Vertical + + + + + + + Flags + + + + + + URG + + + + + + + ACK + + + + + + + PSH + + + + + + + RST + + + + + + + SYN + + + + + + + FIN + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 181 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + Source Port + + + + + + + + + + Destination Port + + + + + + + + + + Override Length + + + + + + + false + + + + + + + Override Checksum + + + + + + + false + + + HH HH; + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + ICMP: TODO + + + + + + + + + + + IGMP: TODO + + + + + + + + + + + + + + + + Stream Control + + + + + + Send + + + + + + Packets + + + true + + + + + + + Bursts + + + + + + + + + + Numbers + + + + + + Number of Packets + + + leNumPackets + + + + + + + 1 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Number of Bursts + + + leNumPackets + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Packets per Burst + + + leNumPackets + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + After this stream + + + + + + Stop + + + + + + + Goto Next Stream + + + true + + + + + + + Goto Stream + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Mode + + + + + + Fixed + + + true + + + + + + + Continuous + + + + + + + + + + Qt::Horizontal + + + + 41 + 20 + + + + + + + + Qt::Horizontal + + + + + + + Rate + + + false + + + false + + + + + + Packets/Sec + + + leNumPackets + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Bursts/Sec + + + leNumPackets + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + true + + + Gaps + + + false + + + false + + + + + + + + + icons/gaps.png + + + + + + + ISG + + + leNumPackets + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + IPG + + + leNumPackets + + + + + + + IBG + + + leNumPackets + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Packet View + + + + + + Qt::Vertical + + + + true + + + + New Column + + + + + Ethernet + + + + DstMac: 00:00:00:00:00:00 + + + + + SrcMac: 00:00:00:00:00:00 + + + + + EtherType: IP (0800) + + + + + + IP + + + + Version: 4 + + + + + Header Length: 20 + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;">0004 00 00 00 00 00 00</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p></body></html> + + + + + + + + + + + + + + Prev + + + + + + + Next + + + + + + + Qt::Horizontal + + + + 191 + 20 + + + + + + + + OK + + + true + + + + + + + Cancel + + + + + + + + + + HexLineEdit + QLineEdit +
hexlineedit.h
+
+
+ + twTopLevel + cmbPatternMode + lePattern + cmbPktLenMode + lePktLen + lePktLenMin + lePktLenMax + twProto + leDstMac + cmbDstMacMode + leDstMacCount + leDstMacStep + leSrcMac + cmbSrcMacMode + leSrcMacCount + leSrcMacStep + gbCvlan + cmbCvlanPrio + cmbCvlanCfi + leCvlanId + cbCvlanTpidOverride + leCvlanTpid + gbSvlan + cmbSvlanPrio + cmbSvlanCfi + leSvlanId + cbSvlanTpidOverride + leSvlanTpid + + + + + + + cbCvlanTpidOverride + toggled(bool) + leCvlanTpid + setEnabled(bool) + + + 147 + 238 + + + 147 + 238 + + + + + cbSvlanTpidOverride + toggled(bool) + leSvlanTpid + setEnabled(bool) + + + 147 + 238 + + + 147 + 238 + + + + + gbCvlan + toggled(bool) + cmbCvlanPrio + setEnabled(bool) + + + 101 + 238 + + + 101 + 238 + + + + + gbCvlan + toggled(bool) + cmbCvlanCfi + setEnabled(bool) + + + 101 + 238 + + + 101 + 238 + + + + + gbCvlan + toggled(bool) + leCvlanId + setEnabled(bool) + + + 101 + 238 + + + 133 + 238 + + + + + gbCvlan + toggled(bool) + cbCvlanTpidOverride + setEnabled(bool) + + + 101 + 238 + + + 147 + 238 + + + + + gbSvlan + toggled(bool) + cmbSvlanPrio + setEnabled(bool) + + + 101 + 238 + + + 101 + 238 + + + + + gbSvlan + toggled(bool) + leSvlanId + setEnabled(bool) + + + 101 + 238 + + + 101 + 238 + + + + + gbSvlan + toggled(bool) + cbSvlanTpidOverride + setEnabled(bool) + + + 101 + 238 + + + 147 + 238 + + + + + gbSvlan + toggled(bool) + cmbSvlanCfi + setEnabled(bool) + + + 101 + 238 + + + 101 + 238 + + + + + cbUdpLengthOverride + toggled(bool) + leUdpLength + setEnabled(bool) + + + 79 + 247 + + + 99 + 247 + + + + + cbUdpCksumOverride + toggled(bool) + leUdpCksum + setEnabled(bool) + + + 79 + 247 + + + 99 + 247 + + + + + cbIpVersionOverride + toggled(bool) + leIpVersion + setEnabled(bool) + + + 42 + 171 + + + 232 + 170 + + + + + cbIpHdrLenOverride + toggled(bool) + leIpHdrLen + setEnabled(bool) + + + 42 + 197 + + + 232 + 196 + + + + + cbIpLengthOverride + toggled(bool) + leIpLength + setEnabled(bool) + + + 42 + 252 + + + 232 + 251 + + + + + cbIpCksumOverride + toggled(bool) + leIpCksum + setEnabled(bool) + + + 383 + 274 + + + 506 + 274 + + + + + cbTcpHdrLenOverride + toggled(bool) + leTcpHdrLen + setEnabled(bool) + + + 79 + 247 + + + 99 + 247 + + + + + cbTcpCksumOverride + toggled(bool) + leTcpCksum + setEnabled(bool) + + + 79 + 247 + + + 99 + 247 + + + + + rbFtNone + toggled(bool) + lblDsap + setHidden(bool) + + + 43 + 186 + + + 137 + 185 + + + + + rbFtNone + toggled(bool) + leDsap + setHidden(bool) + + + 43 + 186 + + + 178 + 185 + + + + + rbFtNone + toggled(bool) + lblSsap + setHidden(bool) + + + 43 + 186 + + + 137 + 211 + + + + + rbFtNone + toggled(bool) + leSsap + setHidden(bool) + + + 43 + 186 + + + 178 + 211 + + + + + rbFtNone + toggled(bool) + lblControl + setHidden(bool) + + + 43 + 186 + + + 137 + 237 + + + + + rbFtNone + toggled(bool) + leControl + setHidden(bool) + + + 43 + 186 + + + 178 + 237 + + + + + rbFtNone + toggled(bool) + lblOui + setHidden(bool) + + + 43 + 186 + + + 137 + 263 + + + + + rbFtNone + toggled(bool) + leOui + setHidden(bool) + + + 43 + 186 + + + 178 + 263 + + + + + rbFtNone + toggled(bool) + lblTpe + setHidden(bool) + + + 43 + 186 + + + 137 + 289 + + + + + rbFtNone + toggled(bool) + leType + setHidden(bool) + + + 43 + 186 + + + 178 + 289 + + + + + rbFtEthernet2 + toggled(bool) + lblDsap + setHidden(bool) + + + 43 + 211 + + + 137 + 185 + + + + + rbFtEthernet2 + toggled(bool) + leDsap + setHidden(bool) + + + 43 + 211 + + + 178 + 185 + + + + + rbFtEthernet2 + toggled(bool) + lblSsap + setHidden(bool) + + + 43 + 211 + + + 137 + 211 + + + + + rbFtEthernet2 + toggled(bool) + leSsap + setHidden(bool) + + + 43 + 211 + + + 178 + 211 + + + + + rbFt802Dot3Raw + toggled(bool) + lblControl + setHidden(bool) + + + 43 + 236 + + + 137 + 237 + + + + + rbFt802Dot3Raw + toggled(bool) + leControl + setHidden(bool) + + + 43 + 236 + + + 178 + 237 + + + + + rbFtEthernet2 + toggled(bool) + lblControl + setHidden(bool) + + + 43 + 211 + + + 137 + 237 + + + + + rbFtEthernet2 + toggled(bool) + leControl + setHidden(bool) + + + 43 + 211 + + + 178 + 237 + + + + + rbFtEthernet2 + toggled(bool) + lblOui + setHidden(bool) + + + 43 + 211 + + + 137 + 263 + + + + + rbFtEthernet2 + toggled(bool) + leOui + setHidden(bool) + + + 43 + 211 + + + 178 + 263 + + + + + rbFt802Dot3Raw + toggled(bool) + lblDsap + setHidden(bool) + + + 43 + 236 + + + 137 + 185 + + + + + rbFt802Dot3Raw + toggled(bool) + leDsap + setHidden(bool) + + + 43 + 236 + + + 178 + 185 + + + + + rbFt802Dot3Raw + toggled(bool) + lblSsap + setHidden(bool) + + + 43 + 236 + + + 137 + 211 + + + + + rbFt802Dot3Raw + toggled(bool) + leSsap + setHidden(bool) + + + 43 + 236 + + + 178 + 211 + + + + + rbFt802Dot3Raw + toggled(bool) + lblControl + setHidden(bool) + + + 43 + 236 + + + 137 + 237 + + + + + rbFt802Dot3Raw + toggled(bool) + leControl + setHidden(bool) + + + 43 + 236 + + + 178 + 237 + + + + + rbFt802Dot3Raw + toggled(bool) + lblOui + setHidden(bool) + + + 43 + 236 + + + 137 + 263 + + + + + rbFt802Dot3Raw + toggled(bool) + leOui + setHidden(bool) + + + 43 + 236 + + + 178 + 263 + + + + + rbFt802Dot3Raw + toggled(bool) + lblTpe + setHidden(bool) + + + 43 + 236 + + + 137 + 289 + + + + + rbFt802Dot3Raw + toggled(bool) + leType + setHidden(bool) + + + 43 + 236 + + + 178 + 289 + + + + + pbOk + clicked() + StreamConfigDialog + accept() + + + 460 + 510 + + + 565 + 433 + + + + + pbCancel + clicked() + StreamConfigDialog + reject() + + + 543 + 510 + + + 561 + 466 + + + + + rbFtLlcSnap + toggled(bool) + leDsap + setDisabled(bool) + + + 43 + 286 + + + 178 + 185 + + + + + rbFtLlcSnap + toggled(bool) + leSsap + setDisabled(bool) + + + 43 + 286 + + + 178 + 211 + + + + + rbFtLlcSnap + toggled(bool) + leControl + setDisabled(bool) + + + 43 + 286 + + + 178 + 237 + + + + + rbL3Ipv4 + toggled(bool) + rbL4Tcp + setEnabled(bool) + + + 355 + 196 + + + 300 + 291 + + + + + rbL3Ipv4 + toggled(bool) + rbL4Udp + setEnabled(bool) + + + 355 + 196 + + + 372 + 291 + + + + + rbL3Ipv4 + toggled(bool) + rbL4Other + setEnabled(bool) + + + 355 + 196 + + + 443 + 291 + + + + + rbL3Ipv4 + toggled(bool) + rbL4Icmp + setEnabled(bool) + + + 355 + 196 + + + 372 + 267 + + + + + rbL3Ipv4 + toggled(bool) + rbL4Igmp + setEnabled(bool) + + + 355 + 196 + + + 443 + 267 + + + + + rbL3None + clicked() + rbL4None + click() + + + 300 + 196 + + + 300 + 267 + + + + + rbL3Arp + clicked() + rbL4None + click() + + + 407 + 196 + + + 300 + 267 + + + + + rbL3Other + clicked() + rbL4None + click() + + + 457 + 196 + + + 300 + 267 + + + + + rbActionGotoStream + toggled(bool) + leStreamId + setEnabled(bool) + + + 334 + 147 + + + 411 + 177 + + + + + rbSendPackets + toggled(bool) + lePacketsPerSec + setEnabled(bool) + + + 38 + 73 + + + 180 + 284 + + + + + rbSendBursts + toggled(bool) + leBurstsPerSec + setEnabled(bool) + + + 46 + 98 + + + 162 + 313 + + + + + rbSendBursts + toggled(bool) + lePacketsPerBurst + setEnabled(bool) + + + 73 + 108 + + + 225 + 184 + + + + +
diff --git a/client/streamlistmodel.cpp b/client/streamlistmodel.cpp new file mode 100644 index 0000000..9812720 --- /dev/null +++ b/client/streamlistmodel.cpp @@ -0,0 +1,119 @@ +#include "streamlistmodel.h" + +StreamListModel::StreamListModel(QObject *parent) + : QAbstractTableModel(parent) +{ + uint i; + + // Enable all streams by default + for (i=0; i= MAX_ROWS) + return QVariant(); + + if (index.column() >= MAX_COLS) + return QVariant(); + + // Check role + if (index.column() == 0) // Icon + { + if ((role == Qt::DisplayRole)) + return QString("EDIT"); + else + return QVariant(); + } + else if (index.column() == 1) // Name + { + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + return streamList[index.row()].streamName; + else + return QVariant(); + } + else if (index.column() == 2) // Enabled? + { + //if ((role == Qt::CheckStateRole) || (role == Qt::EditRole)) + // return streamList[index.row()].isEnabled ? Qt::Checked : Qt::Unchecked; + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + return streamList[index.row()].isEnabled; + else + return QVariant(); + } +} + +bool StreamListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) + { + if (index.column() == 1) // Name + streamList[index.row()].streamName = value.toString(); + else if (index.column() == 2) // Enabled? + streamList[index.row()].isEnabled = value.toBool(); + else + return false; + + return true; + } + return false; +} + +QVariant StreamListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return StreamListCols.at(section); + else + return QString("%1").arg(section+1); +} + +#if 0 +// QModelIndex StreamListModel::index (int portNum, PortStat stat, const QModelIndex & parent = QModelIndex() ) const + +void StreamListModel::on_portStatsUpdate(int port, void*stats) +{ + int i; + QModelIndex topLeft = index(port, 0, QModelIndex()); + QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex()); + + for (i = 0; i < e_STAT_MAX; i++) + dummyStats[port][i] = ((int *)stats)[i]; + + emit dataChanged(topLeft, bottomRight); +} + +#endif diff --git a/client/streamlistmodel.h b/client/streamlistmodel.h new file mode 100644 index 0000000..54c222b --- /dev/null +++ b/client/streamlistmodel.h @@ -0,0 +1,46 @@ +#ifndef _STREAM_LIST_MODEL_H +#define _STREAM_LIST_MODEL_H + +#include +#include + +static QStringList StreamListCols = (QStringList() + << "Icon" + << "Name" + << "Enable" +); + +#define MAX_ROWS 5 +#define MAX_COLS 3 + +class StreamListModel : public QAbstractTableModel +{ + Q_OBJECT + + public: + //StreamListModel(QObject *parent = 0) : QAbstractTableModel(parent) {} + StreamListModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + // QModelIndex index (int portNum, PortStat stat, const QModelIndex & parent = QModelIndex() ) const; + + public slots: +// void on_portStatsUpdate(int port, void*stats); + + private: + // FIXME: temp +//#define NUM_PORTS 2 +// int dummyStats[NUM_PORTS][e_STAT_MAX]; + struct { + QString streamName; + bool isEnabled; + } streamList[MAX_ROWS]; + +}; + +#endif diff --git a/client/streammodel.cpp b/client/streammodel.cpp new file mode 100644 index 0000000..21588b7 --- /dev/null +++ b/client/streammodel.cpp @@ -0,0 +1,218 @@ +#include "streammodel.h" +#include "portgrouplist.h" +#include "qicon.h" + +StreamModel::StreamModel(PortGroupList *p, QObject *parent) + : QAbstractTableModel(parent) +{ + pgl = p; + mCurrentPort = NULL; +} + +int StreamModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + if (mCurrentPort) + return mCurrentPort->mStreams.size(); + else + return 0; +} + +int StreamModel::columnCount(const QModelIndex &parent ) const +{ + return (int) StreamMaxFields; +} + +Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractTableModel::flags(index); + + + switch (index.column()) + { + case StreamIcon: + break; + case StreamName: + flags |= Qt::ItemIsEditable; + break; + case StreamStatus: + flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable; + break; + default: + break; + } + + return flags; +} +QVariant StreamModel::data(const QModelIndex &index, int role) const +{ + // Check for a valid index + if (!index.isValid()) + return QVariant(); + + // Check for row/column limits + if (index.row() >= mCurrentPort->mStreams.size()) + return QVariant(); + + if (index.column() >= StreamMaxFields) + return QVariant(); + + if (mCurrentPort == NULL) + return QVariant(); + + // Return data based on field and role + switch(index.column()) + { + case StreamIcon: + { + if (role == Qt::DecorationRole) + return QIcon(":/icons/stream_edit.png"); +#if 0 + else if ((role == Qt::DisplayRole)) + return QString("EDIT"); +#endif + else + return QVariant(); + break; + } + case StreamName: + { + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + return mCurrentPort->mStreams[index.row()].name(); + else + return QVariant(); + break; + } + case StreamStatus: + { + #if 0 + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + return streamList[index.row()].isEnabled; + if ((role == Qt::DisplayRole) || (role == Qt::CheckStateRole) || + #endif + if ((role == Qt::CheckStateRole) || (role == Qt::EditRole)) + { + if (mCurrentPort->mStreams[index.row()].isEnabled()) + return Qt::Checked; + else + return Qt::Unchecked; + } + else + return QVariant(); + break; + } + default: + qDebug("-------------UNHANDLED STREAM FIELD----------------"); + } + + return QVariant(); +} + +bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (mCurrentPort == NULL) + return false; + + if (index.isValid() && role == Qt::EditRole) + { + // Edit Supported Fields + switch (index.column()) + { + case StreamName: + mCurrentPort->mStreams[index.row()].setName(value.toString()); + return true; + break; + case StreamStatus: + mCurrentPort->mStreams[index.row()].setEnabled(value.toBool()); + return true; + break; + + // Edit Not Supported Fields + case StreamIcon: + return false; + break; + + // Unhandled Stream Field + default: + qDebug("-------------UNHANDLED STREAM FIELD----------------"); + break; + } + } + return false; +} + +QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + switch(section) + { + case StreamIcon: + return QString("Icon"); + break; + case StreamName: + return QString("Name"); + break; + case StreamStatus: + return QString("Enabled"); + break; + default: + qDebug("-------------UNHANDLED STREAM FIELD----------------"); + break; + } + } + else + return QString("%1").arg(section+1); + + return QVariant(); +} + +bool StreamModel::insertRows(int row, int count, const QModelIndex &parent) +{ + qDebug("insertRows() row = %d", row); + qDebug("insertRows() count = %d", count); + beginInsertRows(QModelIndex(), row, row+count-1); + for (int i = 0; i < count; i++) + mCurrentPort->mStreams.insert(row, Stream()); + endInsertRows(); + + return true; +} + +bool StreamModel::removeRows(int row, int count, const QModelIndex &parent) +{ + qDebug("removeRows() row = %d", row); + qDebug("removeRows() count = %d", count); + beginRemoveRows(QModelIndex(), row, row+count-1); + for (int i = 0; i < count; i++) + { + // FIXME(HIGH): do we need to free the removed stream? + mCurrentPort->mStreams.removeAt(row); + } + endRemoveRows(); + + return true; +} + +// --------------------- SLOTS ------------------------ + +void StreamModel::setCurrentPortIndex(const QModelIndex ¤t) +{ + if (!current.isValid() || !pgl->isPort(current)) + { + qDebug("current is either invalid or not a port"); + mCurrentPort = NULL; + } + else + { + qDebug("change to valid port"); + quint16 pg = current.internalId() >> 16; + mCurrentPort = &pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()]; + } + reset(); +} diff --git a/client/streammodel.h b/client/streammodel.h new file mode 100644 index 0000000..de648a2 --- /dev/null +++ b/client/streammodel.h @@ -0,0 +1,49 @@ +#ifndef _STREAM_MODEL_H +#define _STREAM_MODEL_H + +#include +#include "port.h" + +class PortGroupList; + +class StreamModel : public QAbstractTableModel +{ + Q_OBJECT + + enum StreamFields { + StreamIcon = 0, + StreamName, + StreamStatus, + + StreamMaxFields + }; + + Port *mCurrentPort; + PortGroupList *pgl; + + public: + StreamModel(PortGroupList *p, QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole); + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + bool insertRows (int row, int count, + const QModelIndex & parent = QModelIndex()); + bool removeRows (int row, int count, + const QModelIndex & parent = QModelIndex()); + + // FIXME(HIGH): This *is* like a kludge + QList* currentPortStreamList() + { return &mCurrentPort->mStreams; } + + public slots: + void setCurrentPortIndex(const QModelIndex ¤t); + +}; + +#endif diff --git a/common/protocol.h b/common/protocol.h new file mode 100644 index 0000000..f7c61dc --- /dev/null +++ b/common/protocol.h @@ -0,0 +1,53 @@ +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + +#define UINT8 unsigned char +#define UINT16 unsigned short +#define UINT32 unsigned int + +#define BYTESWAP4(x) \ + (((x & 0xFF000000) >> 24) | \ + ((x & 0x00FF0000) >> 8) | \ + ((x & 0x0000FF00) << 8) | \ + ((x & 0x000000FF) << 24)) + +#define BYTESWAP2(x) \ + (((x & 0xFF00) >> 8) | \ + ((x & 0x00FF) << 8)) + +// TODO: portability +#define HTONL(x) BYTESWAP4(x) +#define NTOHL(x) BYTESWAP4(x) +#define HTONS(x) BYTESWAP2(x) +#define NTOHS(x) BYTESWAP2(x) + + +typedef struct { + UINT8 ver; + UINT8 resv1; + UINT16 resv2; + UINT16 msgType; + UINT16 msgLen; +} tCommHdr; + +typedef enum { + e_MT_CapabilityReq=1, + e_MT_CapabilityInfo +} eMsgType; + +typedef enum { + e_TT_PortCapability +} eTlvType; + +typedef struct { + UINT16 tlvType; + UINT16 tlvLen; + UINT32 port; + UINT32 speed; +#define TLV_MAX_PORT_NAME 64 +#define TLV_MAX_PORT_DESC 64 + char name[TLV_MAX_PORT_NAME]; + char desc[TLV_MAX_PORT_DESC]; +} tTlvPortCapability; + +#endif diff --git a/server/abstracthost.h b/server/abstracthost.h new file mode 100644 index 0000000..38e266c --- /dev/null +++ b/server/abstracthost.h @@ -0,0 +1,12 @@ +#ifndef _ABSTRACT_HOST +#define _ABSTRACT_HOST + +class AbstractHost +{ + public: + virtual void Log(const char* str) = 0; + virtual int SendMsg(const void* msg, int size) = 0; +}; + +#endif + diff --git a/server/drone.cpp b/server/drone.cpp new file mode 100644 index 0000000..54bf9cf --- /dev/null +++ b/server/drone.cpp @@ -0,0 +1,85 @@ +#include "drone.h" + +extern int myport; // FIXME(HIGH) + +Drone::Drone(QDialog *parent) + : QDialog(parent) +{ + ui.setupUi(this); + serverPortNum = DRONE_PORT; + clientSock = NULL; + + if (myport) + serverPortNum = myport; + + rxtx = new RxTx(this); + + server = new QTcpServer(this); + connect(server, SIGNAL(newConnection()), this, SLOT(when_newConnection())); + //if (!server->listen(QHostAddress("10.0.0.1"), serverPortNum)) + if (!server->listen(QHostAddress::Any, serverPortNum)) + LogInt(tr("Unable to start the server: %1").arg(server->errorString())); + else + LogInt(tr("The server is running on %1:%2").arg(server->serverAddress().toString()).arg(server->serverPort())); +} + +void Drone::Log(const char* str) +{ + ui.teLog->append(QString(str)); +} + +int Drone::SendMsg(const void* msg, int size) +{ + qDebug("Inside SendMsg\n"); + clientSock->write((char*) msg, size); +} + +void Drone::LogInt(const QString &str) +{ + ui.teLog->append(str); +} + +void Drone::when_newConnection() +{ + if (clientSock) + { + QTcpSocket *sock; + + LogInt(tr("already connected, no new connections will be accepted\n")); + sock = server->nextPendingConnection(); + // TODO: Send reason msg to client + sock->disconnectFromHost(); + goto _exit; + } + clientSock = server->nextPendingConnection(); + LogInt(tr("accepting new connection from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort())); + connect(clientSock, SIGNAL(readyRead()), + this, SLOT(when_dataAvail())); + connect(clientSock, SIGNAL(disconnected()), + this, SLOT(when_disconnected())); + connect(clientSock, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(when_error(QAbstractSocket::SocketError))); + + +_exit: + return; +} + +void Drone::when_disconnected() +{ + LogInt(tr("closing connection from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort())); + clientSock->deleteLater(); + clientSock = NULL; +} + +void Drone::when_dataAvail() +{ + QByteArray msg = clientSock->read(1024); // FIXME: hardcoding + LogInt(QString(msg.toHex())); + rxtx->ProcessMsg(msg.constData(), msg.size()); +} + +void Drone::when_error(QAbstractSocket::SocketError socketError) +{ + LogInt(clientSock->errorString()); +} diff --git a/server/drone.h b/server/drone.h new file mode 100644 index 0000000..f99255b --- /dev/null +++ b/server/drone.h @@ -0,0 +1,36 @@ +#ifndef _DRONE_H +#define _DRONE_H + +#include +#include +#include "ui_drone.h" +#include "abstracthost.h" +#include "rxtx.h" + + +class Drone : public QDialog, AbstractHost +{ + Q_OBJECT + + public: + Drone(QDialog *parent = 0); + void Log(const char *msg); + int SendMsg(const void* msg, int msgLen); + + Ui::Drone ui; + private: + RxTx *rxtx; + QTcpServer *server; + QTcpSocket *clientSock; +#define DRONE_PORT 7878 + quint16 serverPortNum; + // Ui::Drone ui; + void LogInt(const QString &msg); + private slots: + void when_newConnection(); + void when_disconnected(); + void when_dataAvail(); + void when_error(QAbstractSocket::SocketError socketError); +}; +#endif + diff --git a/server/drone.pro b/server/drone.pro new file mode 100644 index 0000000..1fd8862 --- /dev/null +++ b/server/drone.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +CONFIG += qt +QT += network +DEFINES += HAVE_REMOTE +INCLUDEPATH += "C:\DevelLibs\WpdPack\Include" +LIBS += -L"C:\DevelLibs\WpdPack\Lib" -lwpcap +HEADERS += drone.h +FORMS += drone.ui +SOURCES += drone_main.cpp drone.cpp rxtx.cpp diff --git a/server/drone.ui b/server/drone.ui new file mode 100644 index 0000000..5caa184 --- /dev/null +++ b/server/drone.ui @@ -0,0 +1,126 @@ + + Drone + + + + 0 + 0 + 400 + 300 + + + + Drone + + + + + + 1 + + + + Status + + + + + 160 + 100 + 46 + 14 + + + + TODO + + + + + + Log + + + + + + true + + + false + + + + + + + + + + + + + Clear Log + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Exit + + + + + + + + + + + pushButton + clicked(bool) + Drone + accept() + + + 341 + 279 + + + 226 + 268 + + + + + pbClearLog + clicked() + teLog + clear() + + + 52 + 278 + + + 100 + 185 + + + + + diff --git a/server/drone_main.cpp b/server/drone_main.cpp new file mode 100644 index 0000000..5a66b6a --- /dev/null +++ b/server/drone_main.cpp @@ -0,0 +1,22 @@ +#include "drone.h" + +Drone *drone; + +//void FindDevList(void); + +int myport; + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + // FIXME(HIGH) + if (argc > 1) + myport = atoi(argv[1]); + + drone = new Drone; + //FindDevList(); + drone->show(); + return app.exec(); +} + diff --git a/server/rxtx.cpp b/server/rxtx.cpp new file mode 100644 index 0000000..7c0be69 --- /dev/null +++ b/server/rxtx.cpp @@ -0,0 +1,147 @@ +#include "rxtx.h" +#include "../common/protocol.h" +#include "qtglobal" // FIXME: needed only for qdebug + +//#define LOG(...) drone->ui.teLOG->append(QString().sprintf( __VA_ARGS__)) +//#define LOG(...) drone->LOG(QString().sprintf( __VA_ARGS__)) +#define LOG(...) {sprintf(logStr, __VA_ARGS__); host->Log(logStr);} + + +RxTx::RxTx(AbstractHost *host) +{ + pcap_if_t *d; + int i=0; + char errbuf[PCAP_ERRBUF_SIZE]; + + // Init Data + RxTx::host = host; + numPorts = 0; + alldevs = NULL; + + LOG("Retrieving the device list from the local machine\n"); + if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) + { + LOG("Error in pcap_findalldevs_ex: %s\n", errbuf); + goto _fail; + } + + /* Count number of local ports */ + for(d = alldevs; d != NULL; d = d->next) + numPorts++; + + portInfo = new PortInfo[numPorts]; + + /* Print the list */ + for(i=0, d=alldevs; d!=NULL; i++, d=d->next) + { + portInfo[i].portId = i; + portInfo[i].dev = d; +#if 1 + LOG("%d. %s", i, d->name); + if (d->description) + { + LOG(" (%s)\n", d->description); + } + else + LOG(" (No description available)\n"); +#endif + } + + if (i == 0) + { + LOG("\nNo interfaces found! Make sure WinPcap is installed.\n"); + goto _fail; + } + +_fail: + return; +} + +#if 0 +RxTx::LOG(char* fmt, ...) +{ + sprintf(logStr, fmt, _VA_ARGS_); + host->LOG(logStr); +} +#endif + +RxTx::~RxTx() +{ + pcap_freealldevs(alldevs); +} + +void RxTx::ProcessMsg(const char* msg, int len) +{ + tCommHdr *hdr; + // TODO: For now, assuming we'll get a complete msg + // but need to fix this as this is a TCP stream + + hdr = (tCommHdr*) msg; + + if (hdr->ver != 1) // FIXME:hardcoding + { + LOG("Rcvd msg with invalid version %d\n", hdr->ver); + goto _exit; + } + + qDebug("msgType - %x: %x\n", hdr->msgType, NTOHS(hdr->msgType)); + switch (NTOHS(hdr->msgType)) + { + case e_MT_CapabilityReq: + SendCapabilityInfo(); + break; + + default: + LOG("Rcvd msg with unrecognized msgType %d\n", NTOHS(hdr->msgType)); + } + +_exit: + return; +} + +void RxTx::SendCapabilityInfo(void) +{ + unsigned char *msg, *p; + unsigned int i, msgLen; + + p = msg = (unsigned char*) pktBuff; + ((tCommHdr*)(p))->ver = 1; + ((tCommHdr*)(p))->msgType = HTONS(e_MT_CapabilityInfo); + p += sizeof(tCommHdr); + + for (i = 0; i < numPorts; i++) + { + // TLV: Port Capability + ((tTlvPortCapability*)(p))->tlvType = HTONS(e_TT_PortCapability); + ((tTlvPortCapability*)(p))->tlvLen = HTONS(sizeof(tTlvPortCapability)); + ((tTlvPortCapability*)(p))->port = HTONL(portInfo[i].portId); + ((tTlvPortCapability*)(p))->speed = 0; // TODO +#if 0 + strncpy(((tTlvPortCapability*)(p))->name, + portInfo[i].dev->name, TLV_MAX_PORT_NAME); + ((tTlvPortCapability*)(p))->name[TLV_MAX_PORT_NAME-1] = 0; +#else + strcpy(((tTlvPortCapability*)(p))->name, "eth"); + //strcat(((tTlvPortCapability*)(p))->name, itoa(portInfo[i].portId, NULL, 10)); + itoa(portInfo[i].portId, &(((tTlvPortCapability*)(p))->name[3]), 10); +#endif + strncpy(((tTlvPortCapability*)(p))->desc, + portInfo[i].dev->description, TLV_MAX_PORT_DESC); + ((tTlvPortCapability*)(p))->desc[TLV_MAX_PORT_DESC -1] = 0; + p += sizeof(tTlvPortCapability); + } + msgLen = (p - msg); + ((tCommHdr*)(msg))->msgLen = HTONS(msgLen); + + logStr[0] = 0; + for (i = 0; i < msgLen >> 2; i++) + { + char word[10]; + + sprintf(word, "%08X ", HTONL(((unsigned int *)(msg))[i])); + strcat(logStr, word); + } + host->Log("Sending msg\n"); + host->Log(logStr); + host->SendMsg(pktBuff, msgLen); +} diff --git a/server/rxtx.h b/server/rxtx.h new file mode 100644 index 0000000..97eb2c3 --- /dev/null +++ b/server/rxtx.h @@ -0,0 +1,35 @@ +#ifndef _RXTX_H +#define _RXTX_H + +#include "pcap.h" +#include "abstracthost.h" + + +typedef struct +{ + unsigned int portId; + pcap_if_t *dev; +} PortInfo; + +class RxTx +{ + public: + RxTx(AbstractHost* host); + ~RxTx(); + void ProcessMsg(const char* msg, int len); + + private: + AbstractHost *host; + char logStr[1024]; + +#define MAX_PKT_SIZE 1024 + unsigned char pktBuff[MAX_PKT_SIZE]; + unsigned numPorts; + PortInfo *portInfo; + pcap_if_t *alldevs; + + //void Log(char *fmt, ...); + void SendCapabilityInfo(void); +}; + +#endif