ostinato-0.5.1/0000700000175300010010000000000012005505763012672 5ustar srivatspNoneostinato-0.5.1/.vimrc0000700000175300010010000000011612005505614014007 0ustar srivatspNoneset shiftwidth=4 set tabstop=8 set softtabstop=4 set expandtab set cindent ostinato-0.5.1/client/0000700000175300010010000000000012005505614014143 5ustar srivatspNoneostinato-0.5.1/client/about.ui0000700000175300010010000001370512005505614015625 0ustar srivatspNone About 0 0 500 327 0 0 About Ostinato 0 Ostinato 0 0 :/icons/logo.png false Qt::AlignCenter Qt::Vertical 20 21 :/icons/name.png Qt::AlignCenter Version/Revision Placeholder Qt::AlignCenter Copyright (c) 2007-2012 Srivats P. Qt::AlignCenter Qt::Vertical 20 21 Logo (c): Dhiman Sengupta Icons (c): Mark James (http://www.famfamfam.com/lab/icons/silk/) Qt::AlignCenter License <p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</p><p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p><p>You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a></p> Qt::RichText Qt::AlignCenter true Qt::Horizontal QDialogButtonBox::Ok buttonBox accepted() About accept() 353 280 286 262 ostinato-0.5.1/client/dumpview.cpp0000700000175300010010000002722612005505614016523 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "dumpview.h" //! \todo Enable Scrollbars DumpView::DumpView(QWidget *parent) : QAbstractItemView(parent) { int w, h; // NOTE: Monospaced fonts only !!!!!!!!!!! setFont(QFont("Courier")); w = fontMetrics().width('X'); h = fontMetrics().height(); mLineHeight = h; mCharWidth = w; mSelectedRow = mSelectedCol = -1; // calculate width for offset column and the whitespace that follows it // 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........ mOffsetPaneTopRect = QRect(0, 0, w*4, h); mDumpPaneTopRect = QRect(mOffsetPaneTopRect.right()+w*3, 0, w*((8*3-1)+2+(8*3-1)), h); mAsciiPaneTopRect = QRect(mDumpPaneTopRect.right()+w*3, 0, w*(8+1+8), h); qDebug("DumpView::DumpView"); } QModelIndex DumpView::indexAt(const QPoint &/*point*/) const { #if 0 int x = point.x(); int row, col; if (x > mAsciiPaneTopRect.left()) { col = (x - mAsciiPaneTopRect.left()) / mCharWidth; if (col == 8) // don't select whitespace goto _exit; else if (col > 8) // adjust for whitespace col--; } else if (x > mDumpPaneTopRect.left()) { col = (x - mDumpPaneTopRect.left()) / (mCharWidth*3); } row = point.y()/mLineHeight; if ((col < 16) && (row < ((data.size()+16)/16))) { selrow = row; selcol = col; } else goto _exit; // last row check col if ((row == (((data.size()+16)/16) - 1)) && (col >= (data.size() % 16))) goto _exit; qDebug("dumpview::selection(%d, %d)", selrow, selcol); offset = selrow * 16 + selcol; #if 0 for(int i = 0; i < model()->rowCount(parent); i++) { QModelIndex index = model()->index(i, 0, parent); if (model()->hasChildren(index)) indexAtOffset(offset, index); // Non Leaf else if ( dump.append(model()->data(index, Qt::UserRole).toByteArray()); // Leaf // FIXME: Use RawValueRole instead of UserRole } #endif } _exit: // Clear existing selection selrow = -1; #endif return QModelIndex(); } void DumpView::scrollTo(const QModelIndex &/*index*/, ScrollHint /*hint*/) { // FIXME: implement scrolling } QRect DumpView::visualRect(const QModelIndex &/*index*/) const { // FIXME: calculate actual rect return rect(); } //protected: int DumpView::horizontalOffset() const { return horizontalScrollBar()->value(); } bool DumpView::isIndexHidden(const QModelIndex &/*index*/) const { return false; } QModelIndex DumpView::moveCursor(CursorAction /*cursorAction*/, Qt::KeyboardModifiers /*modifiers*/) { // FIXME(MED): need to implement movement using cursor return currentIndex(); } void DumpView::setSelection(const QRect &/*rect*/, QItemSelectionModel::SelectionFlags flags) { // FIXME(HI): calculate indexes using rect selectionModel()->select(QModelIndex(), flags); } int DumpView::verticalOffset() const { return verticalScrollBar()->value(); } QRegion DumpView::visualRegionForSelection( const QItemSelection &/*selection*/) const { // FIXME(HI) return QRegion(rect()); } //protected slots: void DumpView::dataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) { // FIXME(HI) update(); } void DumpView::selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/) { // FIXME(HI) update(); } void DumpView::populateDump(QByteArray &dump, int &selOfs, int &selSize, QModelIndex parent) { // FIXME: Use new enum instead of Qt::UserRole //! \todo (low): generalize this for any model not just our pkt model Q_ASSERT(!parent.isValid()); qDebug("!!!! %d $$$$", dump.size()); for(int i = 0; i < model()->rowCount(parent); i++) { QModelIndex index = model()->index(i, 0, parent); Q_ASSERT(index.isValid()); // Assumption: protocol data is in bytes (not bits) qDebug("%d: %d bytes", i, model()->data(index, Qt::UserRole).toByteArray().size()); dump.append(model()->data(index, Qt::UserRole).toByteArray()); } if (selectionModel()->selectedIndexes().size()) { int j, bits; QModelIndex index; Q_ASSERT(selectionModel()->selectedIndexes().size() == 1); index = selectionModel()->selectedIndexes().at(0); if (index.parent().isValid()) { // Field // SelOfs = SUM(protocol sizes before selected field's protocol) + // SUM(field sizes before selected field) selOfs = 0; j = index.parent().row() - 1; while (j >= 0) { selOfs += model()->data(index.parent().sibling(j,0), Qt::UserRole).toByteArray().size(); j--; } bits = 0; j = index.row() - 1; while (j >= 0) { bits += model()->data(index.sibling(j,0), Qt::UserRole+1). toInt(); j--; } selOfs += bits/8; selSize = model()->data(index, Qt::UserRole).toByteArray().size(); } else { // Protocol selOfs = 0; j = index.row() - 1; while (j >= 0) { selOfs += model()->data(index.sibling(j,0), Qt::UserRole). toByteArray().size(); j--; } selSize = model()->data(index, Qt::UserRole).toByteArray().size(); } } } // TODO(LOW): rewrite this function - it's a mess! void DumpView::paintEvent(QPaintEvent* /*event*/) { QStylePainter painter(viewport()); QRect offsetRect = mOffsetPaneTopRect; QRect dumpRect = mDumpPaneTopRect; QRect asciiRect = mAsciiPaneTopRect; QPalette pal = palette(); static QByteArray data; //QByteArray ba; int selOfs = -1, selSize; int curSelOfs, curSelSize; qDebug("dumpview::paintEvent"); // FIXME(LOW): unable to set the self widget's font in constructor painter.setFont(QFont("Courier")); // set a white background painter.fillRect(rect(), QBrush(QColor(Qt::white))); if (model()) { data.clear(); populateDump(data, selOfs, selSize); } // display the offset, dump and ascii panes 8 + 8 bytes on a line for (int i = 0; i < data.size(); i+=16) { QString dumpStr, asciiStr; //ba = data.mid(i, 16); // display offset painter.drawItemText(offsetRect, Qt::AlignLeft | Qt::AlignTop, pal, true, QString("%1").arg(i, 4, 16, QChar('0')), QPalette::WindowText); // construct the dumpStr and asciiStr for (int j = i; (j < (i+16)) && (j < data.size()); j++) { unsigned char c = data.at(j); // extra space after 8 bytes if (((j+8) % 16) == 0) { dumpStr.append(" "); asciiStr.append(" "); } dumpStr.append(QString("%1").arg((uint)c, 2, 16, QChar('0')). toUpper()).append(" "); if (isPrintable(c)) asciiStr.append(QChar(c)); else asciiStr.append(QChar('.')); } // display dump painter.drawItemText(dumpRect, Qt::AlignLeft | Qt::AlignTop, pal, true, dumpStr, QPalette::WindowText); // display ascii painter.drawItemText(asciiRect, Qt::AlignLeft | Qt::AlignTop, pal, true, asciiStr, QPalette::WindowText); // if no selection, skip selection painting if (selOfs < 0) goto _next; // Check overlap between current row and selection { QRect r1(i, 0, qMin(16, data.size()-i), 8); QRect s1(selOfs, 0, selSize, 8); if (r1.intersects(s1)) { QRect t = r1.intersected(s1); curSelOfs = t.x(); curSelSize = t.width(); } else curSelSize = 0; } // overpaint selection on current row (if any) if (curSelSize > 0) { QRect r; QString selectedAsciiStr, selectedDumpStr; qDebug("dumpview::paintEvent - Highlighted (%d, %d)", curSelOfs, curSelSize); // construct the dumpStr and asciiStr for (int k = curSelOfs; (k < (curSelOfs + curSelSize)); k++) { unsigned char c = data.at(k); // extra space after 8 bytes if (((k+8) % 16) == 0) { // Avoid adding space at the start for fields starting // at second column 8 byte boundary if (k!=curSelOfs) { selectedDumpStr.append(" "); selectedAsciiStr.append(" "); } } selectedDumpStr.append(QString("%1").arg((uint)c, 2, 16, QChar('0')).toUpper()).append(" "); if (isPrintable(c)) selectedAsciiStr.append(QChar(c)); else selectedAsciiStr.append(QChar('.')); } // display dump r = dumpRect; if ((curSelOfs - i) < 8) r.translate(mCharWidth*(curSelOfs-i)*3, 0); else r.translate(mCharWidth*((curSelOfs-i)*3+1), 0); // adjust width taking care of selection stretching between // the two 8byte columns if (( (curSelOfs-i) < 8 ) && ( (curSelOfs-i+curSelSize) > 8 )) r.setWidth((curSelSize * 3 + 1) * mCharWidth); else r.setWidth((curSelSize * 3) * mCharWidth); painter.fillRect(r, pal.highlight()); painter.drawItemText(r, Qt::AlignLeft | Qt::AlignTop, pal, true, selectedDumpStr, QPalette::HighlightedText); // display ascii r = asciiRect; if ((curSelOfs - i) < 8) r.translate(mCharWidth*(curSelOfs-i)*1, 0); else r.translate(mCharWidth*((curSelOfs-i)*1+1), 0); // adjust width taking care of selection stretching between // the two 8byte columns if (( (curSelOfs-i) < 8 ) && ( (curSelOfs-i+curSelSize) > 8 )) r.setWidth((curSelSize * 1 + 1) * mCharWidth); else r.setWidth((curSelSize * 1) * mCharWidth); painter.fillRect(r, pal.highlight()); painter.drawItemText(r, Qt::AlignLeft | Qt::AlignTop, pal, true, selectedAsciiStr, QPalette::HighlightedText); } _next: // move the rects down offsetRect.translate(0, mLineHeight); dumpRect.translate(0, mLineHeight); asciiRect.translate(0, mLineHeight); } } ostinato-0.5.1/client/dumpview.h0000700000175300010010000000406712005505614016166 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include // FIXME: High class DumpView: public QAbstractItemView { public: DumpView(QWidget *parent=0); QModelIndex indexAt( const QPoint &point ) const; void scrollTo( const QModelIndex &index, ScrollHint hint = EnsureVisible ); QRect visualRect( const QModelIndex &index ) const; protected: int horizontalOffset() const; bool isIndexHidden( const QModelIndex &index ) const; QModelIndex moveCursor( CursorAction cursorAction, Qt::KeyboardModifiers modifiers ); void setSelection( const QRect &rect, QItemSelectionModel::SelectionFlags flags ); int verticalOffset() const; QRegion visualRegionForSelection( const QItemSelection &selection ) const; protected slots: void dataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight ); void selectionChanged( const QItemSelection &selected, const QItemSelection &deselected ); void paintEvent(QPaintEvent *event); private: void populateDump(QByteArray &dump, int &selOfs, int &selSize, QModelIndex parent = QModelIndex()); bool inline isPrintable(char c) {if ((c > 48) && (c < 126)) return true; else return false; } private: QRect mOffsetPaneTopRect; QRect mDumpPaneTopRect; QRect mAsciiPaneTopRect; int mSelectedRow, mSelectedCol; int mLineHeight; int mCharWidth; }; ostinato-0.5.1/client/hexlineedit.cpp0000700000175300010010000000446712005505614017167 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "hexlineedit.h" #include "qdebug.h" QString & uintToHexStr(quint64 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 #define uintToHexStr(num, bytesize) \ QString("%1").arg((num), (bytesize)*2 , 16, QChar('0')) bool isOk; ulong num; qDebug("before = %s\n", text().toAscii().data()); num = text().remove(QChar(' ')).toULong(&isOk, 16); setText(uintToHexStr(num, 4)); qDebug("after = %s\n", text().toAscii().data()); #undef uintToHexStr #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 ostinato-0.5.1/client/hexlineedit.h0000700000175300010010000000204412005505614016621 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #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 ostinato-0.5.1/client/icons/0000700000175300010010000000000012005505614015256 5ustar srivatspNoneostinato-0.5.1/client/icons/about.png0000700000175300010010000000201412005505614017076 0ustar srivatspNonePNG  IHDR szzsRGBbKGD pHYs  tIMEvIDATXýWq: ܿ؁ DwTvP v,An@{?ESoaFep ,0u]"R lg( @p\FUUރ@D9E!xB] "!ཇR Dj|> )%///F|c+Z1Da|>G}p^QUa`s1Zk8u@bG, RZcYxc36D)gig<@k#BDLj~ J9dB9v5]nƘ}0 fH)὇:>e~Z )eB-rq7[%FA Àmc^yx41Oy"S 3G"ipq===ݤMBJsh& KG\34@{}[5~~~85,3erUU}jW]4{bd]K&leƦιM !B/c3*t:skRY9r\v9p*{Bd,X˲Kp~QԶ-m*:NB !u]Gu5⾵'"a⺮S)Mm[^!h4ͪMY|R6p3f꺎╷]ιX&H)7ekm9r>\.ݎiY~Oe#7 @ooo "t]RG[JrlͅdHW4M y<#x2۬v0 CtK3 Z[G7Jn#c̶*k>hLLjƳRwUd:<$hݸIENDB`ostinato-0.5.1/client/icons/arrow_left.png0000700000175300010010000000053112005505614020132 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%B0 (=ĻI12$C_?3¿~1`._edj>)*n90_ ѿV\ٿ0aX`ſ4ܟ@_P303'×^ 4G)1vUMB9 i;N@ͺ@Ռ㡻zZIENDB`ostinato-0.5.1/client/icons/arrow_right.png0000700000175300010010000000053512005505614020321 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%B0 k_WAPz"e_~ ¿~1d7۷.j3Jؖ?7@&˗zZYj'Me7Xo!o+]r{:g0ARR oܽp{=x -YXPAku1ba7lIENDB`ostinato-0.5.1/client/icons/arrow_up.png0000700000175300010010000000056412005505614017632 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥?/Qϲhg5j%'F,[ LH 3(vw=fcoN{O~9VM4Q7ܿ)v/WQ=&bpSO ^'&^:\˨6eND!& 9꒣_|?\ srx,g*,(F#d[OaAA*P p1O+C$`)*w`A#0$ *?b&NRIENDB`ostinato-0.5.1/client/icons/bullet_error.png0000700000175300010010000000070612005505614020472 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<XIDAT8c?%B@,$_\"_H>YoM>IC??'__`J6h50A\/E_x4hӟ*E~c8h)w??~A6q ~c> fPt(fgI8 Ѝ hKÿoz33n&u8 ڞ*m g)ÿDj~gjš ? L|@ fIp{9\nmnj bǹ߁ H?fK qg&Lة IENDB`ostinato-0.5.1/client/icons/bullet_green.png0000700000175300010010000000044712005505614020443 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8c?%a8첒W7[\]k`Df_УwI-6m6˫?g:/D`;[wz tior'_|efp~*^g(e1]OQU"D9єH#"IENDB`ostinato-0.5.1/client/icons/bullet_orange.png0000700000175300010010000000043312005505614020611 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT81 q_ɦ xe:%2\(etW'9[%bRF^K6ó~ꩯ|\5ӒfR89E/cb. &*00x,Q!w0Ta P|Fn^1Bưy<рir #[Xj[MU,O|ދds)IENDB`ostinato-0.5.1/client/icons/bullet_white.png0000700000175300010010000000031112005505614020451 0ustar srivatspNonePNG  IHDR7gAMA7tEXtSoftwareAdobe ImageReadyqe<[IDAT(1 DQi[H kۗL2[ _Y.oL&IlNcNAArG z._I;k9IENDB`ostinato-0.5.1/client/icons/bullet_yellow.png0000700000175300010010000000043712005505614020655 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8= Aq9d1d(Yn]qn<Τp VYuN$K>,z ]oCvUX&VytL2kуF'mfhR>'0hDt]glVxu:?) x\ J4[C:N<@D"vۀY^ȸZ8rjJLn7F-$P `Uu{Ԯ"ц+O&1pHp)|.UE4~SX`02U* `!"+Ìv2NMѮ !A_^d2)q[-cdGgbR( kpHw7kFF?EE IENDB`ostinato-0.5.1/client/icons/control_stop.png0000700000175300010010000000062312005505614020515 0ustar srivatspNonePNG  IHDR7gAMA7tEXtSoftwareAdobe ImageReadyqe<%IDAT(}MKAP}I! B]u)C(AHeÚ:֒쬔le39#ڪ؆U"#tdD`^1D\1O1.]M.67 ` ˌyEsᅖ28Q^hmQ$r1S0G>Y4xx>PE.Yfʭ`ȂES7DZ:D*r媏塩sD]hTLIf@me˶7UYzͿ(yv-|HIENDB`ostinato-0.5.1/client/icons/deco_exclusive.png0000700000175300010010000000143112005505614020767 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥OzS/=Y.k[nZ $K,̮fP r5 /D%L@+Fk9[Ἔ9ۀm?MW/K:|nYx0ϖT\9ڥX x6?C$FC|<ʨGW 6ze^g?Ls@eGM^F<:jϠS K:_ʤТ5Gk7!cep=3^[|vG xT12&(2u$bPʋ"WS@w94qu,"UZ,ئD44RRd8,&$« UZۑ_S`L0+ Xy8:kN'CfP\$(7C~M5J;8C4Qw9r?73fFcr7-2@T ?@C2>Ϧ'l]Q=ECpD!? zhdM)EGze%,KHnau'2b-"'-Y78ɀQe6LIt殷cq!z |v j/Xi@ %1|hl !|! Y#uUNw]˼ H3u t]E>k%IfoRD:0`~ | (r on3oG0!$V *[W0_-+ dW&2ZfMFVJpiF&B > Rg- ~ CmڴER ឫ p5ްy+21Kawh` #aZ񽞆TZoLѓ`"(?'ˎJvKކ|:G9[aw82 Jw f'ymzsӘTsw__ιIrIENDB`ostinato-0.5.1/client/icons/exit.png0000700000175300010010000000126012005505614016737 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<BIDAT8˕kAfI Dh AP+-?NAXYW4>( dgc,VYltrÙsӗ.ƙw6XY)zƲglEOd ʺM6g^ Y}}}Z4;yL"9;"JLﭘfk\_B:fՄ`pM@ R }ʖ鱵8bWUqI& o+0:4kp'⊘p&u6)|ѡjK\*AI*"]?];O[iES;؛o={LJTTKDK"u\#&눩Ň#eTf0uL 7'1cILxKK{ Z#L#!qwTSSd-!$6qIP'vj@ =  L yzz֣gEI[ş5>y-w8u0a3r\9j~Mw{ͽIENDB`ostinato-0.5.1/client/icons/gaps.png0000700000175300010010000000661312005505614016727 0ustar srivatspNonePNG  IHDR,z sBIT|d pHYs``ӟtEXtSoftwarewww.inkscape.org< IDATxyxMڇN1[G |%ollqNQg+^xN!#d ;7gX2[+BJX)aIHH%!!QoDAJXEm: z:-.N.L&nk hol6s[Sw(Ġסו#JGrEe<Ũ\mgĠYQ,V-uԄAD7#25& 4F<(3~b&r#P_+l2R;`k5Η \| zv6[WK`6Q(P:8Z:mJڲm4kL.A\fkeٌ^W^%Fm0L`@`ggAe_SRRdzGu!͖u:*:m[WbtfV 4?2vu mK5W8BYi޺nscH;fhv>N";50,2_ ܭ~W4`J=&:^{9:歽{\;U6/~&2 "~]/ϼن/K3Eg^ӥؼrVe;C9jW=!]=#y ˦ d4Np40n Đ|q!k#DB^ H[6wZsƐh+? YOgoY_iٞk,YI4lOxkv3 FNoD;rPVVgX˺W @,9HJb7j {#I}9lQ\.= II-FNe?`6d*K^ɭ4X| $-;{+&ͤȅӇA@e> IH,$ӟ,i=#d3ՉPqN D?jsy g} YĦ §41{VeKv> zڒ˿s!e2vB>{=43\'ٻl]Ia߷]wlMܽ|YqK:SY@ֱ|e#ygh*ek?F{}O}F[Wq5K[,LIH.ɋY!WؑYȺݹUq7^Wn3թUI(d"]Ud2VM9/<уL0(u唗T9Mg Gg7#nUuWrqj},R)-7#`0d.d޸9TpscFe%+K ))Ǣ<(廰(I,%Tׯ-+*&mi1Fل(V5y,JM-drdAqer%g&/JQb{; lr2~{23tP:w,C̦uQQ,LꉶiK^ T{1%" 6$eL͵>WXeۚ]*Z<.L[mm|<}Xu:R`gL 0'[ (;nJ1bM> MUhO4Cw?lIFlE%f+#&Rdgg|?OZb275~#fm\n>P\aфhܴ5SOZVTopZ2|r6YHg kс24i&Qt]>wt5WhAm y v~7Ǐf(rDdؼn%rb>dșlu6fS|QluJXr/oޘ=)&0v(qQ"Җ[jQ=ydUVO~!+:qV}j򹣄Vޯ4{dW9י<+Sgj&:ƴF;ӿmspwf7_> W:98y`M=(߈U5!QW]Eq ))O\}ۦq,9a՜rFT1OҸQ»Ȓ+Z 7E~Ahewtv%2 ;{"^@&W W(hܴR?DtrEVFMC[˕}pTˈkAF{b"s&:BEQvOA{}fnn M÷aU`8vF*h<,<|ij[Whֺ3y/߀oZ Ⱦ86ꄧO#4 iR&85&Fr U~%EZ#v*/H5e#e$$$$#R’7H KBB %, z$$$ R’70#yIENDB`ostinato-0.5.1/client/icons/logo.icns0000700000175300010010000010507712005505614017111 0ustar srivatspNoneicns?is32r::`&$_Rx?5Krpwh+=*~0*9~nÿfe%fOkWoXQ)%U4q.K*CeB"!LQv/gJb+ )g[dNvG(P8FiDc7EU WS / <%,&V %o77]" \Pu;1Honte':&|,&5{l¾cb! cKiTmUN%!R1o*G&@c? LNs+dF_( %dXa}KtD%M5CgA`3BQ TP+ 8!)"S "p88^#!]Pv<2Ipnuf(;'|-'6|lþcc"dLiUmVO&"S1o+H'Ac@ LOt,eG`) &eYb~KtE&N6CgBa4BR TQ, 9")#T #s8mkil32 1!̄ g1Evo =V#[2w(TK;Aw!*% l2TY'5B!4+s û.#/oG#!\!@* ǂ%9#"a2*3#sCwHx9&< m6A],Nz-<'%&_"mπXi !$# "WLt 7!0lT" u'&# &D!NnL?"#>#%%&9$1-(},!AM=%*"C Y$&6]D^?k؀RՁ;(^i8 Z1؀X iTɀ =sTZ y|8*"KPg@"%e$% &fK%#;)_6&L)U4I$)? ^#(V?$#/(&il $%8@BNe * ߃ q#w-˄e- A tm 9SX/t $Q H7>u&! i.Q U#1?1(q++mDY=&Ƃ!6a/&/p@tEu5#9j2>Z(Kx)8#!"\j ΀ Uf  THq 3,iRs#" "AKkI;:!!"6 -*${(>J9!&@V "3ZA[;h؀OՁ8$[f5W-؀U gP Ȁ :qQWvz4&H Md |=!b ""cH!8%\2~"I%R1E %<\$ S< ,$"gj !4=?Kb&ރ nt.̄e.B tm :T Y0u %RH8?u'" j/R V$2@2)q», ,mE Z>'Ƃ"6 a0'0 q@uFv6$:k3?[)Ly*9$"#]k ΀ Vg! TIr 4-jRs$# #BLlJ< ; ""#7!.+%|)?K:"'AW!#4ZB\<i؀OՁ9%\g6X.؀V gQ Ȁ ;rRWwz5'H Ne }="c!# #dH" 9&]3~#J&S2F!&<\ % T=! -%#gj!"5>?Kc' ރ o ul8mkit327#k'#wā#)ą#Jm#I#%#/#C>#х#ʎ##:+##$&#b#Z#q#'Ϲ#(ɥy#.~#҅#g#(##3W#wQ#.@#-3#iq#F>#%ۄ4#{#ăz#>T#])#g-#ԅ#ƅ#=#|#̂Y#A#R7#c-#/#Uۋ##(#$$###3#Ճʅ##'£9#O#$#4#mu#-ѣ##M#|g#5V#4ޢ@#݌##P#ٕ>#>#em#5#(΅#.#Lɂ#*S##ԃ)#h(#Z3#$#'SF#W#3&#kq#|#g{#Gx#՘$#~#;#ڠO#1@##'##Ԁq8#d#G#ځ#Z#/#'ɞ\#Ɓ#%w.#ћ#4r##~#I##otfT.#al#g#W#5m}#w#6šY##u&#4kڀ##%I#Ă#aC#7##$;#)љĂ#)#%Ƅ#Ƌ#1#9#ք#Ռ#(#P#+#ч##Z#1#o#-####T#r#Sց#+###g#\#%6#b;#z#I#-K#-הG#>΂q#*C#t#$#6#C'#ʃ#A#m#m#3(#s#(#=#g##œ#q#QJ#3;#c#0##+ݏ3##7#t#T#QZ#LɃ#=#;4#Ά#f#;꬞5#}##1##u#6e&#%V$#@#G>#+߄.##g#33#7ȅ#0##T+#΄#F#FC#%[#T8#+A#$#z#̀&#q$#l7##z%#ބ#d#~#C#$#‡.#Ջ##4G#')#ڂ8#*܄#<#Sm#h#J&#>;#[3#{_#(#J#5~#aֆ#ZF#q.#C6#'ڃ;#g3#-#x#t*#Z#+##WR#-/##.#4#/3#&f#q#J#`#(€#;.#4#Mq#&@_|6#0Ɓ#V#z#&і'#>ڂ#V#(#$#(#$΍#֘#'m#c#u#D#bԊ#_V#RF+#=#$ik#L%#'ѷe##$~ޏ#L#V#̊#/W#Ms#;#9#/V#4#΃#~##$N#/i*#|̄#/g#Ƌ##T0# -ȶg=#Lx#g&#=##q#%+####ցF#ƚ#ނ>#)#;*#C[#R#I†#w#zI#Q#qօ#l#ԍ#ڐC#Bρ#w#&'#T#Ԉ=#.WڄƄ#|1#c### 40+-9FS`n##)#7##/)#;#1###/$##|(#'##/#6#ς}#n##/߄##W(#ΐ#q#/τ#ȕ3#Ă|#g#C#/#&#S(#(###/}#P.#W####/A##N#7##3#/#*#1###/#~#Jo#P#;#/<#O(##Δ#i#/#h#l>#r##//#J#.#+#)Ԉ#/w#+###1̇#/#GP#M-#M#+#/##$πF#0F#'#/%#n$#~j#<#m#/#R<#C#4#5#/T#;n#+ـ&#Y.#dɀ#//#+Փ#3#74#M#/+#'.#w8#%ɟT#4r#/G#=ϓT#K>##)qT9#f|#.F#g/#'#%M#N*#$k֕#T#R+#(yޖ'#T#T5#<.#A#W̊F#3jޙ3#}3#Zԃ#5H]r.#q(#]#/+#k#`#/(#w#c#/&#G#w8̍#/t#((#(#'#/N#1^#;Ϩ#x#/4#=ۻ4#Z#F̉#/$#bz##$#/>#'5#7#>†#/x#AO#j#iۄ#/5#Yg#01#%t#/;#&C.#]#(#/@#9#]#/~3#)#1w#/ږD#m#.꿐_/#[ʷ#(9J[gcTB1#%mѹ#*};#Wχ@#QԍG#(Tėj>#>n<#4KczN#3*#:+#FU#r#4#F#$7#Aa5;fg#u%ÅGkG!,@;Ѕʎ6( "_Wm#η$ȥv*{хc$/ߤUuO+<)/foB;!ڄ1xƒy;PZ%c)Ӆą:yʂV>M3`),Rڋ%}  /Ճʅ#£5L 1kr)УIye2S1ޢ<݌Nו;;aj2%΅*HȂ&PӃ%f$W/ #PBT."goyexCu՘ {7ٝL-<#Ӏo4cDفX,#ȞYā!t*Л0n|GmrdP*^jcU2k|u3šVr"0gـ!G‚^@3 7%ЙÂ%!ńŋ-5քՌ%N'ЇX-m)PnPց'~eY!3_7yG)I)֔D;̂o&@r 3@#ʃ=jj.%p$:eœoOG.7`,(ݏ/3r߆QOWHȃ:71̆d7ꫝ2|-r3a"!S <D;(ބ+c./3Dž,Q'̄BB@!XP4(= wʀ"o j3w!ބc|@ ‡+Ջ0D#%ق4&܄9PjfG";7X/x\$G2|^ֆWBm+@3#ك7c.)uq&W'TM),*1,."dmG\$€7+1Io"<\y3,ŁSy"Ж#;قS$ % ̍֘#k`rA_ӊ\SMB': fgH!#жa {ޏHS̊,TIp75,S1̃| K,f&yʄ,cŋP, )Ǵc:Hue":o!(ցBĚނ;%7&@XMG†tyGOoօjӍَ@@΁t~"#QӇ:+UلĄy-` 1,()5BP\l%3,%7-}, y%#,3ς|l,ބU$̐m,΄Ǖ.‚yc@,"P$$ߑ,|N*U,=K3/,߄&-,|GmN7,9L$̔f,fj;n,,G*(%ӈ,t(-̇,CNI)I', πB,B#,!l {h9k,M9@12,P7l'׀"V*cȀ,,(Փ/30I,(#+u4!ȟP0n,D:ΓQI;%mQ5dy+Bc,#!IK& g֕QM'$vޖ#QP29*>ÜB.hޙ/|.WӃ2EZn+m%Z,'g\,%t`,"Du4̍,q%%$#,K-[7Ϩu,0:ڹ0WB̉, _y ~,;#23;†,u=Lhfڄ,2Ve,-!q,7"@*Z$},<5Z,|/%-u,ٓAk+꾎\,Xʷ%5GXc`P@-!kй&|7U΅<OӊC$PÕh;;l91I`yJ/&6(BRn1B 3=^27d i$ wā &Å Hk G " - A< х ʎ 7) !" ` W n $η %ɥv +{ х e % 0ߤU wP ,= )0 go B; "ڄ2 z ăy ;Q Z& e) Ӆ ą ; z ʂW > O4 b) - Tڋ  &} !! 0 Ճʅ $£6 L ! 2 ks )ѣ  J ze 3S 2ޢ= ݌  N ٕ< < al 3 &΅ + Iɂ 'P Ӄ& f% W0 ! $PC V /" io z ez Du ՘! { 7 ٞL .= $ Ӏo5 c E ف X - $Ȟ[ ā "t+ ћ 0p ~ G mrdQ+ ^j e U 3k} w 4šW s" 0iـ "G Ă ^A 4 !9 &љÂ & "ń ŋ . 6 ք Ռ & N ( ч X . m )  Q p Pց ( ~  e [ "4 `7 y G )I )הE <̂o 'A r ! 4 A$ ʃ > l l /& p % ; e œ o PH /7 b - )ݏ0 4 r߆ R PW IɃ ; 92 ̆ d 7ꫝ3 } . s 4a" "S! = E< )߄, e /0 4Dž - R( ̄ B CA "Y Q5 )> ! w ʀ" o! j4 w" ބ c ~ A ! ‡, Ջ 0E $& ق5 '܄ : Pl f H" <9 Y0 z\ % H 3~ ^ֆ WC n, A4 $ك7 e/ ) u s' W ( VO )- + 2 -/ "d n H ^ %€ 7, 2 Jo "=\z4 -Ł S y "і$ <ق S % ! & !̍ ֘ $k b s B `ӊ \S OC( ; !gi I" $Ѷa !{ޏ I S ̊ -V Jp 7 6 -S 2 ̃ ~ !M -g' zʄ -e ŋ Q- )ǵe; Iu e" ; o ")  ցB Ě ނ< & 7' AY O G† t yG P oօ j Ӎ َA @΁ t~ "$ R Ӈ; ,UلĄ z. b  2-))6CP^l & 4 -& 9 .}  -! z& $ - 4 ς} l -߄ U% ̐ n -΄ Ǖ/ Ăz e A - " P% %ߑ -} N+ U  -> M 4 0 -߄ ' . - ~ Hm N 7 -: L% ̔ g - f j< p -- H + ) &ӈ -t ) .̇ - DN J) J ( - !πB -B $ -" l! {h : k - O: A 2 3 -Q 9l (ـ" W+ cȀ -- )Փ 0 40 J -) $, w5 "ȟQ 0p -E ;ΓR I;  &nR6 dz ,B e- $ "J M' !i֕ R O( %vޖ$ R Q3 :+ > ÜB /hޙ0 }/ WӃ 3EZp, n& Z -( i ^ -& t b -" E w5̍ -s && % $ -M .] 7Ϩ u -0 ;ڹ0 W B̉ -! `y  !~ -; $3 4 ;† -u >L h gڄ -3 We -. "s -7 "A+ Z %} -= 6 Z -~0 & .w -ٓB k ,꾎\- Yʷ &6HYebQ@. "kѹ '}9 U΅= PӌD %QÖh; ^37dt8mk@icnV ostinato-0.5.1/client/icons/logo.ico0000700000175300010010000000427612005505614016726 0ustar srivatspNone ( @ !!!///000???@@@AAAPPPQQQ___```ooopppqqq&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&%%&&&&&&&&&&&&&&&&&&% &&&&&&&&&&&&&&&&&&&&&&&&&& #&&&&&&&&&&&&&&&&&&  #&&&&&&&&&&&&&&& &&&& #&&&&%%&&&&&&&&& &&&&&&  &%&&%%&&&&&&"%&& &&&%&&&& &&&&&&&&&&&&&&##&&&%%& &&&&&&&&&&&#!&&&&&&&&&&&&&&&&&&& &&&&&&&&"& &&%"&&&&#&&&&&&&#&& &&&&#&&&&&& &&&&&&&&&& &&&&&&&&&&#&&&&&&&&&& &&&&&&&&&&##&&&&&&&&&  &&&&&&%%&&&&&&&#&&&&&&&&%&&&%&&&&&""# &&%&&&&&&&&&&& &&&&#&& &&&&&& &&&$&&&&&&## &#&&&& &&& &&&& &# & &#&&&&&&&&&&&&#&&% &&&&&&&&& &&&&&& &&&&&&&&&&#&&&&&& &&&&&&&&&&  &&&&&&&   #&&&&& &%&&&&&& % #&&&&& &&&&&&&&$ & &&&&&#&&&&&&&&& &&&&&&&&&&&&&&&" && &&&& $&&&&&&&&#"&! #&&&&&ostinato-0.5.1/client/icons/logo.png0000700000175300010010000004404312005505614016734 0ustar srivatspNonePNG  IHDRښnsBIT|d pHYs]]IXtEXtSoftwarewww.inkscape.org< IDATxiUՆsg& 8^APŽJAE@dSDEPAQDAAE( !IBXY&]~tOZz u;unGHb='FG@Ihq4 VCdP/|c ϟ?`@ìYx=fU bftTzmLrI|@WEl׽7jIS@B`fE`@.!e2elk=Yo 5A&lW7+ml{]eT Ӵ =]Y,s(e$N:G/P ~4i $˲E?8] ,~lFp26+WJ[dT*vLJi[Q`wqxU~WV7%"qTEEIRUyzXo {D;j u!˶\m[5#B|Q-DX:z4I"xA3_a[i>% 6[&~'6O din<5wE>o[PbD2(Ek+ w]֝dr6dos'[iqlc}W! (*\D®]z)|&\'B5.\jO`iҢnY?>O9k˲oL͙[1WXGN{Q"۶(9 ؒtn'Y d|[w )2Iu*ğh~{u@==qg!qˎRT |Y*"ϴ;I"݁фʸ@O\aFL&7T(NU'TT5ZDV@?~V*~{?I˲fضú:k X,} x;k休JQ"=聠n=6(Q")D=)kTE+\Ǜuv+a,H9V~ul;eʄw;?d();BX;[?xH>%S}±NȬYZz\7S9ҡ%ɍtiP Fxg±+<)w笇o NH2;›|ޗd%͐w'xuk^=ڬbn%xO{@ v;Jk @xs&l,뤁$Lk/S\d9BYA"\!*JD5H@w@dc!`| :*!f2ׂ뜁LrȢ7|s֬ˑlo|?@9;5~UCQmmw=|ɢ8%kT/ht~²K۶߆Z:3<@6hp7/-*"RRXyuݷ:Rx?9;$z(L@f5O$V_}/Q b*J;4+U+@~2B.8ٯ;-oܫs!J}$6"sI~N'Tw.O#Hĩy&Vs#2s=Y"HM,̌\^Xg Կoh@BŒ_[?8u=+/SWy;JݧwMkD?@`HcZmӻOG-恭grǭ~!.| bO'q 弧 $}m[Xj@ױmSQi*3婜}wl-xIʸiF[(S 8U;rF>4UL&7bPW]Sx"F4/ZWk92ۛ}6~I$mq}[~R L ]tӶ}&(zܤe}m$Z $;X-9{օv5߫T{2}譵 $΍G:uRmk$q X*vlopy W@ 8 bAEG"Ob u2[fGy)+ xM:F*9IK&Neg)! x4lleZwwwoaDnм/zV:{iA2@!oy12c So"b59޺F)'֚$È4Td9-PAEhqIomLE"21סJģ})q@At5٤Z4ڎWݝ3wlt):8ǀ3=Vf̻Mӥfm-itk?,|A({[@Rȱ w3go F$a6| p1Q󿨼cY%hُ)"*nh9cAeeN3ïtfzbQ83'NU*՞$uH͐e좨sXXz*Qo-D`S yy~[#M^ƔXe6-(KDn3*JR/\p){J+Kn.=%B+9v,l^@٠,>pjŒ5T@ƌ$E܎`.poVQJ!+ߪ$ J(\{%`k!d] CóVƌ0HJ͋_\&^ٸ 6+ Ƿ>lMEp]4&}-58 Az(²,0d4@NV(`wYa&p׹t iV^{D䂱j(\MWq>I`ƶAqlҳQ?))>KԢԢif7+vMVfw}*k%;e٠59~IZM֓t(7K 8H2aY7K$T*Y}iGm qp~ɞSw'C2""*5Qb$Qუ䔴_iDlΙUsrjr* w-E]PI<.uor?/X5 #d2/Ϛ5mk?Jo-RPczϨH,n+mxƨH<]D?qLe/'aYC')U~r7X5 ^`z!:FmG/䬻Ƃ$"Ԣ"HFcQxҶhMfF@oOt :uR>ҶI7w?lj#ͯwbX˲)5G|F 4@E]~;.D{(8)cۿތ.V~rT_:m#qxjq9d߸i%I31`>cدT8?@. S1C}\w"η,*jibNҹaZakE%t2KFǧ%LoTc3q!W Uen!iZiv+8FӋOu|, }mоo ``ŒZc yiy /"8 Bi5 M%FAH$L1)Pc(l `Kֲ?ta*u$nJaƜ4 0j֮^K deܛ2sfbOK9,ht6\k[ 7=94EԒEz2wXJ. 8Ϥl7LHHjR} sCm?lq@&?sfdC f;.{JAS@풦YfJx&;M1NAee%y}'~bW>9'`7؟ sLH2c7NM _`G\h/]a۹?N/ֿ qlpR]B]&O/zVN2{S<0c5Eh_Jf͹H5ͷV \AHNMVW""~{%qա|F[[,SS',+\4(v~!ra<=DҌ' 9֌"wg@í8dz3*M1˲A27z_ ^5!1MsKے[/iǹ]K+ۓ==`&N|O Fo ɩɩxsWVvrf 9sfmѿK] un4@y`\ o \ #B9=s2f'e?.:1 ʸ 0o޼D"p*]i7D4g3RxF|#n\x3 3P*wV}ҕ[\'ԫۜ)V!/Wd24!ӫx<> ⫠Q~ڎV R5ՐJ^CQ/w$h EੌX,0x%{K_>0chو7 7˲fRtfeWp} xpT*r}=NCjM/`D4[KB_SN4LQ)Mm@&{ϛ@յXo(ʗz"zu^bruBM93^dPYg'&-+@itY/P9S2G+}w)sJSed<奄E0}~Cq$;|tyF6}AGH\`יQ xx\se Sєa N$P_)'i@bt,2w]_B}l\F2R_B*ĢgY90KxhfX3g&a-f2!Cr{kb: "3)})6W#'M !1CmS{⳪U,^x%([2kkgc{޷,*HG{)V{;.F?z G;Ƥc(6pGK=x6ZAwo*xOӃ #C -9* <"ЦDWWWg4nu{RZ\zhjwFs!|`3^˲ZNQ7QDuG6]Xe>,5$ H蚦Y 3qmm ,"ӫQ (cZ^xREKhRsB|.*'n6@DzKgz^0T>y P(e2(GBȽV#JBk2_abُvs}}}V= ;yyO@pHYR!|ުCi7}5йz>o5me%u prگEuy}Q)QqIe?g^j'nM!GO&u B E"aZoS{RmtuuuvF:`vS(OSp{lO,F>^#YQ7\ dlƸi8)^l-ݸBűL5} FF8BNr#I- j5%kgtE**w־/ oH݂ޭܺ@qJNX"A4aJN˨j[G@]7)Vtt0"{G& 1jH$f:QI Y AX.~Nנɚ~@./# Ed`q7۳QPQ'ǺcU)fȌ36LQp<ljo Kr5tξPaOmZۚxep c4Lnf7s=Hѡ'nʆlA',B9XDg~6j s5Kdk3wd~p#H`"`"DH#+bGgWW4D4v<FRx# zVsvYږ-]٩䭢(8!N9s(nz.i2HqN mǯND>,exZ 3xw| 0=K x\P{'Opov)XDbSc Jd,vT*ϯ`+a#- C;88 C% ٚ,M$,_}>午1 K*ZMCAu3Zq$ce} Y!C_b?6O9كRsY*{qh!HF鸆~z )i/5}X;.w~cx<|PEsMըr{ R IDAT؆r}|'ؙLfQ(|D_PY!j'$'S 39gjɞrg<|+< ]+f/J==O~ 8g}I$AzezT2Ŋs ?덪1Fo@v(}GEv!܎1O=wJ%5%Rkj;Q n䜃zq4( J|l"!4HU(m2DzbD e dT.{ O !44C= F` C*/cј+'I0|;OHYdGܲ4SrᛕF{%Jڦ:Eh3~ZT<}݆5""F²f~{G&<2=.ϥLD|ez==#_G#HOg\vQhYH|+}oģ񊎜htk*?jx4-?,kbZkWvuu^ ]DOlUIv`o$LkN2,r|.;Xŀ7X4aYq*OLr/{ӎSP ȀҒ^dk )7Re%+g!?ht{T!c%jbu}<5oKt$MCo]`ީò0p,Fɞ~K*k +W*Lضg AP@+`Ԁ#!0o d)FW *H`hەFŠDL- j[W#iG"h3MsKwKr3՛+D}YxYͩx@{@a\ҌGQ3Pq*̝Il2zܼ! ?{kl4S <_&&ol)9q<"i{= i4ӂW@~,k\pk.GTh8 ιN0 D{7J^a$S)8 {d* hȋsQ~Ѩ)"F2}4OI˺/aZ JREpzwd@# oBr w5o ,,\0Pm>^!@tJ5l!,TnuM g :rP bӕv ?2VnWk Ji2 ض_Ҳ'#Z s.׈naƠ{K4r~6svF :ǵRoXWjd !tVDV #F*GipVReM4X. J:B柪 M;NHB nY' qo!i>!n x9\jcLozT9B6 w@b[(t'aI|=SSɟ9!+FC-M@oC"FCc@?wࣃL۾C4w4:-y0^*W:f_My()75%2L]009?.A*z ft>``$$)@1Zhq!٠:8K-^RvJGLdškLقςU̇[bœAoKӶ}j-&?\9eE ,Z0:xPӕ\8񕮧Ҷq+'8@O%S>?6B3 WSwhS=GC.fe綔"0H&pImܸΣWxWx2hI9əLYA$Lsxg)R{M2"LD a"(*xPQPIOB hg5hۤ$J-~0s$,Єi>"!WpK)7wWFIRb>n2Bk8/!x O3MEO(jCڶWtA TB6˲&ºs7TFc&t/4]_Ae\e)PRBNF.?0\T mHkp6Wo)|~<_{{S賲y2w RܒM_h$-kg!-&jժx.0"Cd(nCm!΀qXD>TG؀\ 4>b)rIBik!b2|</gc_c)"YVr[qʢ`iZ"~ƿ۾\+A!x\C^tȢBDQd y\ o!=Glo3fPr!5Dc]H*z R)zI,>QjcDĘ˹<-{ <+PAyil6jqpO;1;ly7ªCya_sB¤{ow󿯩%rOW*\Ax!~#U\}J4erٗ!We2A`¶ o4x2*,FMe2+]znB4@JbnarV[]( | C""2Q0>)1{.͟? 8 bLp'9[s+CzbCx]R!u~:Vz+`QD`Nto!Is*Z:dCI})ǹ mk`cv UT+13MsK0Vc)y iɷ X y.*r9)W1@{#A}(6=[񌪬L*{1e{BeRoCszfڶ[/# k d(ĕaY8ݨ{ #"F =l7o^>~[rD novqGvn'͜9!qTRh)g X_YZJ](z,FM@6q@,M D\ {eBIS׋(}aQqz5}PFW64)`hxBNN$?KK}N2aƮCq셹zdPePoK/O;kCvڱC¾ WjR֧o7nT/(uBkwrljmۯD (>4` 9ÜD;j["o@O5pSEAP'ɀXX90Z֧J'D&)s-,kdžhf@V% -SRg |WvP!6*'Nx3w噇J$Ҥ]|2<:uӂ,˞%TTW !_z{G&멛H6I,W@!'5Nvo+%)u' 5u/Y P3SΓZ_ fQ5-Z90Sa^_lu0ATmԢ"񕰹6 ɞ8w X[in WʉDbsM-8h,^x%T;\ $Pd`(H6l{0i|[Gb{,4u1FT RaKP!lgӱ^Z-mGH#?:5w(ؖQ곙ϴ,AŲqE8oAoo[ᡉbQA[#f hBZkyZn ȱWbv²IMmxKhtjG(+jA @JT=^Eâk@ZpKڶtwwA"kn;Q1< AH/g#K̿A\D j m;$%ds,ԩJ)rVrP3flH(ڌA}P%f095Įb5HR+ PpR0_ P-qW";ںM2YL.e8 &aY7r72;0 ) >"B<ԫfZO~^6u [X'L9(L;")a (<%!Z_;4tƶ/B8%ѭ[:J> `m? ڽix/< 7'1H=yr0c8/)  `ybi[PziQ׏ ".'3lȜeUVSNJ/ @׊ `6FSZXPpr74_k Wph2QW FSJw W?LNX/ <Ҏ0XOJ9J= %6+:=D;|"FAJĐ"|ʶ ߪaVO?d욀dOOx!q=_fk׭1e @1۶0ExFq.WܲN7A7;8Ae3nFU\*P!Q]ޜRI &28+t>2K#*839-61g I<)ǧs+0<50f͚*sA??l(c>஼Gr9/˺ID!81pd2C9wfz5*1i Ǝj['iHbRtڝ.T\6L/N4CHP+Zu#i^LfY}1HI:Q,? _2E @Z<Ҏs+!%]j-۴nB?hN2A\}BGqK{q2FGA))8&c7k BwsֳKŶo x"jOU\-a\䥄H"N}]הw"`2ǥ-h%ɘ7HZ$nFe r Q128u b[(6kM/ifLPYv. =?d{@& b§/OwIDAT r i~J'@rn>sW(Fw@_Oy@#2VC"+!Do2N+@qKP# M_󯼲6@ }L Dpg O8(,KDA}8α>J _p WUU_UO:{YAģE_p! s$I-0!F8%D7֒]ICw<(Pd29{{ר@nؠ7LrԲ Tr\й[Hـa{]6 ^.)~H?SCxɤee[B+9RHS¿ xĽ4vL'4PpF*푦5@ K'} Gft.[LF䁢tͺE4BoHe4yZ#n?۠VuZ7J2܌MfjX݅<(8uiH S,˲EW t}K4N(sMZ9 J^Ι'P4D>-`7-y(nYAnk5xǠ<8Z>H;#b|V8@`.2}z0~veK\PM˓b S\iA2I9f4 WCD`, ǹA+Od$hJ| |ṱ(P N2!aY.5"_'qG.L{d@6} ?UqIb(%2~H4/vʔ[cx4q8Ao v@Tm }Nvjk"ݏi(o{a% 8%'|cenYqqȿ//!(@ʑBBė-zƮ ޳eM1(+\#0ӗQ5d2١ 'J1O`(?IyK(rjX=m $/CC. e! so۶3hȬYzc 4Y$bVcbٽKԢԢZ:Y' v/Dx+rPCi 0kt#/(gez?f_3Xg dӢ\R휺A" VH,Q4Px6~?(9E FITZ]"""2nV0n"f7J2gnzŠ3@REBy{ ]aD0Ms3 `;1L.h 5id)S&<}7f OeIENDB`ostinato-0.5.1/client/icons/magnifier.png0000700000175300010010000000114712005505614017733 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˥kaǿ$F?P*BEpԭ 8TwݺM;TE!"AVD 1 &oysV$yg>jص֖9b C cxfz ̶3a Bhw#2IdST".N:0 ZcݓTOtE|CC>)qWDk6'w.zkJpQ0 toIO^> o?u(gOĵM?2gV\g6W'ghz"Qh}+FDjދ%7.mIs33\r(~J72ˡIENDB`ostinato-0.5.1/client/icons/name.png0000700000175300010010000000537512005505614016721 0ustar srivatspNonePNG  IHDRsBIT|d pHYs  ީdtEXtSoftwarewww.inkscape.org< zIDATx՜{UU?~B!%@"`)i2EQ(O|M0 RǀQ:BP@T" cpι>Ώswwu^{*HD\*XJ)gf`DUO_ nWwN#P7cdTC"r<wUbT/Psz Y'gѱnL^;T51{fHр&:X pjB)y8'{$1X۝Gku/0¶T1~2r`}R*nF {JQ'~e ^gIuY=(/)^k=)/{ھlg hvl h 0oSoNTWX-"TQ1t7ӀǁP|limkw,^(mп8 .}-*@8\Qf_O@ٶ' TDŞ*U}mcoc`ϯTgDޒ^NB5.d|͙\M7`ts@C3 ̼AHμ@Oo 3U3rI v<+g33oxy Za^8| KX{fwؗPރ#"Q#l훔 9@H.k!ZXUTW,%4_-0TU_)_9 EM.X 0vE䨦S[̼lf)J#U} 8̊' n6쫬FAo\LT}z~Ւr-"& sv٫GOUՀ~uLXCDdT%Xrј=cx:``yb m6\ +o:ѿ7nv̴=O}A-EAh{g ýl "]1l#t9oF9bEyvb`1~=ӰoywČw48Rkˁg\S0S^~d.X+"xxM\@ia.$"1sgy_f'""y#|Se^sϵܠYIUw^Dֺ?yŖ3`>h NUe܃99#J.WU7怿˟VΗ\>UMHݧ^U݊*sUm1bvRoo_"\$"Z6j`OcnWպq$"mMr] Q^UA[|$&U|W=X."ZHU_fw]"2&I%4 ܘEX銧4et&Z:w*`Vk^˷L␟xp1vr0 X'"Ω5#U.>S[e#wz+$j?n ]jYQᵦ^>TUoŮG*"qjN +6R;("UݜĨ+xMMKΞS 0WWuM:=DcW{EٴVU.EsUH;̟ Zxr[&3 7BNqT:V>mE3^U$+-3y"ңY[wpNA^v9ss5j#}˘G`ah2}x,ik\^r(xY9OjMx̸V#=wސ*xXY{s?vq]^ُy= p"iOXSRǁbklگR<9g0^U’lDŜ-ʴMbH}-IK+Knԉ112α6/1Bi!c8VGfϕ#)=m8Ӕ"FSɹTBZ9hH a1(+RpϠz<{xKy]FzfK&F]c>aL?7`( V`ϕ.6Q"P=.S֭F0ⷂ[b<Սy8Vƕ*vj {bfd4~'pf,v#A]숅,g?ۀbw'gJ5r"xV^Ӌb3"KڃyI&8Dr07)]np30YN{ 0`E>\&IQ"KJE|WjkODzc-𠪮)O1xmQ0R61jxEؤRxaQ 7Uwj$K(`]MK'FIENDB`ostinato-0.5.1/client/icons/portgroup_add.png0000700000175300010010000000141512005505614020641 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8}SMhQvIq͏Q@bՊ EI!/҃zR<-ւH[\Ei/ ڦ?d]g&_7f=ɲ,o%.0.麮yakkkIHR^J|2hӄ߇PL&# wx<L̂Mӂid@`A LdfKBLԉo 'WT$-Y/ĉߋgW}HBrI$Mxen<*%`. X*r?,C" `6c#*@fN2/&=/n3Ω\8IPuvlΏc*o.+%!dj 漓"ahWLE:پ|\lN`&7Sǻ6өFG jB2,?@͞ rx5ك9uddD預Zd2s}SڄBQNFJRڮU+UՇ'M+1)Es -//cM-Ŷ[,9{* AU=hhhܘ磆ߊ3$tzD<>\:{1Y{m==pP)|7/O6IENDB`ostinato-0.5.1/client/icons/portgroup_connect.png0000700000175300010010000000135412005505614021544 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<~IDATKHa|δk(")С<ŃT`5:EP%FPdtJ""-Bh~츻_{؃B~15ч>JD+Rq%Aޤvj'5b cipk%O 029\ ^)T#DK2?30wqIeWs*'+ԕBvBH*2 (a[&13IEUqjn< b^c\Bm25XE.>4qp ϾMƓDe.agO|Eq >Oۚ:fǦ[D c^UZ ΍Q)Lh(oM?c+RF*!ЇQIENDB`ostinato-0.5.1/client/icons/portgroup_delete.png0000700000175300010010000000140712005505614021354 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8}SKHTac8]͢EVFX ,h- j)qqS vYd6R$Z4:3/?_r]xeYLTɃ5]ҿ )C@ J@DSN8Կ%'c\RRR 0>1fw À:::jض'A9S1?" TN./@: ]~\V DQ/?CUNF8I$Ix"n_-jKOTfpQ1dYD&g :cv{ z'39y16tT%HEUs yڱ oM~oH^ju5ퟅc젮Hm6G]jB R>}TTܺC4-,/B2\,6cۙFb((Աc TםX.wPi$Ij 9hʫR[J?.5ȩ={4OvUń@ v- Wcm禺_窨դ#E"r֬GvxC&Vx4>*zcZoggG`~܌GULl pe,iT?/nE Àپ3OqLFkcVa!`07Euyˎ CiPf|7}~~c|EVLd3 ʚMLr9h5&Д+&]6N?7梳+h+eq=FAaTPɖ>7b #mK~q)L,p1n@rAiɹ7Ł2=443.n*TZp] 2V ~?͸hwk۱XE9~E@W9maz^IjsX۰{28 ИR.gA6tC/o}E${"1-0A?/do^IENDB`ostinato-0.5.1/client/icons/portstats_clear.png0000700000175300010010000000055712005505614021207 0ustar srivatspNonePNG  IHDRa6IDATxc?%"0ߟO_1`Z #A|}/O*hq! XE~}y?u /f"+?:ɾR9 w)͙DNsf7ϟ>@atPG՘;X]T??>{7?YE9deCafRd`r.r{^26gVd뛄J$k+";+y 9`3iIENDB`ostinato-0.5.1/client/icons/portstats_clear_all.png0000700000175300010010000000134012005505614022026 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<rIDATMluOwݺ5d[mdpjN81f<c49qNje'ge[3f۵ݠ]Y&'oT>w#u23@P5QC5DG~i1S{9/inaQ01Le]#~KS §&MXLr fXkDMuŎ!2H X+"Y'\  ͠.v!b&z~hzpEro" 'E6j?…kĉU رqw<{+e_<7fyeo'S"f]tgˍӶpJ2?Mg:[h UCymUepw6L3wUnuQ(*FPCT?ń"zW5IENDB`ostinato-0.5.1/client/icons/portstats_filter.png0000700000175300010010000000066012005505614021401 0ustar srivatspNonePNG  IHDR7gAMA7tEXtSoftwareAdobe ImageReadyqe<BIDAT(}JAl Z  MQm "fIRpaNIop3yLYiklJ?1d蠆A@m)]cfn"8D!\ dTݵX氁WV8WH됲oP`Hwj<>ZjXg`>*‘u@@%/beP#>u  (=F$U T~TXe[# qcZt]F7b+y4X*W#X<1I 9; Dg=mF_W|*IuuRIENDB`ostinato-0.5.1/client/icons/preferences.png0000700000175300010010000000111012005505614020261 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˕kSQ8H)N]uA,wjazcbb6& Qcn^b4b2e l xW }$9Xt:$n"0T8J)N!h4ʉF|p8|2X,f[͵`0S~OZ% } iz=nHXt:4 "BrLRtv_T'-lu&f_uRl6 u]e 5~lޢnz{ejjUiw|}?$&x r|TN%*4Ç l;'T^ٗG <"pFୌw!yhݔeE6  ܙצ PJ:C\DW^,<<4 A ѹ]s6ޑIENDB`ostinato-0.5.1/client/icons/qt.png0000700000175300010010000000376512005505614016426 0ustar srivatspNonePNG  IHDR szzIDATx^ŗk\e眹twg)A[z"ֆ\FK"-H$E%"1^HP>C0|P&^0[J(-.m\/;s{xvrƝ&"ɛdI_ 5` /#p0p<7fgr`z K?f `NP_>G?g.`.C}~7HIN^*IENDB`ostinato-0.5.1/client/icons/sound_mute.png0000700000175300010010000000073212005505614020153 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<lIDAT8œKaצf'ɻ(==R""Ǧ!8!NDR!A-AA xy|>/78LP(䃲,=X' K"$i ,LhZɥi1ŢfSGsהRIEVEZFRFvlO>%0gygzv0 !s3tW>E,8`ۉ8lK:!0<2 .^l`/h48+F(X[8hx7tF>z;B"o,²%BɤL&h4<[@^R.ڦSQ>,SF&>4>pG}IENDB`ostinato-0.5.1/client/icons/sound_none.png0000700000175300010010000000064112005505614020137 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<3IDAT8ӱj@pʒ9[%S)%&Ԩ5Z"zDMEAE!Cqck_Lݮ]@7KJ@yV&G< PA XucFI(a<aY!c+=>i$I\.Aa`Y<Rt]ضOL>p| ]ס( dY$I0M:ѨP( a@D`j6e J;KVJEA׋o'qlhZg?$k^+)G>w jIENDB`ostinato-0.5.1/client/icons/stream_add.png0000700000175300010010000000145612005505614020100 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8uK[Aƃ,.jRpQh5J`ARP4($bHjJM `L(F3>4G/ -zP0 w7sut7͵5Rjaa!EsER''';O$%xt||F{H*tZ?77$Tb@Ȉ:00Sd2}\\\`oo$Sguw(B$. R+=$ rAdI>!F-u0S?/+A;'/@t\.ơqwȅg GO]]jX=AvypK5B\Szj677|jjTX4ndy}!fmm:UYY2?ey1B0_IENDB`ostinato-0.5.1/client/icons/stream_delete.png0000700000175300010010000000151712005505614020610 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8uSKHQofL$QT0f%Һ1ht(nBtg JC (.E,n`%U`bCIBlbb43 6pg{syoXZ~J_e\Pȁ8M2 \3"Y.}Ʀ=l2crZLk{X~w`kkkLAIDJXRbE!}ܷqpzzz=K$䅑l9#慠u"*sW2&iT)Fhn *aP ### qD"yfD=:Ж*,--e,C۹#U$R|@}NSBM"oHN*FNx1L3ٍt:݌cF>W!0w+kNӶi:µ'V()Q`t XLUlIn)tP -E9Z%{*8;>>V'_L7 -`saz0bz.6]UlЋ.f1T&Abpp---{[Q҉; EXdt0dԧ/Ewc UⳘ כ2*JiX\!Lɡ+9;RDEӕA˳HJ$^ѯbEpzD"y<0X ]=K\ ^&qPUU+//?Ɓ! */ #include "mainwindow.h" #include "../common/ostprotolib.h" #include "../common/protocolmanager.h" #include "settings.h" #include #include #include #include extern const char* version; extern const char* revision; extern ProtocolManager *OstProtocolManager; QSettings *appSettings; QMainWindow *mainWindow; #if defined(Q_OS_WIN32) QString kGzipPathDefaultValue; QString kDiffPathDefaultValue; QString kAwkPathDefaultValue; #endif int main(int argc, char* argv[]) { QApplication app(argc, argv); int exitCode; #if defined(Q_OS_WIN32) kGzipPathDefaultValue = app.applicationDirPath() + "/gzip.exe"; kDiffPathDefaultValue = app.applicationDirPath() + "/diff.exe"; kAwkPathDefaultValue = app.applicationDirPath() + "/gawk.exe"; #endif app.setApplicationName("Ostinato"); app.setOrganizationName("Ostinato"); app.setProperty("version", version); app.setProperty("revision", revision); OstProtocolManager = new ProtocolManager(); /* (Portable Mode) If we have a .ini file in the same directory as the executable, we use that instead of the platform specific location and format for the settings */ QString portableIni = QCoreApplication::applicationDirPath() + "/ostinato.ini"; if (QFile::exists(portableIni)) appSettings = new QSettings(portableIni, QSettings::IniFormat); else appSettings = new QSettings(); OstProtoLib::setExternalApplicationPaths( appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(), appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString(), appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(), appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString()); mainWindow = new MainWindow; mainWindow->show(); exitCode = app.exec(); delete mainWindow; delete appSettings; delete OstProtocolManager; google::protobuf::ShutdownProtobufLibrary(); return exitCode; } ostinato-0.5.1/client/mainwindow.cpp0000700000175300010010000000717112005505614017034 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "mainwindow.h" #if 0 #include "dbgthread.h" #endif #include "portgrouplist.h" #include "portstatswindow.h" #include "portswindow.h" #include "preferences.h" #include "settings.h" #include "ui_about.h" #include #include extern const char* version; extern const char* revision; PortGroupList *pgl; MainWindow::MainWindow(QWidget *parent) : QMainWindow (parent) { QString serverApp = QCoreApplication::applicationDirPath(); #ifdef Q_OS_MAC // applicationDirPath() does not return bundle, but executable inside bundle serverApp.replace("Ostinato.app", "drone.app"); #endif #ifdef Q_OS_WIN32 serverApp.append("/drone.exe"); #else serverApp.append("/drone"); #endif localServer_ = new QProcess(this); localServer_->setProcessChannelMode(QProcess::ForwardedChannels); localServer_->start(serverApp, QStringList()); pgl = new PortGroupList; portsWindow = new PortsWindow(pgl, this); statsWindow = new PortStatsWindow(pgl, this); portsDock = new QDockWidget(tr("Ports and Streams"), this); portsDock->setObjectName("portsDock"); portsDock->setFeatures( portsDock->features() & ~QDockWidget::DockWidgetClosable); statsDock = new QDockWidget(tr("Statistics"), this); statsDock->setObjectName("statsDock"); statsDock->setFeatures( statsDock->features() & ~QDockWidget::DockWidgetClosable); setupUi(this); menuFile->insertActions(menuFile->actions().at(0), portsWindow->actions()); statsDock->setWidget(statsWindow); addDockWidget(Qt::BottomDockWidgetArea, statsDock); portsDock->setWidget(portsWindow); addDockWidget(Qt::TopDockWidgetArea, portsDock); QRect geom = appSettings->value(kApplicationWindowGeometryKey).toRect(); if (!geom.isNull()) setGeometry(geom); QByteArray layout = appSettings->value(kApplicationWindowLayout) .toByteArray(); if (layout.size()) restoreState(layout, 0); connect(actionFileExit, SIGNAL(triggered()), this, SLOT(close())); connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); #if 0 { DbgThread *dbg = new DbgThread(pgl); dbg->start(); } #endif } MainWindow::~MainWindow() { delete pgl; localServer_->terminate(); localServer_->waitForFinished(); delete localServer_; QByteArray layout = saveState(0); appSettings->setValue(kApplicationWindowLayout, layout); appSettings->setValue(kApplicationWindowGeometryKey, geometry()); } void MainWindow::on_actionPreferences_triggered() { Preferences *preferences = new Preferences(); preferences->exec(); delete preferences; } void MainWindow::on_actionHelpAbout_triggered() { QDialog *aboutDialog = new QDialog; Ui::About about; about.setupUi(aboutDialog); about.versionLabel->setText( QString("Version: %1 Revision: %2").arg(version).arg(revision)); aboutDialog->exec(); delete aboutDialog; } ostinato-0.5.1/client/mainwindow.h0000700000175300010010000000241212005505614016472 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _MAIN_WINDOW_H #define _MAIN_WINDOW_H #include "ui_mainwindow.h" #include class PortsWindow; class PortStatsWindow; class QDockWidget; class QProcess; class MainWindow : public QMainWindow, private Ui::MainWindow { Q_OBJECT private: QProcess *localServer_; PortsWindow *portsWindow; PortStatsWindow *statsWindow; QDockWidget *portsDock; QDockWidget *statsDock; public: MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: void on_actionPreferences_triggered(); void on_actionHelpAbout_triggered(); }; #endif ostinato-0.5.1/client/mainwindow.ui0000700000175300010010000000432012005505614016660 0ustar srivatspNone MainWindow 0 0 700 550 Ostinato :/icons/about.png 0 0 700 21 File Help :/icons/exit.png E&xit :/icons/about.png &About :/icons/preferences.png Preferences :/icons/qt.png About Qt ostinato-0.5.1/client/modeltest.cpp0000700000175300010010000004717012005505614016663 0ustar srivatspNone/**************************************************************************** ** ** 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))); } ostinato-0.5.1/client/modeltest.h0000700000175300010010000000433412005505614016323 0ustar srivatspNone/**************************************************************************** ** ** 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 ostinato-0.5.1/client/modeltest.pri0000700000175300010010000000014512005505614016662 0ustar srivatspNoneINCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += $$PWD/modeltest.cpp HEADERS += $$PWD/modeltest.h ostinato-0.5.1/client/ostinato.pro0000700000175300010010000000404412005505614016532 0ustar srivatspNoneTEMPLATE = app CONFIG += qt macx: TARGET = Ostinato win32:RC_FILE = ostinato.rc macx:ICON = icons/logo.icns QT += network script xml INCLUDEPATH += "../rpc/" "../common/" win32 { CONFIG(debug, debug|release) { LIBS += -L"../common/debug" -lostproto LIBS += -L"../rpc/debug" -lpbrpc POST_TARGETDEPS += \ "../common/debug/libostproto.a" \ "../rpc/debug/libpbrpc.a" } else { LIBS += -L"../common/release" -lostproto LIBS += -L"../rpc/release" -lpbrpc POST_TARGETDEPS += \ "../common/release/libostproto.a" \ "../rpc/release/libpbrpc.a" } } else { LIBS += -L"../common" -lostproto LIBS += -L"../rpc" -lpbrpc POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a" } LIBS += -lprotobuf LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2 RESOURCES += ostinato.qrc HEADERS += \ dumpview.h \ hexlineedit.h \ mainwindow.h \ packetmodel.h \ port.h \ portconfigdialog.h \ portgroup.h \ portgrouplist.h \ portmodel.h \ portstatsmodel.h \ portstatsfilterdialog.h \ portstatswindow.h \ portswindow.h \ preferences.h \ settings.h \ streamconfigdialog.h \ streamlistdelegate.h \ streammodel.h FORMS += \ about.ui \ mainwindow.ui \ portconfigdialog.ui \ portstatsfilter.ui \ portstatswindow.ui \ portswindow.ui \ preferences.ui \ streamconfigdialog.ui SOURCES += \ dumpview.cpp \ stream.cpp \ hexlineedit.cpp \ main.cpp \ mainwindow.cpp \ packetmodel.cpp \ port.cpp \ portconfigdialog.cpp \ portgroup.cpp \ portgrouplist.cpp \ portmodel.cpp \ portstatsmodel.cpp \ portstatsfilterdialog.cpp \ portstatswindow.cpp \ portswindow.cpp \ preferences.cpp \ streamconfigdialog.cpp \ streamlistdelegate.cpp \ streammodel.cpp QMAKE_DISTCLEAN += object_script.* include(../install.pri) include(../version.pri) # TODO(LOW): Test only CONFIG(debug, debug|release):include(modeltest.pri) ostinato-0.5.1/client/ostinato.qrc0000700000175300010010000000275212005505614016523 0ustar srivatspNone icons/about.png icons/arrow_down.png icons/arrow_left.png icons/arrow_right.png icons/arrow_up.png icons/bullet_error.png icons/bullet_green.png icons/bullet_orange.png icons/bullet_red.png icons/bullet_white.png icons/bullet_yellow.png icons/control_play.png icons/control_stop.png icons/deco_exclusive.png icons/delete.png icons/exit.png icons/gaps.png icons/logo.png icons/magnifier.png icons/name.png icons/portgroup_add.png icons/portgroup_connect.png icons/portgroup_delete.png icons/portgroup_disconnect.png icons/portstats_clear.png icons/portstats_clear_all.png icons/portstats_filter.png icons/preferences.png icons/qt.png icons/sound_mute.png icons/sound_none.png icons/stream_add.png icons/stream_delete.png icons/stream_edit.png ostinato-0.5.1/client/ostinato.rc0000700000175300010010000000010212005505614016325 0ustar srivatspNoneIDI_ICON1 ICON DISCARDABLE "icons/logo.ico" ostinato-0.5.1/client/packetmodel.cpp0000700000175300010010000001416112005505614017145 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "packetmodel.h" #include "../common/protocollistiterator.h" #include "../common/abstractprotocol.h" PacketModel::PacketModel(QObject *parent) : QAbstractItemModel(parent) { } void PacketModel::setSelectedProtocols(ProtocolListIterator &iter) { QList currentProtocols; iter.toFront(); while (iter.hasNext()) currentProtocols.append(iter.next()); if (mSelectedProtocols != currentProtocols) { mSelectedProtocols = currentProtocols; reset(); } else { emit layoutAboutToBeChanged(); emit layoutChanged(); } } int PacketModel::rowCount(const QModelIndex &parent) const { IndexId parentId; // qDebug("in %s", __FUNCTION__); // Parent == Invalid i.e. Invisible Root. // ==> Children are Protocol (Top Level) Items if (!parent.isValid()) return mSelectedProtocols.size(); // Parent - Valid Item parentId.w = parent.internalId(); switch(parentId.ws.type) { case ITYP_PROTOCOL: return mSelectedProtocols.at(parentId.ws.protocol)->frameFieldCount(); case ITYP_FIELD: return 0; default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } Q_ASSERT(1 == 0); // Unreachable code qWarning("%s: Catch all - need to investigate", __FUNCTION__); return 0; // catch all } int PacketModel::columnCount(const QModelIndex &/*parent*/) const { return 1; } QModelIndex PacketModel::index(int row, int col, const QModelIndex &parent) const { QModelIndex index; IndexId id, parentId; if (!hasIndex(row, col, parent)) goto _exit; // Parent is Invisible Root // Request for a Protocol Item if (!parent.isValid()) { id.w = 0; id.ws.type = ITYP_PROTOCOL; id.ws.protocol = row; index = createIndex(row, col, id.w); goto _exit; } // Parent is a Valid Item parentId.w = parent.internalId(); id.w = parentId.w; switch(parentId.ws.type) { case ITYP_PROTOCOL: id.ws.type = ITYP_FIELD; index = createIndex(row, col, id.w); goto _exit; case ITYP_FIELD: Q_ASSERT(1 == 0); // Unreachable code goto _exit; default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } Q_ASSERT(1 == 0); // Unreachable code _exit: return index; } QModelIndex PacketModel::parent(const QModelIndex &index) const { QModelIndex parentIndex; IndexId id, parentId; if (!index.isValid()) return QModelIndex(); id.w = index.internalId(); parentId.w = id.w; switch(id.ws.type) { case ITYP_PROTOCOL: // return invalid index for invisible root goto _exit; case ITYP_FIELD: parentId.ws.type = ITYP_PROTOCOL; parentIndex = createIndex(id.ws.protocol, 0, parentId.w); goto _exit; default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } Q_ASSERT(1 == 1); // Unreachable code _exit: return parentIndex; } QVariant PacketModel::data(const QModelIndex &index, int role) const { IndexId id; int fieldIdx = 0; if (!index.isValid()) return QVariant(); id.w = index.internalId(); if (id.ws.type == ITYP_FIELD) { const AbstractProtocol *p = mSelectedProtocols.at(id.ws.protocol); int n = index.row() + 1; while (n) { if (p->fieldFlags(fieldIdx).testFlag(AbstractProtocol::FrameField)) n--; fieldIdx++; } fieldIdx--; } // FIXME(HI): Relook at this completely if (role == Qt::UserRole) { switch(id.ws.type) { case ITYP_PROTOCOL: qDebug("*** %d/%d", id.ws.protocol, mSelectedProtocols.size()); return mSelectedProtocols.at(id.ws.protocol)-> protocolFrameValue(); case ITYP_FIELD: return mSelectedProtocols.at(id.ws.protocol)->fieldData( fieldIdx, AbstractProtocol::FieldFrameValue); default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } return QByteArray(); } // FIXME: Use a new enum here instead of UserRole if (role == (Qt::UserRole+1)) { switch(id.ws.type) { case ITYP_PROTOCOL: return mSelectedProtocols.at(id.ws.protocol)-> protocolFrameValue().size(); case ITYP_FIELD: return mSelectedProtocols.at(id.ws.protocol)->fieldData( fieldIdx, AbstractProtocol::FieldBitSize); default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } return QVariant(); } if (role != Qt::DisplayRole) return QVariant(); switch(id.ws.type) { case ITYP_PROTOCOL: return QString("%1 (%2)") .arg(mSelectedProtocols.at(id.ws.protocol)->shortName()) .arg(mSelectedProtocols.at(id.ws.protocol)->name()); case ITYP_FIELD: return mSelectedProtocols.at(id.ws.protocol)->fieldData(fieldIdx, AbstractProtocol::FieldName).toString() + QString(" : ") + mSelectedProtocols.at(id.ws.protocol)->fieldData(fieldIdx, AbstractProtocol::FieldTextValue).toString(); default: qWarning("%s: Unhandled ItemType", __FUNCTION__); } Q_ASSERT(1 == 1); // Unreachable code return QVariant(); } ostinato-0.5.1/client/packetmodel.h0000700000175300010010000000342412005505614016612 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PACKET_MODEL_H #define _PACKET_MODEL_H #include class ProtocolListIterator; class AbstractProtocol; class PacketModel: public QAbstractItemModel { public: PacketModel(QObject *parent = 0); void setSelectedProtocols(ProtocolListIterator &iter); 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 { return QVariant(); } QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const; QModelIndex parent(const QModelIndex &index) const; private: typedef union _IndexId { quint32 w; struct { quint16 type; #define ITYP_PROTOCOL 1 #define ITYP_FIELD 2 quint16 protocol; // protocol is valid for both ITYPs } ws; } IndexId; QList mSelectedProtocols; }; #endif ostinato-0.5.1/client/port.cpp0000700000175300010010000003514012005505614015641 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "port.h" #include "abstractfileformat.h" #include #include #include #include #include #include extern QMainWindow *mainWindow; uint Port::mAllocStreamId = 0; static const int kEthOverhead = 20; uint Port::newStreamId() { return mAllocStreamId++; } Port::Port(quint32 id, quint32 portGroupId) { mPortId = id; d.mutable_port_id()->set_id(id); stats.mutable_port_id()->set_id(id); mPortGroupId = portGroupId; capFile_ = NULL; } Port::~Port() { qDebug("%s", __FUNCTION__); while (!mStreams.isEmpty()) delete mStreams.takeFirst(); } void Port::updatePortConfig(OstProto::Port *port) { d.MergeFrom(*port); } void Port::updateStreamOrdinalsFromIndex() { for (int i=0; i < mStreams.size(); i++) mStreams[i]->setOrdinal(i); } void Port::reorderStreamsByOrdinals() { qSort(mStreams.begin(), mStreams.end(), StreamBase::StreamLessThan); } void Port::recalculateAverageRates() { double pps = 0; double bps = 0; int n = 0; foreach (Stream* s, mStreams) { if (!s->isEnabled()) continue; double r = s->averagePacketRate(); pps += r; bps += r * (s->frameLenAvg() + kEthOverhead) * 8; n++; if ((transmitMode() == OstProto::kSequentialTransmit) && (s->nextWhat() == Stream::e_nw_stop)) break; } if (n) { switch (transmitMode()) { case OstProto::kSequentialTransmit: avgPacketsPerSec_ = pps/n; avgBitsPerSec_ = bps/n; break; case OstProto::kInterleavedTransmit: avgPacketsPerSec_ = pps; avgBitsPerSec_ = bps; break; default: Q_ASSERT(false); // Unreachable!! } numActiveStreams_ = n; } else avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0; qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__, avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_); emit portRateChanged(mPortGroupId, mPortId); } void Port::setAveragePacketRate(double packetsPerSec) { double rate; double pps = 0; double bps = 0; int n = 0; qDebug("@%s: packetsPerSec = %g", __FUNCTION__, packetsPerSec); qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__, avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_); foreach (Stream* s, mStreams) { if (!s->isEnabled()) continue; switch (transmitMode()) { case OstProto::kSequentialTransmit: rate = s->averagePacketRate() * (packetsPerSec/avgPacketsPerSec_); break; case OstProto::kInterleavedTransmit: rate = s->averagePacketRate() + ((s->averagePacketRate()/avgPacketsPerSec_) * (packetsPerSec - avgPacketsPerSec_)); break; default: Q_ASSERT(false); // Unreachable!! } qDebug("cur stream pps = %g", s->averagePacketRate()); s->setAveragePacketRate(rate); qDebug("new stream pps = %g", s->averagePacketRate()); double r = s->averagePacketRate(); pps += r; bps += r * (s->frameLenAvg() + kEthOverhead) * 8; n++; if ((transmitMode() == OstProto::kSequentialTransmit) && (s->nextWhat() == Stream::e_nw_stop)) break; } if (n) { switch (transmitMode()) { case OstProto::kSequentialTransmit: avgPacketsPerSec_ = pps/n; avgBitsPerSec_ = bps/n; break; case OstProto::kInterleavedTransmit: avgPacketsPerSec_ = pps; avgBitsPerSec_ = bps; break; default: Q_ASSERT(false); // Unreachable!! } numActiveStreams_ = n; } else avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0; qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__, avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_); emit portRateChanged(mPortGroupId, mPortId); } void Port::setAverageBitRate(double bitsPerSec) { double rate; double pps = 0; double bps = 0; int n = 0; qDebug("@%s: bitsPerSec = %g", __FUNCTION__, bitsPerSec); qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__, avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_); foreach (Stream* s, mStreams) { if (!s->isEnabled()) continue; switch (transmitMode()) { case OstProto::kSequentialTransmit: rate = s->averagePacketRate() * (bitsPerSec/avgBitsPerSec_); qDebug("rate = %g", rate); break; case OstProto::kInterleavedTransmit: rate = s->averagePacketRate() + ((s->averagePacketRate()/avgPacketsPerSec_) * ((bitsPerSec - avgBitsPerSec_) / ((s->frameLenAvg()+kEthOverhead)*8))); break; default: Q_ASSERT(false); // Unreachable!! } qDebug("cur stream pps = %g", s->averagePacketRate()); s->setAveragePacketRate(rate); qDebug("new stream pps = %g", s->averagePacketRate()); double r = s->averagePacketRate(); pps += r; bps += r * (s->frameLenAvg() + kEthOverhead) * 8; n++; if ((transmitMode() == OstProto::kSequentialTransmit) && (s->nextWhat() == Stream::e_nw_stop)) break; } if (n) { switch (transmitMode()) { case OstProto::kSequentialTransmit: avgPacketsPerSec_ = pps/n; avgBitsPerSec_ = bps/n; break; case OstProto::kInterleavedTransmit: avgPacketsPerSec_ = pps; avgBitsPerSec_ = bps; break; default: Q_ASSERT(false); // Unreachable!! } numActiveStreams_ = n; } else avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0; qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__, avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_); emit portRateChanged(mPortGroupId, mPortId); } bool Port::newStreamAt(int index, OstProto::Stream const *stream) { Stream *s = new Stream; if (index > mStreams.size()) return false; if (stream) s->protoDataCopyFrom(*stream); s->setId(newStreamId()); mStreams.insert(index, s); updateStreamOrdinalsFromIndex(); recalculateAverageRates(); return true; } bool Port::deleteStreamAt(int index) { if (index >= mStreams.size()) return false; delete mStreams.takeAt(index); updateStreamOrdinalsFromIndex(); recalculateAverageRates(); return true; } bool Port::insertStream(uint streamId) { Stream *s = new Stream; s->setId(streamId); // FIXME(MED): If a stream with id already exists, what do we do? mStreams.append(s); // Update mAllocStreamId to take into account the stream id received // from server if (mAllocStreamId <= streamId) mAllocStreamId = streamId + 1; return true; } bool Port::updateStream(uint streamId, OstProto::Stream *stream) { int i, streamIndex; for (i = 0; i < mStreams.size(); i++) { if (streamId == mStreams[i]->id()) goto _found; } qDebug("%s: Invalid stream id %d", __FUNCTION__, streamId); return false; _found: streamIndex = i; mStreams[streamIndex]->protoDataCopyFrom(*stream); reorderStreamsByOrdinals(); return true; } void Port::getDeletedStreamsSinceLastSync( OstProto::StreamIdList &streamIdList) { streamIdList.clear_stream_id(); for (int i = 0; i < mLastSyncStreamList.size(); i++) { int j; for (j = 0; j < mStreams.size(); j++) { if (mLastSyncStreamList[i] == mStreams[j]->id()) break; } if (j < mStreams.size()) { // stream still exists! continue; } else { // stream has been deleted since last sync OstProto::StreamId *s; s = streamIdList.add_stream_id(); s->set_id(mLastSyncStreamList.at(i)); } } } void Port::getNewStreamsSinceLastSync( OstProto::StreamIdList &streamIdList) { streamIdList.clear_stream_id(); for (int i = 0; i < mStreams.size(); i++) { if (mLastSyncStreamList.contains(mStreams[i]->id())) { // existing stream! continue; } else { // new stream! OstProto::StreamId *s; s = streamIdList.add_stream_id(); s->set_id(mStreams[i]->id()); } } } void Port::getModifiedStreamsSinceLastSync( OstProto::StreamConfigList &streamConfigList) { qDebug("In %s", __FUNCTION__); //streamConfigList.mutable_port_id()->set_id(mPortId); for (int i = 0; i < mStreams.size(); i++) { OstProto::Stream *s; s = streamConfigList.add_stream(); mStreams[i]->protoDataCopyInto(*s); } qDebug("Done %s", __FUNCTION__); } void Port::when_syncComplete() { //reorderStreamsByOrdinals(); mLastSyncStreamList.clear(); for (int i=0; iid()); } void Port::updateStats(OstProto::PortStats *portStats) { OstProto::PortState oldState; oldState = stats.state(); stats.MergeFrom(*portStats); if (oldState.link_state() != stats.state().link_state()) { qDebug("portstate changed"); emit portDataChanged(mPortGroupId, mPortId); } } bool Port::openStreams(QString fileName, bool append, QString &error) { bool ret = false; QDialog *optDialog; QProgressDialog progress("Opening Streams", "Cancel", 0, 0, mainWindow); OstProto::StreamConfigList streams; AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromFile(fileName); if (fmt == NULL) goto _fail; if ((optDialog = fmt->openOptionsDialog())) { int ret; optDialog->setParent(mainWindow, Qt::Dialog); ret = optDialog->exec(); optDialog->setParent(0, Qt::Dialog); if (ret == QDialog::Rejected) goto _user_opt_cancel; } progress.setAutoReset(false); progress.setAutoClose(false); progress.setMinimumDuration(0); progress.show(); mainWindow->setDisabled(true); progress.setEnabled(true); // to override the mainWindow disable connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString))); connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int))); connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int))); connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel())); fmt->openStreamsOffline(fileName, streams, error); qDebug("after open offline"); while (!fmt->isFinished()) qApp->processEvents(); qDebug("wait over for offline operation"); if (!fmt->result()) goto _fail; // process any remaining events posted from the thread for (int i = 0; i < 10; i++) qApp->processEvents(); if (!append) { int n = numStreams(); progress.setLabelText("Deleting existing streams..."); progress.setRange(0, n); for (int i = 0; i < n; i++) { if (progress.wasCanceled()) goto _user_cancel; deleteStreamAt(0); progress.setValue(i); if (i % 32 == 0) qApp->processEvents(); } } progress.setLabelText("Constructing new streams..."); progress.setRange(0, streams.stream_size()); for (int i = 0; i < streams.stream_size(); i++) { if (progress.wasCanceled()) goto _user_cancel; newStreamAt(mStreams.size(), &streams.stream(i)); progress.setValue(i); if (i % 32 == 0) qApp->processEvents(); } _user_cancel: emit streamListChanged(mPortGroupId, mPortId); _user_opt_cancel: ret = true; _fail: progress.close(); mainWindow->setEnabled(true); recalculateAverageRates(); return ret; } bool Port::saveStreams(QString fileName, QString fileType, QString &error) { bool ret = false; QProgressDialog progress("Saving Streams", "Cancel", 0, 0, mainWindow); AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType(fileType); OstProto::StreamConfigList streams; if (fmt == NULL) goto _fail; progress.setAutoReset(false); progress.setAutoClose(false); progress.setMinimumDuration(0); progress.show(); mainWindow->setDisabled(true); progress.setEnabled(true); // to override the mainWindow disable connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString))); connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int))); connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int))); connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel())); progress.setLabelText("Preparing Streams..."); progress.setRange(0, mStreams.size()); streams.mutable_port_id()->set_id(0); for (int i = 0; i < mStreams.size(); i++) { OstProto::Stream *s = streams.add_stream(); mStreams[i]->protoDataCopyInto(*s); if (progress.wasCanceled()) goto _user_cancel; progress.setValue(i); if (i % 32 == 0) qApp->processEvents(); } fmt->saveStreamsOffline(streams, fileName, error); qDebug("after save offline"); while (!fmt->isFinished()) qApp->processEvents(); qDebug("wait over for offline operation"); ret = fmt->result(); goto _exit; _user_cancel: goto _exit; _fail: error = QString("Unsupported File Type - %1").arg(fileType); goto _exit; _exit: progress.close(); mainWindow->setEnabled(true); return ret; } ostinato-0.5.1/client/port.h0000700000175300010010000001077512005505614015315 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_H #define _PORT_H #include #include #include #include "stream.h" //class StreamModel; class Port : public QObject { Q_OBJECT static uint mAllocStreamId; OstProto::Port d; OstProto::PortStats stats; QTemporaryFile *capFile_; // FIXME(HI): consider removing mPortId as it is duplicated inside 'd' quint32 mPortId; quint32 mPortGroupId; QString mUserAlias; // user defined double avgPacketsPerSec_; double avgBitsPerSec_; int numActiveStreams_; QList mLastSyncStreamList; QList mStreams; // sorted by stream's ordinal value uint newStreamId(); void updateStreamOrdinalsFromIndex(); void reorderStreamsByOrdinals(); public: enum AdminStatus { AdminDisable, AdminEnable }; // FIXME(HIGH): default args is a hack for QList operations on Port Port(quint32 id = 0xFFFFFFFF, quint32 pgId = 0xFFFFFFFF); ~Port(); quint32 portGroupId() const { return mPortGroupId; } const QString& userAlias() const { return mUserAlias; } quint32 id() const { return d.port_id().id(); } const QString name() const { return QString().fromStdString(d.name()); } const QString description() const { return QString().fromStdString(d.description()); } const QString notes() const { return QString().fromStdString(d.notes()); } AdminStatus adminStatus() { return (d.is_enabled()?AdminEnable:AdminDisable); } bool hasExclusiveControl() { return d.is_exclusive_control(); } OstProto::TransmitMode transmitMode() { return d.transmit_mode(); } double averagePacketRate() { return avgPacketsPerSec_; } double averageBitRate() { return avgBitsPerSec_; } //void setAdminEnable(AdminStatus status) { mAdminStatus = status; } void setAlias(QString &alias) { mUserAlias = alias; } //void setExclusive(bool flag); int numStreams() { return mStreams.size(); } Stream* streamByIndex(int index) { Q_ASSERT(index < mStreams.size()); return mStreams[index]; } OstProto::LinkState linkState() { return stats.state().link_state(); } OstProto::PortStats getStats() { return stats; } QTemporaryFile* getCaptureFile() { delete capFile_; capFile_ = new QTemporaryFile(); return capFile_; } // FIXME(MED): naming inconsistency - PortConfig/Stream; also retVal void updatePortConfig(OstProto::Port *port); //! Used by StreamModel //@{ bool newStreamAt(int index, OstProto::Stream const *stream = NULL); bool deleteStreamAt(int index); //@} //! Used by MyService::Stub to update from config received from server //@{ bool insertStream(uint streamId); bool updateStream(uint streamId, OstProto::Stream *stream); //@} void getDeletedStreamsSinceLastSync(OstProto::StreamIdList &streamIdList); void getNewStreamsSinceLastSync(OstProto::StreamIdList &streamIdList); void getModifiedStreamsSinceLastSync( OstProto::StreamConfigList &streamConfigList); void when_syncComplete(); void setAveragePacketRate(double packetsPerSec); void setAverageBitRate(double bitsPerSec); // FIXME(MED): Bad Hack! port should not need an external trigger to // recalculate - refactor client side domain objects and model objects void recalculateAverageRates(); void updateStats(OstProto::PortStats *portStats); bool openStreams(QString fileName, bool append, QString &error); bool saveStreams(QString fileName, QString fileType, QString &error); signals: void portRateChanged(int portGroupId, int portId); void portDataChanged(int portGroupId, int portId); void streamListChanged(int portGroupId, int portId); }; #endif ostinato-0.5.1/client/portconfigdialog.cpp0000700000175300010010000000331612005505614020207 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portconfigdialog.h" PortConfigDialog::PortConfigDialog(OstProto::Port &portConfig, QWidget *parent) : QDialog(parent), portConfig_(portConfig) { qDebug("In %s", __FUNCTION__); setupUi(this); switch(portConfig_.transmit_mode()) { case OstProto::kSequentialTransmit: sequentialStreamsButton->setChecked(true); break; case OstProto::kInterleavedTransmit: interleavedStreamsButton->setChecked(true); break; default: Q_ASSERT(false); // Unreachable!!! break; } exclusiveControlButton->setChecked(portConfig_.is_exclusive_control()); } void PortConfigDialog::accept() { if (sequentialStreamsButton->isChecked()) portConfig_.set_transmit_mode(OstProto::kSequentialTransmit); else if (interleavedStreamsButton->isChecked()) portConfig_.set_transmit_mode(OstProto::kInterleavedTransmit); else Q_ASSERT(false); // Unreachable!!! portConfig_.set_is_exclusive_control(exclusiveControlButton->isChecked()); QDialog::accept(); } ostinato-0.5.1/client/portconfigdialog.h0000700000175300010010000000202212005505614017645 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_CONFIG_DIALOG_H #define _PORT_CONFIG_DIALOG_H #include "ui_portconfigdialog.h" #include "protocol.pb.h" #include class PortConfigDialog : public QDialog, public Ui::PortConfigDialog { public: PortConfigDialog(OstProto::Port &portConfig, QWidget *parent); private: virtual void accept(); OstProto::Port &portConfig_; }; #endif ostinato-0.5.1/client/portconfigdialog.ui0000700000175300010010000000504712005505614020045 0ustar srivatspNone PortConfigDialog 0 0 244 160 Port Config Transmit Mode Sequential Streams true Interleaved Streams Exclusive Control Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok buttonBox accepted() PortConfigDialog accept() 248 254 157 274 buttonBox rejected() PortConfigDialog reject() 316 260 286 274 ostinato-0.5.1/client/portgroup.cpp0000700000175300010010000005714112005505614016723 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portgroup.h" #include "settings.h" #include #include #include #include #include #include #include #include using ::google::protobuf::NewCallback; extern QMainWindow *mainWindow; quint32 PortGroup::mPortGroupAllocId = 0; PortGroup::PortGroup(QHostAddress ip, quint16 port) { // Allocate an id for self mPortGroupId = PortGroup::mPortGroupAllocId++; portIdList_ = new OstProto::PortIdList; portStatsList_ = new OstProto::PortStatsList; statsController = new PbRpcController(portIdList_, portStatsList_); isGetStatsPending_ = false; reconnect = false; reconnectAfter = kMinReconnectWaitTime; reconnectTimer = new QTimer(this); reconnectTimer->setSingleShot(true); connect(reconnectTimer, SIGNAL(timeout()), this, SLOT(on_reconnectTimer_timeout())); rpcChannel = new PbRpcChannel(ip, port); serviceStub = new OstProto::OstService::Stub(rpcChannel); // FIXME(LOW):Can't for my life figure out why this ain't working! //QMetaObject::connectSlotsByName(this); connect(rpcChannel, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(on_rpcChannel_stateChanged(QAbstractSocket::SocketState))); connect(rpcChannel, SIGNAL(connected()), this, SLOT(on_rpcChannel_connected())); connect(rpcChannel, SIGNAL(disconnected()), this, SLOT(on_rpcChannel_disconnected())); connect(rpcChannel, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_rpcChannel_error(QAbstractSocket::SocketError))); connect(this, SIGNAL(portListChanged(quint32)), this, SLOT(when_portListChanged(quint32)), Qt::QueuedConnection); } PortGroup::~PortGroup() { qDebug("PortGroup Destructor"); // Disconnect and free rpc channel etc. PortGroup::disconnectFromHost(); delete serviceStub; delete rpcChannel; delete statsController; } // ------------------------------------------------ // Slots // ------------------------------------------------ void PortGroup::on_reconnectTimer_timeout() { reconnectAfter *= 2; if (reconnectAfter > kMaxReconnectWaitTime) reconnectAfter = kMaxReconnectWaitTime; connectToHost(); } void PortGroup::on_rpcChannel_stateChanged(QAbstractSocket::SocketState state) { qDebug("state changed %d", state); switch (state) { case QAbstractSocket::UnconnectedState: case QAbstractSocket::ClosingState: break; default: emit portGroupDataChanged(mPortGroupId); } } void PortGroup::on_rpcChannel_connected() { OstProto::Void *void_ = new OstProto::Void; OstProto::PortIdList *portIdList = new OstProto::PortIdList; qDebug("connected\n"); emit portGroupDataChanged(mPortGroupId); reconnectAfter = kMinReconnectWaitTime; qDebug("requesting portlist ..."); PbRpcController *controller = new PbRpcController(void_, portIdList); serviceStub->getPortIdList(controller, void_, portIdList, NewCallback(this, &PortGroup::processPortIdList, controller)); } void PortGroup::on_rpcChannel_disconnected() { qDebug("disconnected\n"); emit portListAboutToBeChanged(mPortGroupId); while (!mPorts.isEmpty()) delete mPorts.takeFirst(); emit portListChanged(mPortGroupId); emit portGroupDataChanged(mPortGroupId); if (reconnect) { qDebug("starting reconnect timer for %d ms ...", reconnectAfter); reconnectTimer->start(reconnectAfter); } } void PortGroup::on_rpcChannel_error(QAbstractSocket::SocketError socketError) { qDebug("%s: error %d", __FUNCTION__, socketError); emit portGroupDataChanged(mPortGroupId); qDebug("%s: state %d", __FUNCTION__, rpcChannel->state()); if ((rpcChannel->state() == QAbstractSocket::UnconnectedState) && reconnect) { qDebug("starting reconnect timer for %d ms...", reconnectAfter); reconnectTimer->start(reconnectAfter); } } void PortGroup::when_portListChanged(quint32 /*portGroupId*/) { if (state() == QAbstractSocket::ConnectedState && numPorts() <= 0) { QMessageBox::warning(NULL, tr("No ports in portgroup"), QString("The portgroup %1:%2 does not contain any ports!\n\n" "Packet Transmit/Capture requires elevated privileges. " "Please ensure that you are running 'drone' - the server " "component of Ostinato with admin/root OR setuid privilege.\n\n" "For more information see " "http://code.google.com/p/ostinato/wiki/FAQ#" "Q._Port_group_has_no_interfaces") .arg(serverAddress().toString()) .arg(int(serverPort()))); } } void PortGroup::processPortIdList(PbRpcController *controller) { OstProto::PortIdList *portIdList = static_cast(controller->response()); Q_ASSERT(portIdList != NULL); qDebug("got a portlist ..."); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _error_exit; } emit portListAboutToBeChanged(mPortGroupId); for(int i = 0; i < portIdList->port_id_size(); i++) { Port *p; p = new Port(portIdList->port_id(i).id(), mPortGroupId); connect(p, SIGNAL(portDataChanged(int, int)), this, SIGNAL(portGroupDataChanged(int, int))); qDebug("before port append\n"); mPorts.append(p); } emit portListChanged(mPortGroupId); portIdList_->CopyFrom(*portIdList); // Request PortConfigList { qDebug("requesting port config list ..."); OstProto::PortIdList *portIdList2 = new OstProto::PortIdList(); OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList(); PbRpcController *controller2 = new PbRpcController(portIdList2, portConfigList); portIdList2->CopyFrom(*portIdList); serviceStub->getPortConfig(controller, portIdList2, portConfigList, NewCallback(this, &PortGroup::processPortConfigList, controller2)); goto _exit; } _error_exit: _exit: delete controller; } void PortGroup::processPortConfigList(PbRpcController *controller) { OstProto::PortConfigList *portConfigList = static_cast(controller->response()); qDebug("In %s", __FUNCTION__); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _error_exit; } //emit portListAboutToBeChanged(mPortGroupId); for(int i = 0; i < portConfigList->port_size(); i++) { uint id; id = portConfigList->port(i).port_id().id(); // FIXME: don't mix port id & index into mPorts[] mPorts[id]->updatePortConfig(portConfigList->mutable_port(i)); } //emit portListChanged(mPortGroupId); // FIXME: check if we need new signals since we are not changing the // number of ports, just the port data if (numPorts() > 0) getStreamIdList(); _error_exit: delete controller; } void PortGroup::when_configApply(int portIndex) { OstProto::StreamIdList *streamIdList; OstProto::StreamConfigList *streamConfigList; OstProto::Ack *ack; PbRpcController *controller; Q_ASSERT(portIndex < mPorts.size()); if (state() != QAbstractSocket::ConnectedState) return; QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); mainWindow->setDisabled(true); qDebug("applying 'deleted streams' ..."); streamIdList = new OstProto::StreamIdList; ack = new OstProto::Ack; controller = new PbRpcController(streamIdList, ack); streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id()); mPorts[portIndex]->getDeletedStreamsSinceLastSync(*streamIdList); serviceStub->deleteStream(controller, streamIdList, ack, NewCallback(this, &PortGroup::processDeleteStreamAck, controller)); qDebug("applying 'new streams' ..."); streamIdList = new OstProto::StreamIdList; ack = new OstProto::Ack; controller = new PbRpcController(streamIdList, ack); streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id()); mPorts[portIndex]->getNewStreamsSinceLastSync(*streamIdList); serviceStub->addStream(controller, streamIdList, ack, NewCallback(this, &PortGroup::processAddStreamAck, controller)); qDebug("applying 'modified streams' ..."); streamConfigList = new OstProto::StreamConfigList; ack = new OstProto::Ack; controller = new PbRpcController(streamConfigList, ack); streamConfigList->mutable_port_id()->set_id(mPorts[portIndex]->id()); mPorts[portIndex]->getModifiedStreamsSinceLastSync(*streamConfigList); serviceStub->modifyStream(controller, streamConfigList, ack, NewCallback(this, &PortGroup::processModifyStreamAck, portIndex, controller)); } void PortGroup::processAddStreamAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::processDeleteStreamAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::processModifyStreamAck(int portIndex, PbRpcController *controller) { qDebug("In %s", __FUNCTION__); qDebug("apply completed"); mPorts[portIndex]->when_syncComplete(); mainWindow->setEnabled(true); QApplication::restoreOverrideCursor(); delete controller; } void PortGroup::modifyPort(int portIndex, OstProto::Port portConfig) { OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList; OstProto::Ack *ack = new OstProto::Ack; qDebug("%s: portIndex = %d", __FUNCTION__, portIndex); Q_ASSERT(portIndex < mPorts.size()); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); mainWindow->setDisabled(true); OstProto::Port *port = portConfigList->add_port(); port->CopyFrom(portConfig); port->mutable_port_id()->set_id(mPorts[portIndex]->id()); PbRpcController *controller = new PbRpcController(portConfigList, ack); serviceStub->modifyPort(controller, portConfigList, ack, NewCallback(this, &PortGroup::processModifyPortAck, controller)); } void PortGroup::processModifyPortAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _exit; } { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList; PbRpcController *controller2 = new PbRpcController(portIdList, portConfigList); OstProto::PortId *portId = portIdList->add_port_id(); portId->CopyFrom(static_cast (controller->request())->mutable_port(0)->port_id()); serviceStub->getPortConfig(controller, portIdList, portConfigList, NewCallback(this, &PortGroup::processUpdatedPortConfig, controller2)); } _exit: delete controller; } void PortGroup::processUpdatedPortConfig(PbRpcController *controller) { OstProto::PortConfigList *portConfigList = static_cast(controller->response()); qDebug("In %s", __FUNCTION__); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _exit; } if (portConfigList->port_size() != 1) qDebug("port size = %d (expected = 1)", portConfigList->port_size()); for(int i = 0; i < portConfigList->port_size(); i++) { uint id; id = portConfigList->port(i).port_id().id(); // FIXME: don't mix port id & index into mPorts[] mPorts[id]->updatePortConfig(portConfigList->mutable_port(i)); emit portGroupDataChanged(mPortGroupId, id); } _exit: mainWindow->setEnabled(true); QApplication::restoreOverrideCursor(); delete controller; } void PortGroup::getStreamIdList() { for (int portIndex = 0; portIndex < numPorts(); portIndex++) { OstProto::PortId *portId = new OstProto::PortId; OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList; PbRpcController *controller = new PbRpcController(portId, streamIdList); portId->set_id(mPorts[portIndex]->id()); serviceStub->getStreamIdList(controller, portId, streamIdList, NewCallback(this, &PortGroup::processStreamIdList, portIndex, controller)); } } void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller) { OstProto::StreamIdList *streamIdList = static_cast(controller->response()); qDebug("In %s (portIndex = %d)", __FUNCTION__, portIndex); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _exit; } Q_ASSERT(portIndex < numPorts()); if (streamIdList->port_id().id() != mPorts[portIndex]->id()) { qDebug("Invalid portId %d (expected %d) received for portIndex %d", streamIdList->port_id().id(), mPorts[portIndex]->id(), portIndex); goto _exit; } for(int i = 0; i < streamIdList->stream_id_size(); i++) { uint streamId; streamId = streamIdList->stream_id(i).id(); mPorts[portIndex]->insertStream(streamId); } mPorts[portIndex]->when_syncComplete(); // Are we done for all ports? if (numPorts() && portIndex >= (numPorts()-1)) { // FIXME(HI): some way to reset streammodel getStreamConfigList(); } _exit: delete controller; } void PortGroup::getStreamConfigList() { qDebug("requesting stream config list ..."); for (int portIndex = 0; portIndex < numPorts(); portIndex++) { OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList; OstProto::StreamConfigList *streamConfigList = new OstProto::StreamConfigList; PbRpcController *controller = new PbRpcController( streamIdList, streamConfigList); streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id()); for (int j = 0; j < mPorts[portIndex]->numStreams(); j++) { OstProto::StreamId *s = streamIdList->add_stream_id(); s->set_id(mPorts[portIndex]->streamByIndex(j)->id()); } serviceStub->getStreamConfig(controller, streamIdList, streamConfigList, NewCallback(this, &PortGroup::processStreamConfigList, portIndex, controller)); } } void PortGroup::processStreamConfigList(int portIndex, PbRpcController *controller) { OstProto::StreamConfigList *streamConfigList = static_cast(controller->response()); qDebug("In %s", __PRETTY_FUNCTION__); Q_ASSERT(portIndex < numPorts()); if (controller->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _exit; } Q_ASSERT(portIndex < numPorts()); if (streamConfigList->port_id().id() != mPorts[portIndex]->id()) { qDebug("Invalid portId %d (expected %d) received for portIndex %d", streamConfigList->port_id().id(), mPorts[portIndex]->id(), portIndex); goto _exit; } for(int i = 0; i < streamConfigList->stream_size(); i++) { uint streamId; streamId = streamConfigList->stream(i).stream_id().id(); mPorts[portIndex]->updateStream(streamId, streamConfigList->mutable_stream(i)); } // Are we done for all ports? if (portIndex >= numPorts()) { // FIXME(HI): some way to reset streammodel } _exit: delete controller; } void PortGroup::startTx(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) goto _exit; if (portList == NULL) goto _exit; { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::Ack *ack = new OstProto::Ack; PbRpcController *controller = new PbRpcController(portIdList, ack); for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = portIdList->add_port_id(); portId->set_id(portList->at(i)); } serviceStub->startTx(controller, portIdList, ack, NewCallback(this, &PortGroup::processStartTxAck, controller)); } _exit: return; } void PortGroup::processStartTxAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::stopTx(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) goto _exit; if ((portList == NULL) || (portList->size() == 0)) goto _exit; { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::Ack *ack = new OstProto::Ack; PbRpcController *controller = new PbRpcController(portIdList, ack); for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = portIdList->add_port_id(); portId->set_id(portList->at(i)); } serviceStub->stopTx(controller, portIdList, ack, NewCallback(this, &PortGroup::processStopTxAck, controller)); } _exit: return; } void PortGroup::processStopTxAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::startCapture(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) return; if ((portList == NULL) || (portList->size() == 0)) goto _exit; { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::Ack *ack = new OstProto::Ack; PbRpcController *controller = new PbRpcController(portIdList, ack); for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = portIdList->add_port_id(); portId->set_id(portList->at(i)); } serviceStub->startCapture(controller, portIdList, ack, NewCallback(this, &PortGroup::processStartCaptureAck, controller)); } _exit: return; } void PortGroup::processStartCaptureAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::stopCapture(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) return; if ((portList == NULL) || (portList->size() == 0)) goto _exit; { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::Ack *ack = new OstProto::Ack; PbRpcController *controller = new PbRpcController(portIdList, ack); for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = portIdList->add_port_id(); portId->set_id(portList->at(i)); } serviceStub->stopCapture(controller, portIdList, ack, NewCallback(this, &PortGroup::processStopCaptureAck, controller)); } _exit: return; } void PortGroup::processStopCaptureAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); delete controller; } void PortGroup::viewCapture(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) goto _exit; if ((portList == NULL) || (portList->size() != 1)) goto _exit; for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = new OstProto::PortId; OstProto::CaptureBuffer *buf = new OstProto::CaptureBuffer; PbRpcController *controller = new PbRpcController(portId, buf); QFile *capFile = mPorts[portList->at(i)]->getCaptureFile(); portId->set_id(portList->at(i)); capFile->open(QIODevice::ReadWrite|QIODevice::Truncate); qDebug("Temp CapFile = %s", capFile->fileName().toAscii().constData()); controller->setBinaryBlob(capFile); serviceStub->getCaptureBuffer(controller, portId, buf, NewCallback(this, &PortGroup::processViewCaptureAck, controller)); } _exit: return; } void PortGroup::processViewCaptureAck(PbRpcController *controller) { QFile *capFile = static_cast(controller->binaryBlob()); QString viewer = appSettings->value(kWiresharkPathKey, kWiresharkPathDefaultValue).toString(); qDebug("In %s", __FUNCTION__); capFile->flush(); capFile->close(); if (!QFile::exists(viewer)) { QMessageBox::warning(NULL, "Can't find Wireshark", viewer + QString(" does not exist!\n\nPlease correct the path" " to Wireshark in the Preferences.")); goto _exit; } if (!QProcess::startDetached(viewer, QStringList() << capFile->fileName())) qDebug("Failed starting Wireshark"); _exit: delete controller; } void PortGroup::getPortStats() { //qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) goto _exit; if (numPorts() <= 0) goto _exit; if (isGetStatsPending_) goto _exit; statsController->Reset(); isGetStatsPending_ = true; serviceStub->getStats(statsController, static_cast(statsController->request()), static_cast(statsController->response()), NewCallback(this, &PortGroup::processPortStatsList)); _exit: return; } void PortGroup::processPortStatsList() { //qDebug("In %s", __FUNCTION__); if (statsController->Failed()) { qDebug("%s: rpc failed", __FUNCTION__); goto _error_exit; } for(int i = 0; i < portStatsList_->port_stats_size(); i++) { uint id = portStatsList_->port_stats(i).port_id().id(); // FIXME: don't mix port id & index into mPorts[] mPorts[id]->updateStats(portStatsList_->mutable_port_stats(i)); } emit statsChanged(mPortGroupId); _error_exit: isGetStatsPending_ = false; } void PortGroup::clearPortStats(QList *portList) { qDebug("In %s", __FUNCTION__); if (state() != QAbstractSocket::ConnectedState) goto _exit; { OstProto::PortIdList *portIdList = new OstProto::PortIdList; OstProto::Ack *ack = new OstProto::Ack; PbRpcController *controller = new PbRpcController(portIdList, ack); if (portList == NULL) portIdList->CopyFrom(*portIdList_); else { for (int i = 0; i < portList->size(); i++) { OstProto::PortId *portId = portIdList->add_port_id(); portId->set_id(portList->at(i)); } } serviceStub->clearStats(controller, portIdList, ack, NewCallback(this, &PortGroup::processClearStatsAck, controller)); } _exit: return; } void PortGroup::processClearStatsAck(PbRpcController *controller) { qDebug("In %s", __FUNCTION__); // Refresh stats immediately after a stats clear/reset getPortStats(); delete controller; } ostinato-0.5.1/client/portgroup.h0000700000175300010010000001124012005505614016356 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_GROUP_H #define _PORT_GROUP_H #include "port.h" #include #include #include "../common/protocol.pb.h" #include "pbrpcchannel.h" /* TODO HIGH MED LOW - Allow hostnames in addition to IP Address as "server address" */ #define DEFAULT_SERVER_PORT 7878 class QFile; class QTimer; class PortGroup : public QObject { Q_OBJECT private: static quint32 mPortGroupAllocId; quint32 mPortGroupId; QString mUserAlias; // user defined bool reconnect; int reconnectAfter; // time in milliseconds static const int kMinReconnectWaitTime = 2000; // ms static const int kMaxReconnectWaitTime = 60000; // ms QTimer *reconnectTimer; PbRpcChannel *rpcChannel; PbRpcController *statsController; bool isGetStatsPending_; OstProto::OstService::Stub *serviceStub; OstProto::PortIdList *portIdList_; OstProto::PortStatsList *portStatsList_; public: // FIXME(HIGH): member access QList mPorts; public: PortGroup(QHostAddress ip = QHostAddress::LocalHost, quint16 port = DEFAULT_SERVER_PORT); ~PortGroup(); void connectToHost() { reconnect = true; rpcChannel->establish(); } void connectToHost(QHostAddress ip, quint16 port) { reconnect = true; rpcChannel->establish(ip, port); } void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); } int numPorts() const { return mPorts.size(); } quint32 id() const { return mPortGroupId; } const QString& userAlias() const { return mUserAlias; } void setUserAlias(QString alias) { mUserAlias = alias; }; const QHostAddress& serverAddress() const { return rpcChannel->serverAddress(); } quint16 serverPort() const { return rpcChannel->serverPort(); } QAbstractSocket::SocketState state() const { return rpcChannel->state(); } void processPortIdList(PbRpcController *controller); void processPortConfigList(PbRpcController *controller); void processAddStreamAck(PbRpcController *controller); void processDeleteStreamAck(PbRpcController *controller); void processModifyStreamAck(int portIndex, PbRpcController *controller); void modifyPort(int portId, OstProto::Port portConfig); void processModifyPortAck(PbRpcController *controller); void processUpdatedPortConfig(PbRpcController *controller); void getStreamIdList(); void processStreamIdList(int portIndex, PbRpcController *controller); void getStreamConfigList(); void processStreamConfigList(int portIndex, PbRpcController *controller); void processModifyStreamAck(OstProto::Ack *ack); void startTx(QList *portList = NULL); void processStartTxAck(PbRpcController *controller); void stopTx(QList *portList = NULL); void processStopTxAck(PbRpcController *controller); void startCapture(QList *portList = NULL); void processStartCaptureAck(PbRpcController *controller); void stopCapture(QList *portList = NULL); void processStopCaptureAck(PbRpcController *controller); void viewCapture(QList *portList = NULL); void processViewCaptureAck(PbRpcController *controller); void getPortStats(); void processPortStatsList(); void clearPortStats(QList *portList = NULL); void processClearStatsAck(PbRpcController *controller); signals: void portGroupDataChanged(int portGroupId, int portId = 0xFFFF); void portListAboutToBeChanged(quint32 portGroupId); void portListChanged(quint32 portGroupId); void statsChanged(quint32 portGroupId); private slots: void on_reconnectTimer_timeout(); void on_rpcChannel_stateChanged(QAbstractSocket::SocketState state); void on_rpcChannel_connected(); void on_rpcChannel_disconnected(); void on_rpcChannel_error(QAbstractSocket::SocketError socketError); void when_portListChanged(quint32 portGroupId); public slots: void when_configApply(int portIndex); }; #endif ostinato-0.5.1/client/portgrouplist.cpp0000700000175300010010000000717612005505614017622 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portgrouplist.h" // TODO(LOW): Remove #include PortGroupList::PortGroupList() : mPortGroupListModel(this), mStreamListModel(this), mPortStatsModel(this, this) { PortGroup *pg; #ifdef QT_NO_DEBUG streamModelTester_ = NULL; portModelTester_ = NULL; portStatsModelTester_ = NULL; #else streamModelTester_ = new ModelTest(getStreamModel()); portModelTester_ = new ModelTest(getPortModel()); portStatsModelTester_ = new ModelTest(getPortStatsModel()); #endif // Add the "Local" Port Group pg = new PortGroup; addPortGroup(*pg); } PortGroupList::~PortGroupList() { delete portStatsModelTester_; delete portModelTester_; delete streamModelTester_; while (!mPortGroups.isEmpty()) delete mPortGroups.takeFirst(); } 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) { Q_ASSERT(mPortGroupListModel.isPortGroup(index)); return *(mPortGroups[index.row()]); } Port& PortGroupList::port(const QModelIndex& index) { Q_ASSERT(mPortGroupListModel.isPort(index)); return (*mPortGroups.at(index.parent().row())->mPorts[index.row()]); } void PortGroupList::addPortGroup(PortGroup &portGroup) { mPortGroupListModel.portGroupAboutToBeAppended(); connect(&portGroup, SIGNAL(portGroupDataChanged(int, int)), &mPortGroupListModel, SLOT(when_portGroupDataChanged(int, int))); #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())); connect(&portGroup, SIGNAL(statsChanged(quint32)), &mPortStatsModel, SLOT(when_portGroup_stats_update(quint32))); 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; } ostinato-0.5.1/client/portgrouplist.h0000700000175300010010000000404412005505614017256 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #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; QObject *streamModelTester_; QObject *portModelTester_; QObject *portStatsModelTester_; // 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); int numPortGroups() { return mPortGroups.size(); } PortGroup& portGroupByIndex(int index) { return *(mPortGroups[index]); } void addPortGroup(PortGroup &portGroup); void removePortGroup(PortGroup &portGroup); private: int indexOfPortGroup(quint32 portGroupId); }; #endif ostinato-0.5.1/client/portmodel.cpp0000700000175300010010000002202012005505614016653 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portmodel.h" #include "portgrouplist.h" #include #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; portIconFactory[OstProto::LinkStateUnknown][false] = QIcon(":/icons/bullet_white.png"); portIconFactory[OstProto::LinkStateDown][false] = QIcon(":/icons/bullet_red.png"); portIconFactory[OstProto::LinkStateUp][false] = QIcon(":/icons/bullet_green.png"); for (int linkState = 0; linkState < kLinkStatesCount; linkState++) { QPixmap pixmap(":/icons/deco_exclusive.png"); QPainter painter(&pixmap); QIcon icon = portIconFactory[linkState][false]; painter.drawPixmap(0, 0, icon.pixmap(QSize(32,32))); portIconFactory[linkState][true] = QIcon(pixmap); } } 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 { if (pgl->mPortGroups.at(parent.row())->numPorts() == 0) { DBG0("Exit PortModel data 4\n"); return QVariant(); } Port *port = pgl->mPortGroups.at(parent.row())->mPorts[index.row()]; // Non Top Level - Port if ((role == Qt::DisplayRole)) { // FIXME(LOW) - IP Address below return QString("Port %1: %2 [%3] (%4)") .arg(port->id()) .arg(port->name()) .arg(QHostAddress("0.0.0.0").toString()) .arg(port->description()); } else if ((role == Qt::DecorationRole)) { return portIconFactory[port->linkState()][port->hasExclusiveControl()]; } else { DBG0("Exit PortModel data 6\n"); return QVariant(); } } 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.isValid() && ((index.internalId() & 0xFFFF) == 0xFFFF)) return true; else return false; } bool PortModel::isPort(const QModelIndex& index) { if (index.isValid() && ((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(int portGroupId, int portId) { QModelIndex index; int row; qDebug("portGroupId = %d, portId = %d", portGroupId, portId); if (portId == 0xFFFF) row = pgl->indexOfPortGroup(portGroupId); else row = portId; index = createIndex(row, 0, (portGroupId << 16) | portId); 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(); } void PortModel::when_portListChanged() { reset(); } ostinato-0.5.1/client/portmodel.h0000700000175300010010000000431412005505614016326 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_MODEL_H #define _PORT_MODEL_H #include #include class PortGroupList; class PortGroup; class PortModel : public QAbstractItemModel { Q_OBJECT friend class PortGroupList; 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: PortGroupList *pgl; static const int kLinkStatesCount = 3; static const int kExclusiveStatesCount = 2; QIcon portIconFactory[kLinkStatesCount][kExclusiveStatesCount]; private slots: void when_portGroupDataChanged(int portGroupId, int portId); void portGroupAboutToBeAppended(); void portGroupAppended(); void portGroupAboutToBeRemoved(PortGroup *portGroup); void portGroupRemoved(); void when_portListChanged(); #if 0 void triggerLayoutAboutToBeChanged(); void triggerLayoutChanged(); #endif }; #endif ostinato-0.5.1/client/portstatsfilter.ui0000700000175300010010000001057112005505614017762 0ustar srivatspNone PortStatsFilterDialog 0 0 319 193 Select Ports :/icons/portstats_filter.png false false QAbstractItemView::NoDragDrop QAbstractItemView::ExtendedSelection QListView::Static Qt::Vertical 20 40 > :/icons/arrow_right.png < :/icons/arrow_left.png Qt::Vertical 20 40 true true false QAbstractItemView::InternalMove QAbstractItemView::ExtendedSelection QListView::Free Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok lvUnselected tbSelectIn tbSelectOut lvSelected buttonBox buttonBox accepted() PortStatsFilterDialog accept() 248 254 157 274 buttonBox rejected() PortStatsFilterDialog reject() 316 260 286 274 ostinato-0.5.1/client/portstatsfilterdialog.cpp0000700000175300010010000000722512005505614021311 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portstatsfilterdialog.h" PortStatsFilterDialog::PortStatsFilterDialog(QWidget *parent) : QDialog(parent) { setupUi(this); mUnselected.setSortRole(PositionRole); lvUnselected->setModel(&mUnselected); lvSelected->setModel(&mSelected); } QList PortStatsFilterDialog::getItemList(bool* ok, QAbstractItemModel *model, Qt::Orientation orientation, QList initial) { QList ret; uint count = (orientation == Qt::Vertical) ? model->rowCount() : model->columnCount(); *ok = false; mUnselected.clear(); mSelected.clear(); for (uint i = 0; i < count; i++) { QStandardItem *item; item = new QStandardItem(model->headerData(i, orientation).toString()); item->setData(i, PositionRole); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled //| Qt::ItemIsDropEnabled | Qt::ItemIsEnabled); if (initial.contains(i)) mSelected.appendRow(item); else mUnselected.appendRow(item); } // No need to sort right now 'coz we have inserted items in order if (exec() == QDialog::Accepted) { uint count = mSelected.rowCount(); for (uint i = 0; i < count; i++) { QModelIndex index = mSelected.index(i, 0, QModelIndex()); QStandardItem *item = mSelected.itemFromIndex(index); ret.append(item->data(PositionRole).toInt()); } *ok = true; } return ret; } void PortStatsFilterDialog::on_tbSelectIn_clicked() { QList rows; foreach(QModelIndex idx, lvUnselected->selectionModel()->selectedIndexes()) rows.append(idx.row()); qSort(rows.begin(), rows.end(), qGreater()); QModelIndex idx = lvSelected->selectionModel()->currentIndex(); int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount(); foreach(int row, rows) { QList items = mUnselected.takeRow(row); mSelected.insertRow(insertAt, items); } } void PortStatsFilterDialog::on_tbSelectOut_clicked() { QList rows; foreach(QModelIndex idx, lvSelected->selectionModel()->selectedIndexes()) rows.append(idx.row()); qSort(rows.begin(), rows.end(), qGreater()); foreach(int row, rows) { QList items = mSelected.takeRow(row); mUnselected.appendRow(items); } mUnselected.sort(0); } void PortStatsFilterDialog::on_lvUnselected_doubleClicked(const QModelIndex &index) { QList items = mUnselected.takeRow(index.row()); QModelIndex idx = lvSelected->selectionModel()->currentIndex(); int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount(); mSelected.insertRow(insertAt, items); } void PortStatsFilterDialog::on_lvSelected_doubleClicked(const QModelIndex &index) { QList items = mSelected.takeRow(index.row()); mUnselected.appendRow(items); mUnselected.sort(0); } ostinato-0.5.1/client/portstatsfilterdialog.h0000700000175300010010000000305512005505614020753 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_STATS_FILTER_DIALOG_H #define _PORT_STATS_FILTER_DIALOG_H #include #include #include #include "ui_portstatsfilter.h" #include "portgrouplist.h" class PortStatsFilterDialog : public QDialog, public Ui::PortStatsFilterDialog { Q_OBJECT public: PortStatsFilterDialog(QWidget *parent = 0); QList getItemList(bool* ok, QAbstractItemModel *model, Qt::Orientation orientation = Qt::Vertical, QList initial = QList()); private: enum ItemRole { PositionRole = Qt::UserRole + 1 }; QStandardItemModel mUnselected; QStandardItemModel mSelected; private slots: void on_tbSelectIn_clicked(); void on_tbSelectOut_clicked(); void on_lvUnselected_doubleClicked(const QModelIndex &index); void on_lvSelected_doubleClicked(const QModelIndex &index); }; #endif ostinato-0.5.1/client/portstatsmodel.cpp0000700000175300010010000002050712005505614017742 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portstatsmodel.h" #include "portgrouplist.h" #include PortStatsModel::PortStatsModel(PortGroupList *p, QObject *parent) : QAbstractTableModel(parent) { pgl = p; timer = new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(updateStats())); timer->start(1000); } PortStatsModel::~PortStatsModel() { timer->stop(); delete timer; } 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(); } void PortStatsModel::getDomainIndexes(const QModelIndex &index, uint &portGroupIdx, uint &portIdx) const { int portNum; // TODO(LOW): Optimize using binary search: see qLowerBound() portNum = index.column() + 1; for (portGroupIdx = 0; portGroupIdx < (uint) numPorts.size(); portGroupIdx++) if (portNum <= numPorts.at(portGroupIdx)) break; if (portGroupIdx) { if (numPorts.at(portGroupIdx -1)) portIdx = (portNum - 1) % numPorts.at(portGroupIdx - 1); else portIdx = portNum - 1; } else portIdx = portNum - 1; //qDebug("PSM: %d - %d, %d", index.column(), portGroupIdx, portIdx); } QVariant PortStatsModel::data(const QModelIndex &index, int role) const { uint pgidx, pidx; int row; // Check for a valid index if (!index.isValid()) return QVariant(); // Check for row/column limits row = index.row(); if (row >= e_STAT_MAX) return QVariant(); if (numPorts.isEmpty()) return QVariant(); if (index.column() >= (numPorts.last())) return QVariant(); getDomainIndexes(index, pgidx, pidx); // Check role if (role == Qt::DisplayRole) { OstProto::PortStats stats; stats = pgl->mPortGroups.at(pgidx)->mPorts[pidx]->getStats(); switch(row) { // States case e_LINK_STATE: return LinkStateName.at(stats.state().link_state()); case e_TRANSMIT_STATE: return BoolStateName.at(stats.state().is_transmit_on()); case e_CAPTURE_STATE: return BoolStateName.at(stats.state().is_capture_on()); // Statistics case e_STAT_FRAMES_RCVD: return quint64(stats.rx_pkts()); case e_STAT_FRAMES_SENT: return quint64(stats.tx_pkts()); case e_STAT_FRAME_SEND_RATE: return quint64(stats.tx_pps()); case e_STAT_FRAME_RECV_RATE: return quint64(stats.rx_pps()); case e_STAT_BYTES_RCVD: return quint64(stats.rx_bytes()); case e_STAT_BYTES_SENT: return quint64(stats.tx_bytes()); case e_STAT_BYTE_SEND_RATE: return quint64(stats.tx_bps()); case e_STAT_BYTE_RECV_RATE: return quint64(stats.rx_bps()); #if 0 case e_STAT_FRAMES_RCVD_NIC: return stats.rx_pkts_nic(); case e_STAT_FRAMES_SENT_NIC: return stats.tx_pkts_nic(); case e_STAT_BYTES_RCVD_NIC: return stats.rx_bytes_nic(); case e_STAT_BYTES_SENT_NIC: return stats.tx_bytes_nic(); #endif case e_STAT_RX_DROPS : return quint64(stats.rx_drops()); case e_STAT_RX_ERRORS: return quint64(stats.rx_errors()); case e_STAT_RX_FIFO_ERRORS: return quint64(stats.rx_fifo_errors()); case e_STAT_RX_FRAME_ERRORS: return quint64(stats.rx_frame_errors()); default: qWarning("%s: Unhandled stats id %d\n", __FUNCTION__, index.row()); return 0; } } else if (role == Qt::TextAlignmentRole) { if (row >= e_STATE_START && row <= e_STATE_END) return Qt::AlignHCenter; else if (row >= e_STATISTICS_START && row <= e_STATISTICS_END) return Qt::AlignRight; else return QVariant(); } else return QVariant(); } QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::ToolTipRole) { if (orientation == Qt::Horizontal) { QString notes; uint portGroupIdx, portIdx; getDomainIndexes(index(0, section), portGroupIdx, portIdx); notes = pgl->mPortGroups.at(portGroupIdx)->mPorts[portIdx]->notes(); if (!notes.isEmpty()) return notes; else return QVariant(); } else return QVariant(); } if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { uint portGroupIdx, portIdx; QString portName; getDomainIndexes(index(0, section), portGroupIdx, portIdx); portName = QString("Port %1-%2").arg(portGroupIdx).arg(portIdx); if (portGroupIdx < (uint) pgl->mPortGroups.size() && portIdx < (uint) pgl->mPortGroups.at(portGroupIdx)->mPorts.size()) { if (!pgl->mPortGroups.at(portGroupIdx)->mPorts[portIdx]->notes() .isEmpty()) portName += " *"; } return portName; } else return PortStatName.at(section); } void PortStatsModel::portListFromIndex(QModelIndexList indices, QList &portList) { int i, j; QModelIndexList selectedCols(indices); portList.clear(); //selectedCols = indices.selectedColumns(); for (i = 0; i < selectedCols.size(); i++) { uint portGroupIdx, portIdx; getDomainIndexes(selectedCols.at(i), portGroupIdx, portIdx); for (j = 0; j < portList.size(); j++) { if (portList[j].portGroupId == portGroupIdx) break; } if (j >= portList.size()) { // PortGroup Not found PortGroupAndPortList p; p.portGroupId = portGroupIdx; p.portList.append(portIdx); portList.append(p); } else { // PortGroup found portList[j].portList.append(portIdx); } } } // // 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*/) { QModelIndex topLeft = index(port, 0, QModelIndex()); QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex()); emit dataChanged(topLeft, bottomRight); } void PortStatsModel::updateStats() { // Request each portgroup to fetch updated stats - the port group // raises a signal once updated stats are available for (int i = 0; i < pgl->mPortGroups.size(); i++) pgl->mPortGroups[i]->getPortStats(); } void PortStatsModel::when_portGroup_stats_update(quint32 /*portGroupId*/) { // FIXME(MED): update only the changed ports, not all QModelIndex topLeft = index(0, 0, QModelIndex()); QModelIndex bottomRight = index(rowCount(), columnCount(), QModelIndex()); emit dataChanged(topLeft, bottomRight); } ostinato-0.5.1/client/portstatsmodel.h0000700000175300010010000000716112005505614017410 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_STATS_MODEL_H #define _PORT_STATS_MODEL_H #include #include class QTimer; typedef enum { // State e_STATE_START = 0, e_LINK_STATE = e_STATE_START, e_TRANSMIT_STATE, e_CAPTURE_STATE, e_STATE_END = e_CAPTURE_STATE, // Statistics e_STATISTICS_START, e_STAT_FRAMES_RCVD = e_STATISTICS_START, 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, #if 0 e_STAT_FRAMES_RCVD_NIC, e_STAT_FRAMES_SENT_NIC, e_STAT_BYTES_RCVD_NIC, e_STAT_BYTES_SENT_NIC, #endif // Rx Errors e_STAT_RX_DROPS, e_STAT_RX_ERRORS, e_STAT_RX_FIFO_ERRORS, e_STAT_RX_FRAME_ERRORS, e_STATISTICS_END = e_STAT_RX_FRAME_ERRORS, e_STAT_MAX } PortStat; static QStringList PortStatName = (QStringList() << "Link State" << "Transmit State" << "Capture State" << "Frames Received" << "Frames Sent" << "Frame Send Rate (fps)" << "Frame Receive Rate (fps)" << "Bytes Received" << "Bytes Sent" << "Byte Send Rate (Bps)" << "Byte Receive Rate (Bps)" #if 0 << "Frames Received (NIC)" << "Frames Sent (NIC)" << "Bytes Received (NIC)" << "Bytes Sent (NIC)" #endif << "Receive Drops" << "Receive Errors" << "Receive Fifo Errors" << "Receive Frame Errors" ); static QStringList LinkStateName = (QStringList() << "Unknown" << "Down" << "Up" ); static QStringList BoolStateName = (QStringList() << "Off" << "On" ); class PortGroupList; class PortStatsModel : public QAbstractTableModel { Q_OBJECT public: PortStatsModel(PortGroupList *p, QObject *parent = 0); ~PortStatsModel(); 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; class PortGroupAndPortList { public: uint portGroupId; QList portList; }; void portListFromIndex(QModelIndexList indices, QList &portList); public slots: void when_portListChanged(); void on_portStatsUpdate(int port, void*stats); void when_portGroup_stats_update(quint32 portGroupId); private slots: void updateStats(); private: PortGroupList *pgl; // 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; QTimer *timer; void getDomainIndexes(const QModelIndex &index, uint &portGroupIdx, uint &portIdx) const; }; #endif ostinato-0.5.1/client/portstatswindow.cpp0000700000175300010010000001161412005505614020150 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portstatswindow.h" #include "portstatsmodel.h" #include "portstatsfilterdialog.h" #include "QHeaderView" PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent) : QWidget(parent) { setupUi(this); this->pgl = pgl; model = pgl->getPortStatsModel(); tvPortStats->setModel(model); tvPortStats->verticalHeader()->setHighlightSections(false); tvPortStats->verticalHeader()->setDefaultSectionSize( tvPortStats->verticalHeader()->minimumSectionSize()); } PortStatsWindow::~PortStatsWindow() { } /* ------------- SLOTS -------------- */ void PortStatsWindow::on_tbStartTransmit_clicked() { QList pgpl; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), pgpl); // Clear selected ports, portgroup by portgroup for (int i = 0; i < pgpl.size(); i++) { pgl->portGroupByIndex(pgpl.at(i).portGroupId). startTx(&pgpl[i].portList); } } void PortStatsWindow::on_tbStopTransmit_clicked() { QList pgpl; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), pgpl); // Clear selected ports, portgroup by portgroup for (int i = 0; i < pgpl.size(); i++) { pgl->portGroupByIndex(pgpl.at(i).portGroupId). stopTx(&pgpl[i].portList); } } void PortStatsWindow::on_tbStartCapture_clicked() { // TODO(MED) QList pgpl; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), pgpl); // Clear selected ports, portgroup by portgroup for (int i = 0; i < pgpl.size(); i++) { pgl->portGroupByIndex(pgpl.at(i).portGroupId). startCapture(&pgpl[i].portList); } } void PortStatsWindow::on_tbStopCapture_clicked() { // TODO(MED) QList pgpl; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), pgpl); // Clear selected ports, portgroup by portgroup for (int i = 0; i < pgpl.size(); i++) { pgl->portGroupByIndex(pgpl.at(i).portGroupId). stopCapture(&pgpl[i].portList); } } void PortStatsWindow::on_tbViewCapture_clicked() { // TODO(MED) QList pgpl; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), pgpl); // Clear selected ports, portgroup by portgroup for (int i = 0; i < pgpl.size(); i++) { pgl->portGroupByIndex(pgpl.at(i).portGroupId). viewCapture(&pgpl[i].portList); } } void PortStatsWindow::on_tbClear_clicked() { QList portList; // Get selected ports model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(), portList); // Clear selected ports, portgroup by portgroup for (int i = 0; i < portList.size(); i++) { pgl->portGroupByIndex(portList.at(i).portGroupId). clearPortStats(&portList[i].portList); } } void PortStatsWindow::on_tbClearAll_clicked() { for (int i = 0; i < pgl->numPortGroups(); i++) { pgl->portGroupByIndex(0).clearPortStats(); } } void PortStatsWindow::on_tbFilter_clicked() { bool ok; QList currentColumns, newColumns; PortStatsFilterDialog dialog; for(int i = 0; i < model->columnCount(); i++) if (!tvPortStats->isColumnHidden(i)) currentColumns.append(i); newColumns = dialog.getItemList(&ok, model, Qt::Horizontal, currentColumns); if (ok) { // hide/show sections first ... for(int i = 0; i < model->columnCount(); i++) tvPortStats->setColumnHidden(i, !newColumns.contains(i)); // ... then for the 'shown' columns, set the visual index for(int i = 0; i < newColumns.size(); i++) { tvPortStats->horizontalHeader()->moveSection(tvPortStats-> horizontalHeader()->visualIndex(newColumns.at(i)), i); } } } ostinato-0.5.1/client/portstatswindow.h0000700000175300010010000000263712005505614017622 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORT_STATS_WINDOW_H #define _PORT_STATS_WINDOW_H #include #include #include "ui_portstatswindow.h" #include "portgrouplist.h" #include "portstatsmodel.h" class PortStatsWindow : public QWidget, public Ui::PortStatsWindow { Q_OBJECT public: PortStatsWindow(PortGroupList *pgl, QWidget *parent = 0); ~PortStatsWindow(); private: PortGroupList *pgl; PortStatsModel *model; private slots: void on_tbStartTransmit_clicked(); void on_tbStopTransmit_clicked(); void on_tbStartCapture_clicked(); void on_tbStopCapture_clicked(); void on_tbViewCapture_clicked(); void on_tbClear_clicked(); void on_tbClearAll_clicked(); void on_tbFilter_clicked(); }; #endif ostinato-0.5.1/client/portstatswindow.ui0000700000175300010010000001260512005505614020004 0ustar srivatspNone PortStatsWindow 0 0 502 415 Form QFrame::Panel QFrame::Raised Start Tx Starts transmit on selected port(s) Start Transmit :/icons/control_play.png Stop Tx Stops transmit on selected port(s) Stop Trasmit :/icons/control_stop.png Clear Selected Port Stats Clears statistics of the selected port(s) Clear :/icons/portstats_clear.png Clear All Ports Stats Clears statistics of all ports Clear All :/icons/portstats_clear_all.png Start Capture Captures packets on the selected port(s) Start Capture :/icons/sound_none.png Stop Capture End capture on selecteed port(s) Stop Capture :/icons/sound_mute.png View Capture Buffer View captured packets on selected port(s) View Capture :/icons/magnifier.png Qt::Vertical Qt::Horizontal 40 20 Select which ports to view Filter :/icons/portstats_filter.png ostinato-0.5.1/client/portswindow.cpp0000700000175300010010000005020412005505614017252 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portswindow.h" #include "abstractfileformat.h" #include "portconfigdialog.h" #include "streamconfigdialog.h" #include "streamlistdelegate.h" #include #include #include #include PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) : QWidget(parent) { QAction *sep; delegate = new StreamListDelegate; //slm = new StreamListModel(); //plm = new PortGroupList(); plm = pgl; setupUi(this); tvPortList->header()->hide(); tvStreamList->setItemDelegate(delegate); tvStreamList->verticalHeader()->setDefaultSectionSize( tvStreamList->verticalHeader()->minimumSectionSize()); // Populate PortList Context Menu Actions tvPortList->addAction(actionNew_Port_Group); tvPortList->addAction(actionDelete_Port_Group); tvPortList->addAction(actionConnect_Port_Group); tvPortList->addAction(actionDisconnect_Port_Group); tvPortList->addAction(actionExclusive_Control); tvPortList->addAction(actionPort_Configuration); // Populate StramList Context Menu Actions tvStreamList->addAction(actionNew_Stream); tvStreamList->addAction(actionEdit_Stream); tvStreamList->addAction(actionDelete_Stream); sep = new QAction(this); sep->setSeparator(true); tvStreamList->addAction(sep); tvStreamList->addAction(actionOpen_Streams); tvStreamList->addAction(actionSave_Streams); // PortList and StreamList actions combined make this window's actions addActions(tvPortList->actions()); sep = new QAction(this); sep->setSeparator(true); addAction(sep); addActions(tvStreamList->actions()); 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(plm->getPortModel(), SIGNAL(modelReset()), SLOT(when_portModel_reset())); connect( tvPortList->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(when_portView_currentChanged(const QModelIndex&, const QModelIndex&))); connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(updateStreamViewActions())); connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(updateStreamViewActions())); connect(tvStreamList->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), SLOT(updateStreamViewActions())); connect(tvStreamList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(updateStreamViewActions())); tvStreamList->resizeColumnToContents(StreamModel::StreamIcon); tvStreamList->resizeColumnToContents(StreamModel::StreamStatus); // Initially we don't have any ports/streams - so send signal triggers when_portView_currentChanged(QModelIndex(), QModelIndex()); updateStreamViewActions(); connect(plm->getStreamModel(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(streamModelDataChanged())); connect(plm->getStreamModel(), SIGNAL(modelReset()), this, SLOT(streamModelDataChanged())); } void PortsWindow::streamModelDataChanged() { if (plm->isPort(tvPortList->currentIndex())) plm->port(tvPortList->currentIndex()).recalculateAverageRates(); } PortsWindow::~PortsWindow() { delete delegate; } void PortsWindow::on_tvStreamList_activated(const QModelIndex & index) { StreamConfigDialog *scd; int ret; if (!index.isValid()) { qDebug("%s: invalid index", __FUNCTION__); return; } scd = new StreamConfigDialog(plm->port(tvPortList->currentIndex()), index.row(), this); qDebug("stream list activated\n"); ret = scd->exec(); if (ret == QDialog::Accepted) plm->port(tvPortList->currentIndex()).recalculateAverageRates(); delete scd; } void PortsWindow::when_portView_currentChanged(const QModelIndex& current, const QModelIndex& previous) { plm->getStreamModel()->setCurrentPortIndex(current); updatePortViewActions(current); updateStreamViewActions(); qDebug("In %s", __FUNCTION__); if (previous.isValid() && plm->isPort(previous)) { disconnect(&(plm->port(previous)), SIGNAL(portRateChanged(int, int)), this, SLOT(updatePortRates())); } 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 updatePortRates(); connect(&(plm->port(current)), SIGNAL(portRateChanged(int, int)), SLOT(updatePortRates())); } } } void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { qDebug("In %s", __FUNCTION__); #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))) { // Update UI to reflect potential change in exclusive mode, // transmit mode et al when_portView_currentChanged(tvPortList->currentIndex(), tvPortList->currentIndex()); } } void PortsWindow::when_portModel_reset() { when_portView_currentChanged(QModelIndex(), tvPortList->currentIndex()); } void PortsWindow::on_averagePacketsPerSec_editingFinished() { QModelIndex current = tvPortList->currentIndex(); Q_ASSERT(plm->isPort(current)); bool isOk; double pps = QLocale().toDouble(averagePacketsPerSec->text(), &isOk); plm->port(current).setAveragePacketRate(pps); } void PortsWindow::on_averageBitsPerSec_editingFinished() { QModelIndex current = tvPortList->currentIndex(); Q_ASSERT(plm->isPort(current)); bool isOk; double bps = QLocale().toDouble(averageBitsPerSec->text(), &isOk); plm->port(current).setAverageBitRate(bps); } void PortsWindow::updatePortRates() { QModelIndex current = tvPortList->currentIndex(); if (!current.isValid()) return; if (!plm->isPort(current)) return; averagePacketsPerSec->setText(QString("%L1") .arg(plm->port(current).averagePacketRate(), 0, 'f', 4)); averageBitsPerSec->setText(QString("%L1") .arg(plm->port(current).averageBitRate(), 0, 'f', 0)); } void PortsWindow::updateStreamViewActions() { // For some reason hasSelection() returns true even if selection size is 0 // so additional check for size introduced if (tvStreamList->selectionModel()->hasSelection() && (tvStreamList->selectionModel()->selection().size() > 0)) { qDebug("Has selection %d", tvStreamList->selectionModel()->selection().size()); // If more than one non-contiguous ranges selected, // disable "New" and "Edit" if (tvStreamList->selectionModel()->selection().size() > 1) { actionNew_Stream->setDisabled(true); actionEdit_Stream->setDisabled(true); } else { actionNew_Stream->setEnabled(true); // Enable "Edit" only if the single range has a single row if (tvStreamList->selectionModel()->selection().at(0).height() > 1) actionEdit_Stream->setDisabled(true); else actionEdit_Stream->setEnabled(true); } // Delete is always enabled as long as we have a selection actionDelete_Stream->setEnabled(true); } else { qDebug("No selection"); if (plm->isPort(tvPortList->currentIndex())) actionNew_Stream->setEnabled(true); else actionNew_Stream->setDisabled(true); actionEdit_Stream->setDisabled(true); actionDelete_Stream->setDisabled(true); } actionOpen_Streams->setEnabled(plm->isPort( tvPortList->selectionModel()->currentIndex())); actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0); } 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); actionExclusive_Control->setDisabled(true); actionPort_Configuration->setDisabled(true); goto _EXIT; } qDebug("currentChanged %llx", current.internalId()); if (plm->isPortGroup(current)) { actionDelete_Port_Group->setEnabled(true); actionExclusive_Control->setDisabled(true); actionPort_Configuration->setDisabled(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->setDisabled(true); actionConnect_Port_Group->setDisabled(true); actionDisconnect_Port_Group->setDisabled(true); actionExclusive_Control->setEnabled(true); if (plm->port(current).hasExclusiveControl()) actionExclusive_Control->setChecked(true); else actionExclusive_Control->setChecked(false); actionPort_Configuration->setEnabled(true); } _EXIT: return; } void PortsWindow::on_pbApply_clicked() { QModelIndex curPort; QModelIndex curPortGroup; curPort = tvPortList->selectionModel()->currentIndex(); if (!curPort.isValid()) { qDebug("%s: curPort is invalid", __FUNCTION__); goto _exit; } if (!plm->isPort(curPort)) { qDebug("%s: curPort is not a port", __FUNCTION__); goto _exit; } if (plm->port(curPort).getStats().state().is_transmit_on()) { QMessageBox::information(0, "Configuration Change", "Please stop transmit on the port before applying any changes"); goto _exit; } curPortGroup = plm->getPortModel()->parent(curPort); if (!curPortGroup.isValid()) { qDebug("%s: curPortGroup is invalid", __FUNCTION__); goto _exit; } if (!plm->isPortGroup(curPortGroup)) { qDebug("%s: curPortGroup is not a portGroup", __FUNCTION__); goto _exit; } // FIXME(HI): shd this be a signal? //portGroup.when_configApply(port); // FIXME(MED): mixing port id and index!!! plm->portGroup(curPortGroup).when_configApply(plm->port(curPort).id()); _exit: return; #if 0 // 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"); #endif } 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(); } void PortsWindow::on_actionExclusive_Control_triggered(bool checked) { QModelIndex current = tvPortList->selectionModel()->currentIndex(); if (plm->isPort(current)) { OstProto::Port config; config.set_is_exclusive_control(checked); plm->portGroup(current.parent()).modifyPort(current.row(), config); } } void PortsWindow::on_actionPort_Configuration_triggered() { QModelIndex current = tvPortList->selectionModel()->currentIndex(); if (!plm->isPort(current)) return; OstProto::Port config; config.set_transmit_mode(plm->port(current).transmitMode()); config.set_is_exclusive_control(plm->port(current).hasExclusiveControl()); PortConfigDialog dialog(config, this); if (dialog.exec() == QDialog::Accepted) plm->portGroup(current.parent()).modifyPort(current.row(), config); } 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_actionEdit_Stream_triggered() { qDebug("Edit Stream Action"); // Ensure we have only one range selected which contains only one row if ((tvStreamList->selectionModel()->selection().size() == 1) && (tvStreamList->selectionModel()->selection().at(0).height() == 1)) { on_tvStreamList_activated(tvStreamList->selectionModel()-> selection().at(0).topLeft()); } } 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"); } void PortsWindow::on_actionOpen_Streams_triggered() { qDebug("Open Streams Action"); QModelIndex current = tvPortList->selectionModel()->currentIndex(); static QString dirName; QString fileName; QString errorStr; bool append = true; bool ret; Q_ASSERT(plm->isPort(current)); fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"), dirName); if (fileName.isEmpty()) goto _exit; if (tvStreamList->model()->rowCount()) { QMessageBox msgBox(QMessageBox::Question, qApp->applicationName(), tr("Append to existing streams? Or overwrite?"), QMessageBox::NoButton, this); QPushButton *appendBtn = msgBox.addButton(tr("Append"), QMessageBox::ActionRole); QPushButton *overwriteBtn = msgBox.addButton(tr("Overwrite"), QMessageBox::ActionRole); QPushButton *cancelBtn = msgBox.addButton(QMessageBox::Cancel); msgBox.exec(); if (msgBox.clickedButton() == cancelBtn) goto _exit; else if (msgBox.clickedButton() == appendBtn) append = true; else if (msgBox.clickedButton() == overwriteBtn) append = false; else Q_ASSERT(false); } ret = plm->port(current).openStreams(fileName, append, errorStr); if (!ret || !errorStr.isEmpty()) { QMessageBox msgBox(this); QStringList str = errorStr.split("\n\n\n\n"); msgBox.setIcon(ret ? QMessageBox::Warning : QMessageBox::Critical); msgBox.setWindowTitle(qApp->applicationName()); msgBox.setText(str.at(0)); if (str.size() > 1) msgBox.setDetailedText(str.at(1)); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); } dirName = QFileInfo(fileName).absolutePath(); _exit: return; } void PortsWindow::on_actionSave_Streams_triggered() { qDebug("Save Streams Action"); QModelIndex current = tvPortList->selectionModel()->currentIndex(); static QString fileName; QStringList fileTypes = AbstractFileFormat::supportedFileTypes(); QString fileType; QString errorStr; QFileDialog::Options options; // On Mac OS with Native Dialog, getSaveFileName() ignores fileType // which we need.On some Linux distros the native dialog can't // distinguish between Ostinato(*) and PCAP(*) #if defined(Q_OS_MAC) || defined(Q_OS_UNIX) options |= QFileDialog::DontUseNativeDialog; #endif if (fileTypes.size()) fileType = fileTypes.at(0); Q_ASSERT(plm->isPort(current)); _retry: fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"), fileName, fileTypes.join(";;"), &fileType, options); if (fileName.isEmpty()) goto _exit; fileType = fileType.remove(QRegExp("\\(.*\\)")).trimmed(); if (!fileType.startsWith("Ostinato")) { if (QMessageBox::warning(this, tr("Ostinato"), QString("You have chosen to save in %1 format. All stream " "attributes may not be saved in this format.\n\n" "It is recommended to save in native Ostinato format.\n\n" "Continue to save in %2 format?").arg(fileType).arg(fileType), QMessageBox::Yes|QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) goto _retry; } // TODO: all or selected? if (!plm->port(current).saveStreams(fileName, fileType, errorStr)) QMessageBox::critical(this, qApp->applicationName(), errorStr); else if (!errorStr.isEmpty()) QMessageBox::warning(this, qApp->applicationName(), errorStr); fileName = QFileInfo(fileName).absolutePath(); _exit: return; } ostinato-0.5.1/client/portswindow.h0000700000175300010010000000451212005505614016720 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PORTS_WINDOW_H #define _PORTS_WINDOW_H #include #include #include "ui_portswindow.h" #include "portgrouplist.h" /* TODO HIGH MED LOW */ class QAbstractItemDelegate; 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; QAbstractItemDelegate *delegate; private slots: void updatePortViewActions(const QModelIndex& current); void updateStreamViewActions(); void on_averagePacketsPerSec_editingFinished(); void on_averageBitsPerSec_editingFinished(); void updatePortRates(); void on_tvStreamList_activated(const QModelIndex & index); void when_portView_currentChanged(const QModelIndex& current, const QModelIndex& previous); void when_portModel_dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); void when_portModel_reset(); 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_actionExclusive_Control_triggered(bool checked); void on_actionPort_Configuration_triggered(); void on_actionNew_Stream_triggered(); void on_actionEdit_Stream_triggered(); void on_actionDelete_Stream_triggered(); void on_actionOpen_Streams_triggered(); void on_actionSave_Streams_triggered(); void streamModelDataChanged(); }; #endif ostinato-0.5.1/client/portswindow.ui0000700000175300010010000002143212005505614017106 0ustar srivatspNone PortsWindow 0 0 710 352 Form Qt::Horizontal false Qt::ActionsContextMenu QAbstractItemView::SingleSelection 0 0 0 0 0 0 0 QFrame::StyledPanel QFrame::Sunken Avg pps true Avg bps false Qt::Horizontal 40 20 Apply Qt::Vertical 20 0 0 1 Qt::ActionsContextMenu QFrame::StyledPanel 1 QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows Select a port to configure streams Qt::AlignCenter :/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 :/icons/stream_edit.png Edit Stream true Exclusive Port Control (EXPERIMENTAL) Open Streams ... Save Streams ... Port Configuration ... radioButton toggled(bool) averagePacketsPerSec setEnabled(bool) 313 28 380 28 radioButton_2 toggled(bool) averageBitsPerSec setEnabled(bool) 333 55 395 56 ostinato-0.5.1/client/preferences.cpp0000700000175300010010000000642412005505614017161 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "preferences.h" #include "../common/ostprotolib.h" #include "settings.h" #include Preferences::Preferences() { Q_ASSERT(appSettings); setupUi(this); wiresharkPathEdit->setText(appSettings->value(kWiresharkPathKey, kWiresharkPathDefaultValue).toString()); tsharkPathEdit->setText(appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString()); gzipPathEdit->setText(appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString()); diffPathEdit->setText(appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString()); awkPathEdit->setText(appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString()); } Preferences::~Preferences() { } void Preferences::accept() { appSettings->setValue(kWiresharkPathKey, wiresharkPathEdit->text()); appSettings->setValue(kTsharkPathKey, tsharkPathEdit->text()); appSettings->setValue(kGzipPathKey, gzipPathEdit->text()); appSettings->setValue(kDiffPathKey, diffPathEdit->text()); appSettings->setValue(kAwkPathKey, awkPathEdit->text()); OstProtoLib::setExternalApplicationPaths( appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(), appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString(), appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(), appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString()); QDialog::accept(); } void Preferences::on_wiresharkPathButton_clicked() { QString path; path = QFileDialog::getOpenFileName(0, "Locate Wireshark", wiresharkPathEdit->text()); if (!path.isEmpty()) wiresharkPathEdit->setText(path); } void Preferences::on_tsharkPathButton_clicked() { QString path; path = QFileDialog::getOpenFileName(0, "Locate tshark", tsharkPathEdit->text()); if (!path.isEmpty()) tsharkPathEdit->setText(path); } void Preferences::on_gzipPathButton_clicked() { QString path; path = QFileDialog::getOpenFileName(0, "Locate gzip", gzipPathEdit->text()); if (!path.isEmpty()) gzipPathEdit->setText(path); } void Preferences::on_diffPathButton_clicked() { QString path; path = QFileDialog::getOpenFileName(0, "Locate diff", diffPathEdit->text()); if (!path.isEmpty()) diffPathEdit->setText(path); } void Preferences::on_awkPathButton_clicked() { QString path; path = QFileDialog::getOpenFileName(0, "Locate awk", awkPathEdit->text()); if (!path.isEmpty()) awkPathEdit->setText(path); } ostinato-0.5.1/client/preferences.h0000700000175300010010000000217512005505614016625 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PREFERENCES_H #define _PREFERENCES_H #include "ui_preferences.h" #include class Preferences : public QDialog, private Ui::Preferences { Q_OBJECT public: Preferences(); ~Preferences(); public slots: void accept(); private slots: void on_wiresharkPathButton_clicked(); void on_tsharkPathButton_clicked(); void on_gzipPathButton_clicked(); void on_diffPathButton_clicked(); void on_awkPathButton_clicked(); }; #endif ostinato-0.5.1/client/preferences.ui0000700000175300010010000001377512005505614017023 0ustar srivatspNone Preferences 0 0 400 220 Preferences :/icons/preferences.png QFrame::Box QFrame::Sunken 'wireshark' Path wiresharkPathEdit false ... 'tshark' Path tsharkPathEdit false ... 'gzip' Path diffPathEdit false ... 'diff' Path diffPathEdit false ... 'awk' Path awkPathEdit false ... Qt::Vertical 21 61 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok wiresharkPathEdit wiresharkPathButton tsharkPathEdit tsharkPathButton gzipPathEdit gzipPathButton diffPathEdit diffPathButton awkPathEdit awkPathButton buttonBox buttonBox accepted() Preferences accept() 248 254 157 274 buttonBox rejected() Preferences reject() 316 260 286 274 ostinato-0.5.1/client/settings.h0000700000175300010010000000464712005505614016172 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SETTINGS_H #define _SETTINGS_H #include #include extern QSettings *appSettings; const QString kWiresharkPathKey("WiresharkPath"); #if defined(Q_OS_WIN32) const QString kWiresharkPathDefaultValue( "C:/Program Files/Wireshark/wireshark.exe"); #elif defined(Q_OS_MAC) const QString kWiresharkPathDefaultValue( "/Applications/Wireshark.app/Contents/Resources/bin/wireshark"); #else const QString kWiresharkPathDefaultValue("/usr/bin/wireshark"); #endif const QString kTsharkPathKey("TsharkPath"); #if defined(Q_OS_WIN32) const QString kTsharkPathDefaultValue( "C:/Program Files/Wireshark/tshark.exe"); #elif defined(Q_OS_MAC) const QString kTsharkPathDefaultValue( "/Applications/Wireshark.app/Contents/Resources/bin/tshark"); #else const QString kTsharkPathDefaultValue("/usr/bin/tshark"); #endif const QString kGzipPathKey("GzipPath"); #if defined(Q_OS_WIN32) extern QString kGzipPathDefaultValue; #elif defined(Q_OS_MAC) const QString kGzipPathDefaultValue("/usr/bin/gzip"); #else const QString kGzipPathDefaultValue("/usr/bin/gzip"); #endif const QString kDiffPathKey("DiffPath"); #if defined(Q_OS_WIN32) extern QString kDiffPathDefaultValue; #elif defined(Q_OS_MAC) const QString kDiffPathDefaultValue("/usr/bin/diff"); #else const QString kDiffPathDefaultValue("/usr/bin/diff"); #endif const QString kAwkPathKey("AwkPath"); #if defined(Q_OS_WIN32) extern QString kAwkPathDefaultValue; #elif defined(Q_OS_MAC) const QString kAwkPathDefaultValue("/usr/bin/awk"); #else const QString kAwkPathDefaultValue("/usr/bin/awk"); #endif // // LastUse Section Keys // const QString kApplicationWindowGeometryKey("LastUse/ApplicationWindowGeometry"); const QString kApplicationWindowLayout("LastUse/ApplicationWindowLayout"); #endif ostinato-0.5.1/client/stream.cpp0000700000175300010010000000342012005505614016144 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "stream.h" //#include "../common/protocollist.h" #include "../common/protocollistiterator.h" #include "../common/abstractprotocol.h" Stream::Stream() { //mId = 0xFFFFFFFF; setEnabled(true); } Stream::~Stream() { } void Stream::loadProtocolWidgets() { #if 0 //protocols.loadConfigWidgets(); foreach(AbstractProtocol* proto, *currentFrameProtocols) { proto->loadConfigWidget(); } #else ProtocolListIterator *iter; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol* p = iter->next(); p->loadConfigWidget(); } delete iter; #endif } void Stream::storeProtocolWidgets() { #if 0 //protocols.storeConfigWidgets(); foreach(const AbstractProtocol* proto, frameProtocol()) { proto->storeConfigWidget(); _iter->toFront(); } #else ProtocolListIterator *iter; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol* p = iter->next(); p->storeConfigWidget(); } delete iter; #endif } ostinato-0.5.1/client/stream.h0000700000175300010010000000200312005505614015605 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _STREAM_H #define _STREAM_H #include #include #include #include "../common/protocol.pb.h" #include "../common/streambase.h" class Stream : public StreamBase { //quint32 mId; public: Stream(); ~Stream(); void loadProtocolWidgets(); void storeProtocolWidgets(); }; #endif ostinato-0.5.1/client/streamconfigdialog.cpp0000700000175300010010000010303412005505614020514 0ustar srivatspNone/* Copyright (C) 2010-2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "streamconfigdialog.h" #include "stream.h" #include "abstractprotocol.h" #include "protocollistiterator.h" #include "modeltest.h" // FIXME(HI) - remove #include "../common/protocolmanager.h" extern ProtocolManager *OstProtocolManager; QRect StreamConfigDialog::lastGeometry; int StreamConfigDialog::lastTopLevelTabIndex = 0; int StreamConfigDialog::lastProtocolDataIndex = 0; static const uint kEthFrameOverHead = 20; StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, QWidget *parent) : QDialog (parent), mPort(port) { OstProto::Stream s; mCurrentStreamIndex = streamIndex; mpStream = new Stream; mPort.streamByIndex(mCurrentStreamIndex)->protoDataCopyInto(s); mpStream->protoDataCopyFrom(s); _iter = mpStream->createProtocolListIterator(); isUpdateInProgress = false; setupUi(this); setupUiExtra(); for (int i = ProtoMin; i < ProtoMax; i++) { bgProto[i]->setProperty("ProtocolLevel", i); bgProto[i]->setProperty("ProtocolId", ButtonIdNone); connect(bgProto[i], SIGNAL(buttonClicked(int)), this, SLOT(updateProtocol(int))); } //! \todo causes a crash! #if 0 connect(lePktLen, SIGNAL(textEdited(QString)), this, SLOT(updateContents())); #endif // Time to play match the signals and slots! // If L1/L2(FT)/L3 = None, force subsequent protocol level(s) also to None connect(rbL1None, SIGNAL(toggled(bool)), SLOT(forceProtocolNone(bool))); connect(rbFtNone, SIGNAL(toggled(bool)), SLOT(forceProtocolNone(bool))); connect(rbL3None, SIGNAL(toggled(bool)), SLOT(forceProtocolNone(bool))); connect(rbL4None, SIGNAL(toggled(bool)), SLOT(forceProtocolNone(bool))); // If L1/L2(FT)/L3/L4 = Other, force subsequent protocol to Other and // disable the subsequent protocol group as well connect(rbL1Other, SIGNAL(toggled(bool)), rbFtOther, SLOT(setChecked(bool))); connect(rbL1Other, SIGNAL(toggled(bool)), gbFrameType, SLOT(setDisabled(bool))); connect(rbFtOther, SIGNAL(toggled(bool)), rbL3Other, SLOT(setChecked(bool))); connect(rbFtOther, SIGNAL(toggled(bool)), gbL3Proto, SLOT(setDisabled(bool))); connect(rbL3Other, SIGNAL(toggled(bool)), rbL4Other, SLOT(setChecked(bool))); connect(rbL3Other, SIGNAL(toggled(bool)), gbL4Proto, SLOT(setDisabled(bool))); connect(rbL4Other, SIGNAL(toggled(bool)), rbPayloadOther, SLOT(setChecked(bool))); connect(rbL4Other, SIGNAL(toggled(bool)), gbPayloadProto, SLOT(setDisabled(bool))); // Setup valid subsequent protocols for L2 to L4 protocols for (int i = ProtoL2; i <= ProtoL4; i++) { foreach(QAbstractButton *btn1, bgProto[i]->buttons()) { int id1 = bgProto[i]->id(btn1); if (id1 != ButtonIdNone && id1 != ButtonIdOther) { int validProtocolCount = 0; foreach(QAbstractButton *btn2, bgProto[i+1]->buttons()) { int id2 = bgProto[i+1]->id(btn2); if (id2 != ButtonIdNone && id2 != ButtonIdOther) { if (OstProtocolManager->isValidNeighbour(id1, id2)) { connect(btn1, SIGNAL(toggled(bool)), btn2, SLOT(setEnabled(bool))); validProtocolCount++; } else connect(btn1, SIGNAL(toggled(bool)), btn2, SLOT(setDisabled(bool))); } } // If btn1 has no subsequent valid protocols, // force subsequent Protocol to 'None' if (validProtocolCount == 0) connect(btn1, SIGNAL(clicked(bool)), bgProto[i+1]->button(ButtonIdNone), SLOT(click())); // If the id1 protocol doesn't have a payload (e.g. IGMP) // force payload protocol to 'None' if (!OstProtocolManager->protocolHasPayload(id1)) { connect(btn1, SIGNAL(clicked(bool)), bgProto[ProtoPayload]->button(ButtonIdNone), SLOT(click())); } } } } mpAvailableProtocolsModel = new QStringListModel( OstProtocolManager->protocolDatabase(), this); lvAllProtocols->setModel(mpAvailableProtocolsModel); mpSelectedProtocolsModel = new QStringListModel(this); lvSelectedProtocols->setModel(mpSelectedProtocolsModel); connect(lvAllProtocols->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(when_lvAllProtocols_selectionChanged( const QItemSelection&, const QItemSelection&))); connect(lvSelectedProtocols->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(when_lvSelectedProtocols_currentChanged(const QModelIndex&, const QModelIndex&))); LoadCurrentStream(); mpPacketModel = new PacketModel(this); tvPacketTree->setModel(mpPacketModel); #ifdef QT_NO_DEBUG mpPacketModelTester = NULL; #else mpPacketModelTester = new ModelTest(mpPacketModel); #endif tvPacketTree->header()->hide(); vwPacketDump->setModel(mpPacketModel); vwPacketDump->setSelectionModel(tvPacketTree->selectionModel()); // TODO(MED): //! \todo Enable navigation of streams pbPrev->setHidden(true); pbNext->setHidden(true); //! \todo Support Goto Stream Id leStreamId->setHidden(true); disconnect(rbActionGotoStream, SIGNAL(toggled(bool)), leStreamId, SLOT(setEnabled(bool))); switch(mPort.transmitMode()) { case OstProto::kSequentialTransmit: rbModeFixed->setChecked(true); rbModeContinuous->setDisabled(true); break; case OstProto::kInterleavedTransmit: rbModeContinuous->setChecked(true); rbModeFixed->setDisabled(true); nextWhat->setHidden(true); break; default: Q_ASSERT(false); // Unreachable } // Finally, restore the saved last geometry and selected tab for the // various tab widgets if (!lastGeometry.isNull()) setGeometry(lastGeometry); twTopLevel->setCurrentIndex(lastTopLevelTabIndex); } 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 ---- bgProto[ProtoL1] = new QButtonGroup(); bgProto[ProtoL1]->addButton(rbL1None, ButtonIdNone); bgProto[ProtoL1]->addButton(rbL1Mac, OstProto::Protocol::kMacFieldNumber); bgProto[ProtoL1]->addButton(rbL1Other, ButtonIdOther); bgProto[ProtoL2] = new QButtonGroup(); #if 0 foreach(QRadioButton *btn, gbFrameType->findChildren()) bgL2Proto->addButton(btn); #else bgProto[ProtoL2]->addButton(rbFtNone, ButtonIdNone); bgProto[ProtoL2]->addButton(rbFtEthernet2, OstProto::Protocol::kEth2FieldNumber); bgProto[ProtoL2]->addButton(rbFt802Dot3Raw, OstProto::Protocol::kDot3FieldNumber); bgProto[ProtoL2]->addButton(rbFt802Dot3Llc, OstProto::Protocol::kDot2LlcFieldNumber); bgProto[ProtoL2]->addButton(rbFtLlcSnap, OstProto::Protocol::kDot2SnapFieldNumber); bgProto[ProtoL2]->addButton(rbFtOther, ButtonIdOther); #endif bgProto[ProtoVlan] = new QButtonGroup(); bgProto[ProtoVlan]->addButton(rbVlanNone, ButtonIdNone); bgProto[ProtoVlan]->addButton(rbVlanSingle, OstProto::Protocol::kVlanFieldNumber); bgProto[ProtoVlan]->addButton(rbVlanDouble, OstProto::Protocol::kVlanStackFieldNumber); bgProto[ProtoL3] = new QButtonGroup(); #if 0 foreach(QRadioButton *btn, gbL3Proto->findChildren()) bgProto[ProtoL3]->addButton(btn); #else bgProto[ProtoL3]->addButton(rbL3None, ButtonIdNone); bgProto[ProtoL3]->addButton(rbL3Arp, OstProto::Protocol::kArpFieldNumber); bgProto[ProtoL3]->addButton(rbL3Ipv4, OstProto::Protocol::kIp4FieldNumber); bgProto[ProtoL3]->addButton(rbL3Ipv6, OstProto::Protocol::kIp6FieldNumber); bgProto[ProtoL3]->addButton(rbL3Ip6over4, OstProto::Protocol::kIp6over4FieldNumber); bgProto[ProtoL3]->addButton(rbL3Ip4over6, OstProto::Protocol::kIp4over6FieldNumber); bgProto[ProtoL3]->addButton(rbL3Ip4over4, OstProto::Protocol::kIp4over4FieldNumber); bgProto[ProtoL3]->addButton(rbL3Ip6over6, OstProto::Protocol::kIp6over6FieldNumber); bgProto[ProtoL3]->addButton(rbL3Other, ButtonIdOther); #endif bgProto[ProtoL4] = new QButtonGroup(); #if 0 foreach(QRadioButton *btn, gbL4Proto->findChildren()) bgProto[ProtoL4]->addButton(btn); #else bgProto[ProtoL4]->addButton(rbL4None, ButtonIdNone); bgProto[ProtoL4]->addButton(rbL4Tcp, OstProto::Protocol::kTcpFieldNumber); bgProto[ProtoL4]->addButton(rbL4Udp, OstProto::Protocol::kUdpFieldNumber); bgProto[ProtoL4]->addButton(rbL4Icmp, OstProto::Protocol::kIcmpFieldNumber); bgProto[ProtoL4]->addButton(rbL4Igmp, OstProto::Protocol::kIgmpFieldNumber); bgProto[ProtoL4]->addButton(rbL4Mld, OstProto::Protocol::kMldFieldNumber); bgProto[ProtoL4]->addButton(rbL4Other, ButtonIdOther); #endif bgProto[ProtoL5] = new QButtonGroup(); #if 0 foreach(QRadioButton *btn, gbL5Proto->findChildren()) bgProto[ProtoL5]->addButton(btn); #else bgProto[ProtoL5]->addButton(rbL5None, ButtonIdNone); bgProto[ProtoL5]->addButton(rbL5Text, OstProto::Protocol::kTextProtocolFieldNumber); bgProto[ProtoL5]->addButton(rbL5Other, ButtonIdOther); #endif bgProto[ProtoPayload] = new QButtonGroup(); #if 0 foreach(QRadioButton *btn, gbPayloadProto->findChildren()) bgProto[ProtoPayload]->addButton(btn); #else bgProto[ProtoPayload]->addButton(rbPayloadNone, ButtonIdNone); bgProto[ProtoPayload]->addButton(rbPayloadPattern, OstProto::Protocol::kPayloadFieldNumber); bgProto[ProtoPayload]->addButton(rbPayloadHexDump, OstProto::Protocol::kHexDumpFieldNumber); bgProto[ProtoPayload]->addButton(rbPayloadOther, ButtonIdOther); #endif /* ** Setup Validators */ // Meta Data lePktLen->setValidator(new QIntValidator(MIN_PKT_LEN, MAX_PKT_LEN, this)); lePktLenMin->setValidator(new QIntValidator(MIN_PKT_LEN, MAX_PKT_LEN,this)); lePktLenMax->setValidator(new QIntValidator(MIN_PKT_LEN, MAX_PKT_LEN,this)); lePacketsPerBurst->setValidator(new QIntValidator(1, 0x7FFFFFFF,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())); } StreamConfigDialog::~StreamConfigDialog() { delete mpPacketModelTester; delete mpPacketModel; for (int i = ProtoMin; i < ProtoMax; i++) delete bgProto[i]; delete _iter; delete mpStream; } void StreamConfigDialog::on_cmbPktLenMode_currentIndexChanged(QString mode) { if (mode == "Fixed") { lePktLen->setEnabled(true); lePktLenMin->setDisabled(true); lePktLenMax->setDisabled(true); } else if (mode == "Increment") { lePktLen->setDisabled(true); lePktLenMin->setEnabled(true); lePktLenMax->setEnabled(true); } else if (mode == "Decrement") { lePktLen->setDisabled(true); lePktLenMin->setEnabled(true); lePktLenMax->setEnabled(true); } else if (mode == "Random") { lePktLen->setDisabled(true); lePktLenMin->setEnabled(true); lePktLenMax->setEnabled(true); } else { qWarning("Unhandled/Unknown PktLenMode = %s", mode.toAscii().data()); } } 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_tbSelectProtocols_currentChanged(int index) { qDebug("%s, index = %d", __FUNCTION__, index); switch (index) { case 0: updateSelectProtocolsSimpleWidget(); break; case 1: updateSelectProtocolsAdvancedWidget(); break; default: qFatal("%s: unexpected index = %d", __FUNCTION__, index); } } void StreamConfigDialog::when_lvAllProtocols_selectionChanged( const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/) { int size = lvAllProtocols->selectionModel()->selectedIndexes().size(); qDebug("%s: selected.indexes().size = %d\n", __FUNCTION__, size); tbAdd->setEnabled(size > 0); } void StreamConfigDialog::when_lvSelectedProtocols_currentChanged( const QModelIndex ¤t, const QModelIndex &/*previous*/) { qDebug("%s: currentRow = %d\n", __FUNCTION__, current.row()); tbDelete->setEnabled(current.isValid()); tbUp->setEnabled(current.isValid() && (current.row() != 0)); tbDown->setEnabled(current.isValid() && (current.row() != (current.model()->rowCount() - 1))); } void StreamConfigDialog::on_tbAdd_clicked() { int n = 0; QModelIndex idx2; QModelIndexList selection; selection = lvAllProtocols->selectionModel()->selectedIndexes(); // Validation if (selection.size() == 0) return; idx2 = lvSelectedProtocols->currentIndex(); if (idx2.isValid()) n = idx2.row(); _iter->toFront(); while (n--) { if (!_iter->hasNext()) return; _iter->next(); } foreach(QModelIndex idx, selection) _iter->insert(OstProtocolManager->createProtocol( mpAvailableProtocolsModel->stringList().at(idx.row()), mpStream)); updateSelectProtocolsAdvancedWidget(); lvSelectedProtocols->setCurrentIndex(idx2); } void StreamConfigDialog::on_tbDelete_clicked() { int n; QModelIndex idx; AbstractProtocol *p = NULL; idx = lvSelectedProtocols->currentIndex(); // Validation if (!idx.isValid()) return; n = idx.row() + 1; _iter->toFront(); while (n--) { if (!_iter->hasNext()) return; p = _iter->next(); } Q_CHECK_PTR(p); _iter->remove(); delete p; updateSelectProtocolsAdvancedWidget(); lvSelectedProtocols->setCurrentIndex(idx); } void StreamConfigDialog::on_tbUp_clicked() { int m, n; QModelIndex idx; AbstractProtocol *p = NULL; idx = lvSelectedProtocols->currentIndex(); // Validation if (!idx.isValid() || idx.row() == 0) return; m = n = idx.row() + 1; _iter->toFront(); while (n--) { if (!_iter->hasNext()) return; p = _iter->next(); } Q_CHECK_PTR(p); _iter->remove(); _iter->previous(); _iter->insert(p); updateSelectProtocolsAdvancedWidget(); lvSelectedProtocols->setCurrentIndex(idx.sibling(m-2, 0)); } void StreamConfigDialog::on_tbDown_clicked() { int m, n; QModelIndex idx; AbstractProtocol *p = NULL; idx = lvSelectedProtocols->currentIndex(); // Validation if (!idx.isValid() || idx.row() == idx.model()->rowCount()) return; m = n = idx.row() + 1; _iter->toFront(); while (n--) { if (!_iter->hasNext()) return; p = _iter->next(); } Q_CHECK_PTR(p); _iter->remove(); _iter->next(); _iter->insert(p); updateSelectProtocolsAdvancedWidget(); lvSelectedProtocols->setCurrentIndex(idx.sibling(m,0)); } void StreamConfigDialog::updateSelectProtocolsAdvancedWidget() { QStringList selProtoList; qDebug("%s", __FUNCTION__); _iter->toFront(); while(_iter->hasNext()) { AbstractProtocol* p = _iter->next(); qDebug("%p -- %d", p, p->protocolNumber()); selProtoList.append(p->shortName()); } mpSelectedProtocolsModel->setStringList(selProtoList); } void StreamConfigDialog::on_twTopLevel_currentChanged(int index) { switch (index) { // Protocol Data case 1: { // Hide the ToolBox before modifying it - else we have a crash !!! tbProtocolData->hide(); // Remove all existing protocol widgets while (tbProtocolData->count() > 0) { QWidget* w = tbProtocolData->widget(0); tbProtocolData->removeItem(0); w->setParent(0); } // Repopulate the widgets _iter->toFront(); while (_iter->hasNext()) { AbstractProtocol* p = _iter->next(); tbProtocolData->addItem(p->configWidget(), p->name()); } if (lastProtocolDataIndex < tbProtocolData->count()) tbProtocolData->setCurrentIndex(lastProtocolDataIndex); tbProtocolData->show(); break; } // Stream Control case 2: { StoreCurrentStream(); break; } // Packet View case 3: { StoreCurrentStream(); mpPacketModel->setSelectedProtocols(*_iter); break; } default: break; } lastProtocolDataIndex = tbProtocolData->currentIndex(); } 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); } #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 /*! Skip protocols upto and including the layer specified. */ bool StreamConfigDialog::skipProtocols(int layer) { _iter->toFront(); for (int i = ProtoMin; i <= layer; i++) { if(_iter->hasNext()) { int id; QAbstractButton *btn; id = _iter->peekNext()->protocolNumber(); btn = bgProto[i]->button(id); if (btn) _iter->next(); } } return true; } /*! Protocol choices (except "None" and "Other") for a protocol button group are disabled if checked is true, else they are enabled */ void StreamConfigDialog::disableProtocols(QButtonGroup *protocolGroup, bool checked) { qDebug("%s: btnGrp = %p, chk? = %d", __FUNCTION__, protocolGroup, checked); foreach(QAbstractButton *btn, protocolGroup->buttons()) { int id = protocolGroup->id(btn); if ((id != ButtonIdNone) && (id != ButtonIdOther)) btn->setDisabled(checked); } } void StreamConfigDialog::forceProtocolNone(bool checked) { QObject *btn; btn = sender(); Q_ASSERT(btn != NULL); qDebug("%s: chk? = %d, btn = %p, L1 = %p, L2 = %p, L3 = %p", __FUNCTION__, checked, btn, rbL1None, rbFtNone, rbL3None); if (btn == rbL1None) { if (checked) { bgProto[ProtoVlan]->button(ButtonIdNone)->click(); bgProto[ProtoL2]->button(ButtonIdNone)->click(); bgProto[ProtoPayload]->button(ButtonIdNone)->click(); } disableProtocols(bgProto[ProtoVlan], checked); disableProtocols(bgProto[ProtoL2], checked); disableProtocols(bgProto[ProtoPayload], checked); } else if (btn == rbFtNone) { if (checked) bgProto[ProtoL3]->button(ButtonIdNone)->click(); disableProtocols(bgProto[ProtoL3], checked); } else if (btn == rbL3None) { if (checked) bgProto[ProtoL4]->button(ButtonIdNone)->click(); disableProtocols(bgProto[ProtoL4], checked); } else if (btn == rbL4None) { if (checked) bgProto[ProtoL5]->button(ButtonIdNone)->click(); disableProtocols(bgProto[ProtoL5], checked); } else { Q_ASSERT(1 == 0); // Unreachable code! } } void StreamConfigDialog::updateProtocol(int newId) { int level; QButtonGroup *btnGrp; btnGrp = static_cast(sender()); Q_ASSERT(btnGrp != NULL); level = btnGrp->property("ProtocolLevel").toInt(); Q_ASSERT(btnGrp == bgProto[level]); __updateProtocol(level, newId); } void StreamConfigDialog::__updateProtocol(int level, int newId) { int oldId; QButtonGroup *btnGrp; Q_ASSERT((level >= ProtoMin) && (level <= ProtoMax)); btnGrp = bgProto[level]; oldId = btnGrp->property("ProtocolId").toInt(); qDebug("%s: level = %d old id = %d new id = %d upd? = %d", __FUNCTION__, level, oldId, newId, isUpdateInProgress); if (newId == oldId) return; if (!isUpdateInProgress) { int ret; AbstractProtocol *p; ret = skipProtocols(level-1); Q_ASSERT(ret == true); Q_ASSERT(oldId != newId); Q_ASSERT(newId != ButtonIdOther); switch (oldId) { case ButtonIdNone: _iter->insert(OstProtocolManager->createProtocol( newId, mpStream)); break; case ButtonIdOther: default: Q_ASSERT(_iter->hasNext()); p =_iter->next(); if (newId) _iter->setValue(OstProtocolManager->createProtocol( newId, mpStream)); else _iter->remove(); delete p; if (level == ProtoPayload) { while (_iter->hasNext()) { p = _iter->next(); _iter->remove(); delete p; } } break; } } btnGrp->setProperty("ProtocolId", newId); return; } void StreamConfigDialog::updateSelectProtocolsSimpleWidget() { int i; quint32 id; QAbstractButton *btn; qDebug("%s", __FUNCTION__); isUpdateInProgress = true; // Reset to default state ... for (i = ProtoMin; i < ProtoMax; i++) bgProto[i]->button(ButtonIdNone)->click(); // ... now iterate and update _iter->toFront(); for (i = ProtoMin; i < ProtoMax; i++) { if (!_iter->hasNext()) goto _done; id = _iter->next()->protocolNumber(); btn = bgProto[i]->button(id); if (btn) { if (btn->isEnabled()) btn->click(); else { btn->setChecked(true); __updateProtocol(i, id); } } else { switch (i) { case ProtoVlan: _iter->previous(); break; case ProtoPayload: goto _other; default: btn = bgProto[ProtoPayload]->button(id); if (btn && btn->isEnabled()) { btn->click(); break; } else goto _other; } } } // If more protocol(s) beyond payload ... if (_iter->hasNext()) { i = ProtoPayload; goto _other; } goto _done; _other: for (int j = i; j < ProtoMax; j++) { // VLAN doesn't have a "Other" button if (j == ProtoVlan) continue; bgProto[j]->button(ButtonIdOther)->setChecked(true); __updateProtocol(j, ButtonIdOther); } _done: isUpdateInProgress = false; } void StreamConfigDialog::LoadCurrentStream() { QString str; qDebug("loading mpStream %p", mpStream); // Meta Data { cmbPktLenMode->setCurrentIndex(mpStream->lenMode()); lePktLen->setText(str.setNum(mpStream->frameLen())); lePktLenMin->setText(str.setNum(mpStream->frameLenMin())); lePktLenMax->setText(str.setNum(mpStream->frameLenMax())); } // Protocols { updateSelectProtocolsSimpleWidget(); updateSelectProtocolsAdvancedWidget(); mpStream->loadProtocolWidgets(); } // Stream Control { switch (mpStream->sendUnit()) { case Stream::e_su_packets: rbSendPackets->setChecked(true); break; case Stream::e_su_bursts: rbSendBursts->setChecked(true); break; default: qWarning("Unhandled sendUnit = %d\n", mpStream->sendUnit()); } switch (mpStream->sendMode()) { case Stream::e_sm_fixed: rbModeFixed->setChecked(true); break; case Stream::e_sm_continuous: rbModeContinuous->setChecked(true); break; default: qWarning("Unhandled sendMode = %d\n", mpStream->sendMode()); } switch(mpStream->nextWhat()) { case Stream::e_nw_stop: rbActionStop->setChecked(true); break; case Stream::e_nw_goto_next: rbActionGotoNext->setChecked(true); break; case Stream::e_nw_goto_id: rbActionGotoStream->setChecked(true); break; default: qWarning("Unhandled nextAction = %d\n", mpStream->nextWhat()); } leNumPackets->setText(QString().setNum(mpStream->numPackets())); leNumBursts->setText(QString().setNum(mpStream->numBursts())); lePacketsPerBurst->setText(QString().setNum(mpStream->burstSize())); lePacketsPerSec->setText( QString("%L1").arg(mpStream->packetRate(), 0, 'f', 4)); leBurstsPerSec->setText( QString("%L1").arg(mpStream->burstRate(), 0, 'f', 4)); // TODO(MED): Change this when we support goto to specific stream leStreamId->setText(QString("0")); leGapIsg->setText("0.0"); } qDebug("loading stream done"); } void StreamConfigDialog::StoreCurrentStream() { QString str; bool isOk; Stream *pStream = mpStream; qDebug("storing pStream %p", pStream); // Meta Data pStream->setLenMode((Stream::FrameLengthMode) cmbPktLenMode->currentIndex()); pStream->setFrameLen(lePktLen->text().toULong(&isOk)); pStream->setFrameLenMin(lePktLenMin->text().toULong(&isOk)); pStream->setFrameLenMax(lePktLenMax->text().toULong(&isOk)); // Protocols { pStream->storeProtocolWidgets(); } // Stream Control { if (rbSendPackets->isChecked()) pStream->setSendUnit(Stream::e_su_packets); if (rbSendBursts->isChecked()) pStream->setSendUnit(Stream::e_su_bursts); if (rbModeFixed->isChecked()) pStream->setSendMode(Stream::e_sm_fixed); if (rbModeContinuous->isChecked()) pStream->setSendMode(Stream::e_sm_continuous); if (rbActionStop->isChecked()) pStream->setNextWhat(Stream::e_nw_stop); if (rbActionGotoNext->isChecked()) pStream->setNextWhat(Stream::e_nw_goto_next); if (rbActionGotoStream->isChecked()) pStream->setNextWhat(Stream::e_nw_goto_id); pStream->setNumPackets(leNumPackets->text().toULong(&isOk)); pStream->setNumBursts(leNumBursts->text().toULong(&isOk)); pStream->setBurstSize(lePacketsPerBurst->text().toULong(&isOk)); pStream->setPacketRate( QLocale().toDouble(lePacketsPerSec->text(), &isOk)); pStream->setBurstRate( QLocale().toDouble(leBurstsPerSec->text(), &isOk)); } } void StreamConfigDialog::on_tbProtocolData_currentChanged(int /*index*/) { // Refresh protocol widgets in case there is any dependent data between // protocols e.g. TCP/UDP port numbers are dependent on Port/Protocol // selection in TextProtocol #if 0 // FIXME: temp mask to avoid crash till we fix it mpStream->storeProtocolWidgets(); mpStream->loadProtocolWidgets(); #endif } void StreamConfigDialog::on_rbPacketsPerSec_toggled(bool checked) { if (checked) on_lePacketsPerSec_textChanged(lePacketsPerSec->text()); } void StreamConfigDialog::on_rbBurstsPerSec_toggled(bool checked) { if (checked) on_leBurstsPerSec_textChanged(leBurstsPerSec->text()); } void StreamConfigDialog::on_lePacketsPerBurst_textChanged(const QString &/*text*/) { if (rbSendBursts->isChecked()) on_leBurstsPerSec_textChanged(leBurstsPerSec->text()); } void StreamConfigDialog::on_lePacketsPerSec_textChanged(const QString &text) { bool isOk; Stream *pStream = mpStream; uint frameLen; if (pStream->lenMode() == Stream::e_fl_fixed) frameLen = pStream->frameLen(); else frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2; if (rbSendPackets->isChecked()) { double pktsPerSec = QLocale().toDouble(text, &isOk); double bitsPerSec = pktsPerSec * double((frameLen+kEthFrameOverHead)*8); if (rbPacketsPerSec->isChecked()) leBitsPerSec->setText(QString("%L1").arg(bitsPerSec, 0, 'f', 0)); leGapIbg->setText(QString("0.0")); leGapIpg->setText(QString("%L1").arg(1/double(pktsPerSec), 0, 'f', 9)); } } void StreamConfigDialog::on_leBurstsPerSec_textChanged(const QString &text) { bool isOk; Stream *pStream = mpStream; uint burstSize = lePacketsPerBurst->text().toULong(&isOk); uint frameLen; qDebug("start of %s(%s)", __FUNCTION__, text.toAscii().constData()); if (pStream->lenMode() == Stream::e_fl_fixed) frameLen = pStream->frameLen(); else frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2; if (rbSendBursts->isChecked()) { double burstsPerSec = QLocale().toDouble(text, &isOk); double bitsPerSec = burstsPerSec * double(burstSize * (frameLen + kEthFrameOverHead) * 8); if (rbBurstsPerSec->isChecked()) leBitsPerSec->setText(QString("%L1").arg(bitsPerSec, 0, 'f', 0)); leGapIbg->setText(QString("%L1").arg(1/double(burstsPerSec), 0, 'f',9)); leGapIpg->setText(QString("0.0")); } qDebug("end of %s", __FUNCTION__); } void StreamConfigDialog::on_leBitsPerSec_textEdited(const QString &text) { bool isOk; Stream *pStream = mpStream; uint burstSize = lePacketsPerBurst->text().toULong(&isOk); uint frameLen; if (pStream->lenMode() == Stream::e_fl_fixed) frameLen = pStream->frameLen(); else frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2; if (rbSendPackets->isChecked()) { double pktsPerSec = QLocale().toDouble(text, &isOk)/ double((frameLen+kEthFrameOverHead)*8); lePacketsPerSec->setText(QString("%L1").arg(pktsPerSec, 0, 'f', 4)); } else if (rbSendBursts->isChecked()) { double burstsPerSec = QLocale().toDouble(text, &isOk)/ double(burstSize * (frameLen + kEthFrameOverHead) * 8); leBurstsPerSec->setText(QString("%L1").arg(burstsPerSec, 0, 'f', 4)); } } void StreamConfigDialog::on_pbOk_clicked() { QString log; OstProto::Stream s; // Store dialog contents into stream StoreCurrentStream(); if ((mPort.transmitMode() == OstProto::kInterleavedTransmit) && (mpStream->isFrameVariable())) { log += "In 'Interleaved Streams' transmit mode, the count for " "varying fields at transmit time may not be same as configured\n"; } mpStream->preflightCheck(log); if (log.length()) { if (QMessageBox::warning(this, "Preflight Check", log + "\nContinue?", QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) return; } // Copy the data from the "local working copy of stream" to "actual stream" mpStream->protoDataCopyInto(s); mPort.streamByIndex(mCurrentStreamIndex)->protoDataCopyFrom(s); qDebug("stream stored"); lastGeometry = geometry(); lastTopLevelTabIndex = twTopLevel->currentIndex(); lastProtocolDataIndex = tbProtocolData->currentIndex(); accept(); } ostinato-0.5.1/client/streamconfigdialog.h0000700000175300010010000000757512005505614020176 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _STREAM_CONFIG_DIALOG_H #define _STREAM_CONFIG_DIALOG_H #include #include "ui_streamconfigdialog.h" #include "port.h" #include "stream.h" #include "packetmodel.h" #include "modeltest.h" #define MAX_MAC_ITER_COUNT 256 #define MIN_PKT_LEN 64 #define MAX_PKT_LEN 16384 /* ** TODO ** \todo Improve HexStr handling ** */ class StreamConfigDialog : public QDialog, public Ui::StreamConfigDialog { Q_OBJECT public: StreamConfigDialog(Port &port, uint streamIndex, QWidget *parent = 0); ~StreamConfigDialog(); private: enum ButtonId { ButtonIdNone = 0, ButtonIdOther = -2 }; enum ProtoButtonGroup { ProtoMin, ProtoL1 = 0, ProtoVlan = 1, ProtoL2 = 2, ProtoL3 = 3, ProtoL4 = 4, ProtoL5 = 5, ProtoPayload = 6, ProtoMax }; QButtonGroup *bgProto[ProtoMax]; QStringListModel *mpAvailableProtocolsModel; QStringListModel *mpSelectedProtocolsModel; Port& mPort; uint mCurrentStreamIndex; Stream *mpStream; ProtocolListIterator *_iter; bool isUpdateInProgress; PacketModel *mpPacketModel; ModelTest *mpPacketModelTester; // The following static variables are used to track the "selected" tab // for the various tab widgets so that it can be restored when the dialog // is opened the next time. We also track the last Dialog geometry. static QRect lastGeometry; static int lastTopLevelTabIndex; static int lastProtocolDataIndex; void setupUiExtra(); void LoadCurrentStream(); void StoreCurrentStream(); private slots: void on_cmbPktLenMode_currentIndexChanged(QString mode); void update_NumPacketsAndNumBursts(); void on_twTopLevel_currentChanged(int index); void on_tbSelectProtocols_currentChanged(int index); // "Simple" Protocol Selection related bool skipProtocols(int layer); void disableProtocols(QButtonGroup *protocolGroup, bool checked); void forceProtocolNone(bool checked); void updateProtocol(int newId); void __updateProtocol(int level, int newId); void updateSelectProtocolsSimpleWidget(); // "Advanced" Protocol Selection related void when_lvAllProtocols_selectionChanged( const QItemSelection &selected, const QItemSelection &deselected); void when_lvSelectedProtocols_currentChanged( const QModelIndex ¤t, const QModelIndex &previous); void on_tbAdd_clicked(); void on_tbDelete_clicked(); void on_tbUp_clicked(); void on_tbDown_clicked(); void updateSelectProtocolsAdvancedWidget(); // "Protocol Data" related void on_tbProtocolData_currentChanged(int index); // "Stream Control" related void on_rbPacketsPerSec_toggled(bool checked); void on_rbBurstsPerSec_toggled(bool checked); void on_lePacketsPerBurst_textChanged(const QString &text); void on_lePacketsPerSec_textChanged(const QString &text); void on_leBurstsPerSec_textChanged(const QString &text); void on_leBitsPerSec_textEdited(const QString &text); void on_pbPrev_clicked(); void on_pbNext_clicked(); void on_pbOk_clicked(); }; #endif ostinato-0.5.1/client/streamconfigdialog.ui0000700000175300010010000013127312005505614020355 0ustar srivatspNone StreamConfigDialog Qt::ApplicationModal 0 0 634 507 0 0 Edit Stream :/icons/stream_edit.png 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 Protocol Selection Qt::Horizontal 241 20 Frame Length (including FCS) Fixed Increment Decrement Random Min false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Max false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 0 592 269 Simple L1 None true Mac false false Other true L2 None true Ethernet II false 802.3 Raw 802.3 LLC false 802.3 LLC SNAP false Other true L3 None true false ARP false IPv4 false false IPv6 false IP 6over4 false false IP 4over6 false false IP 4over4 false false IP 6over6 false false Other true L5 None true false Text false Other true VLAN false false Untagged true Tagged Stacked true L4 None true false ICMP false IGMP false TCP false UDP false Other false MLD true Payload None true Pattern false Hex Dump false Other 0 0 250 135 Advanced Available Protocols true QAbstractItemView::ExtendedSelection QAbstractItemView::SelectRows Qt::Vertical 20 40 false > :/icons/arrow_right.png Qt::Vertical 20 40 Selected Protocols false ^ :/icons/arrow_up.png false v :/icons/arrow_down.png false - :/icons/delete.png Qt::Horizontal 40 20 QAbstractItemView::SelectRows Protocol Data -1 Stream Control Send Packets true Bursts Numbers Number of Packets leNumPackets Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Number of Bursts leNumBursts false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Packets per Burst lePacketsPerBurst false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Rate false false Packets/Sec true Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false Bursts/Sec false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Bits/Sec false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter After this stream Stop Goto Next Stream true Goto First false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 20 41 Mode Fixed true Continuous true Gaps (in seconds) false false :/icons/gaps.png ISG leGapIsg false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter IBG leGapIbg false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter IPG leGapIpg false Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 153 21 Packet View Qt::Vertical QAbstractItemView::SelectItems true Prev Next Qt::Horizontal 191 20 OK true Cancel DumpView QWidget
dumpview.h
1
twTopLevel cmbPktLenMode lePktLen lePktLenMin lePktLenMax rbFtEthernet2 rbFt802Dot3Raw rbFt802Dot3Llc rbFtLlcSnap rbFtOther rbVlanNone rbVlanSingle rbVlanDouble rbL3None rbL3Ipv4 rbL3Ipv6 rbL3Arp rbL3Other rbL4None rbL4Icmp rbL4Igmp rbL4Tcp rbL4Udp rbL4Other rbPayloadPattern rbPayloadOther pbPrev pbNext pbOk pbCancel rbSendBursts leNumPackets leNumBursts lePacketsPerBurst rbActionStop rbActionGotoNext rbActionGotoStream leStreamId rbModeFixed rbModeContinuous lePacketsPerSec leBurstsPerSec leGapIsg leGapIpg leGapIbg tvPacketTree tbDown tbDelete lvSelectedProtocols rbSendPackets tbUp lvAllProtocols tbAdd pbCancel clicked() StreamConfigDialog reject() 623 496 533 466 rbActionGotoStream toggled(bool) leStreamId setEnabled(bool) 463 143 463 177 rbSendPackets toggled(bool) rbPacketsPerSec setEnabled(bool) 30 68 299 82 rbSendBursts toggled(bool) rbBurstsPerSec setEnabled(bool) 30 95 299 132 rbSendBursts toggled(bool) lePacketsPerBurst setEnabled(bool) 30 95 134 189 rbPacketsPerSec toggled(bool) lePacketsPerSec setEnabled(bool) 299 82 299 108 rbBurstsPerSec toggled(bool) leBurstsPerSec setEnabled(bool) 299 132 299 158 rbBitsPerSec toggled(bool) leBitsPerSec setEnabled(bool) 299 182 299 208 rbSendPackets toggled(bool) rbPacketsPerSec setChecked(bool) 95 70 299 82 rbSendBursts toggled(bool) rbBurstsPerSec setChecked(bool) 96 98 299 132 rbModeContinuous toggled(bool) leNumPackets setDisabled(bool) 73 196 164 108 rbModeContinuous toggled(bool) leNumBursts setDisabled(bool) 96 199 226 155
ostinato-0.5.1/client/streamlistdelegate.cpp0000700000175300010010000001260212005505614020535 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include #include #include "streammodel.h" #include "streamlistdelegate.h" StreamListDelegate::StreamListDelegate(QObject *parent) : QItemDelegate(parent) { } QWidget *StreamListDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QWidget *editor = NULL; switch ((StreamModel::StreamFields) index.column()) { case StreamModel::StreamStatus: { editor = new QCheckBox(parent); goto _handled; } case StreamModel::StreamNextWhat: { editor = new QComboBox(parent); static_cast(editor)->insertItems(0, StreamModel::nextWhatOptionList()); goto _handled; } case StreamModel::StreamIcon: case StreamModel::StreamName: default: break; } editor = QItemDelegate::createEditor(parent, option, index); _handled: return editor; } void StreamListDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { switch ((StreamModel::StreamFields) index.column()) { case StreamModel::StreamStatus: { QCheckBox *cb = static_cast(editor); cb->setChecked( index.model()->data(index, Qt::EditRole).toBool()); goto _handled; } case StreamModel::StreamNextWhat: { QComboBox *cb = static_cast(editor); cb->setCurrentIndex( index.model()->data(index, Qt::EditRole).toInt()); goto _handled; } case StreamModel::StreamIcon: case StreamModel::StreamName: default: break; } QItemDelegate::setEditorData(editor, index); _handled: return; } void StreamListDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { switch ((StreamModel::StreamFields) index.column()) { case StreamModel::StreamStatus: { QCheckBox *cb = static_cast(editor); model->setData(index, cb->isChecked(), Qt::EditRole); goto _handled; } case StreamModel::StreamNextWhat: { QComboBox *cb = static_cast(editor); model->setData(index, cb->currentIndex(), Qt::EditRole); goto _handled; } case StreamModel::StreamIcon: case StreamModel::StreamName: default: break; } QItemDelegate::setModelData(editor, model, index); _handled: return; } void StreamListDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { switch ((StreamModel::StreamFields) index.column()) { case StreamModel::StreamStatus: { /* * extra 'coz QItemDelegate does it - otherwise the editor * placement is incorrect */ int extra = 2 * (qApp->style()->pixelMetric( QStyle::PM_FocusFrameHMargin, 0) + 1); editor->setGeometry(option.rect.translated(extra, 0)); goto _handled; } case StreamModel::StreamIcon: case StreamModel::StreamName: case StreamModel::StreamNextWhat: default: break; } QItemDelegate::updateEditorGeometry(editor, option, index); _handled: return; } bool StreamListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { /* * Special Handling so that user can use the "Stream status" checkbox * without double clicking first. Copied from QItemDelegate::editorEvent() * and modified suitably */ if ((StreamModel::StreamFields)index.column() == StreamModel::StreamStatus) { // make sure that we have the right event type if ((event->type() == QEvent::MouseButtonRelease) || (event->type() == QEvent::MouseButtonDblClick)) { QRect checkRect = check(option, option.rect, Qt::Checked); QRect emptyRect; doLayout(option, &checkRect, &emptyRect, &emptyRect, false); if (!checkRect.contains(static_cast(event)->pos())) return false; Qt::CheckState state = (static_cast(index.data( Qt::CheckStateRole).toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); return model->setData(index, state, Qt::CheckStateRole); } } return QItemDelegate::editorEvent(event, model, option, index); } ostinato-0.5.1/client/streamlistdelegate.h0000700000175300010010000000270312005505614020203 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef STREAM_LIST_DELEGATE_H #define STREAM_LIST_DELEGATE_H #include #include class StreamListDelegate : public QItemDelegate { Q_OBJECT public: StreamListDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index); }; #endif ostinato-0.5.1/client/streammodel.cpp0000700000175300010010000001704212005505614017172 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "stream.h" #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->numStreams(); else return 0; } int StreamModel::columnCount(const QModelIndex &/*parent*/) const { int count = StreamMaxFields; if (mCurrentPort && (mCurrentPort->transmitMode() == OstProto::kInterleavedTransmit)) count--; return count; } 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; break; case StreamNextWhat: flags |= Qt::ItemIsEditable; break; default: //qFatal("Missed case in switch!"); 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->numStreams()) 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"); else return QVariant(); break; } case StreamName: { if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) return mCurrentPort->streamByIndex(index.row())->name(); else return QVariant(); break; } case StreamStatus: { if ((role == Qt::CheckStateRole)) { if (mCurrentPort->streamByIndex(index.row())->isEnabled()) return Qt::Checked; else return Qt::Unchecked; } else return QVariant(); break; } case StreamNextWhat: { int val = mCurrentPort->streamByIndex(index.row())->nextWhat(); if (role == Qt::DisplayRole) return nextWhatOptionList().at(val); else if (role == Qt::EditRole) return val; else return QVariant(); break; } default: qFatal("-------------UNHANDLED STREAM FIELD----------------"); } return QVariant(); } bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (mCurrentPort == NULL) return false; if (index.isValid()) { switch (index.column()) { // Edit Supported Fields case StreamName: mCurrentPort->streamByIndex(index.row())->setName(value.toString()); emit(dataChanged(index, index)); return true; case StreamStatus: mCurrentPort->streamByIndex(index.row())->setEnabled(value.toBool()); emit(dataChanged(index, index)); return true; case StreamNextWhat: if (role == Qt::EditRole) { mCurrentPort->streamByIndex(index.row())->setNextWhat( (Stream::NextWhat)value.toInt()); emit(dataChanged(index, index)); return true; } else return false; // Edit Not Supported Fields case StreamIcon: return false; // 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(""); break; case StreamName: return QString("Name"); break; case StreamStatus: return QString(""); break; case StreamNextWhat: return QString("Goto"); 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->newStreamAt(row); 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++) { mCurrentPort->deleteStreamAt(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"); // Disconnect any existing connection to avoid duplication // Qt 4.6 has Qt::UniqueConnection, but we want to remain compatible // with earlier Qt versions if (mCurrentPort) { disconnect(mCurrentPort, SIGNAL(streamListChanged(int, int)), this, SLOT(when_mCurrentPort_streamListChanged(int, int))); } quint16 pg = current.internalId() >> 16; mCurrentPort = pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()]; connect(mCurrentPort, SIGNAL(streamListChanged(int, int)), this, SLOT(when_mCurrentPort_streamListChanged(int, int))); } reset(); } void StreamModel::when_mCurrentPort_streamListChanged(int portGroupId, int portId) { qDebug("In %s", __FUNCTION__); if (mCurrentPort) { if ((quint32(portGroupId) == mCurrentPort->portGroupId()) && (quint32(portId) == mCurrentPort->id())) reset(); } } ostinato-0.5.1/client/streammodel.h0000700000175300010010000000447112005505614016641 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _STREAM_MODEL_H #define _STREAM_MODEL_H #include #include #include "port.h" class PortGroupList; class StreamModel : public QAbstractTableModel { Q_OBJECT 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()); #if 0 // CleanedUp! // FIXME(HIGH): This *is* like a kludge QList* currentPortStreamList() { return &mCurrentPort->mStreams; } #endif public: enum StreamFields { StreamIcon = 0, StreamStatus, StreamName, StreamNextWhat, StreamMaxFields }; static QStringList nextWhatOptionList() { return QStringList() << "Stop" << "Next" << "Goto first"; } public slots: void setCurrentPortIndex(const QModelIndex ¤t); private slots: void when_mCurrentPort_streamListChanged(int portGroupId, int portId); }; #endif ostinato-0.5.1/common/0000700000175300010010000000000012005505615014156 5ustar srivatspNoneostinato-0.5.1/common/abstractfileformat.cpp0000700000175300010010000000534612005505614020550 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "abstractfileformat.h" #include "fileformat.h" #include "pcapfileformat.h" #include "pdmlfileformat.h" #include AbstractFileFormat::AbstractFileFormat() { stop_ = false; } AbstractFileFormat::~AbstractFileFormat() { } QDialog* AbstractFileFormat::openOptionsDialog() { return NULL; } QDialog* AbstractFileFormat::saveOptionsDialog() { return NULL; } QStringList AbstractFileFormat::supportedFileTypes() { return QStringList() << "Ostinato (*)" << "PCAP (*)" << "PDML (*.pdml)"; } void AbstractFileFormat::openStreamsOffline(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { fileName_ = fileName; openStreams_ = &streams; error_ = &error; op_ = kOpen; stop_ = false; start(); } void AbstractFileFormat::saveStreamsOffline( const OstProto::StreamConfigList streams, const QString fileName, QString &error) { saveStreams_ = streams; fileName_ = fileName; error_ = &error; op_ = kSave; stop_ = false; start(); } bool AbstractFileFormat::result() { return result_; } AbstractFileFormat* AbstractFileFormat::fileFormatFromFile( const QString fileName) { if (fileFormat.isMyFileFormat(fileName)) return &fileFormat; if (pdmlFileFormat.isMyFileFormat(fileName)) return &pdmlFileFormat; if (pcapFileFormat.isMyFileFormat(fileName)) return &pcapFileFormat; return NULL; } AbstractFileFormat* AbstractFileFormat::fileFormatFromType( const QString fileType) { if (fileFormat.isMyFileType(fileType)) return &fileFormat; if (pdmlFileFormat.isMyFileType(fileType)) return &pdmlFileFormat; if (pcapFileFormat.isMyFileType(fileType)) return &pcapFileFormat; return NULL; } void AbstractFileFormat::cancel() { stop_ = true; } void AbstractFileFormat::run() { if (op_ == kOpen) result_ = openStreams(fileName_, *openStreams_, *error_); else if (op_ == kSave) result_ = saveStreams(saveStreams_, fileName_, *error_); } ostinato-0.5.1/common/abstractfileformat.h0000700000175300010010000000435712005505614020216 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _ABSTRACT_FILE_FORMAT_H #define _ABSTRACT_FILE_FORMAT_H #include "protocol.pb.h" #include #include class QDialog; class AbstractFileFormat : public QThread { Q_OBJECT public: AbstractFileFormat(); virtual ~AbstractFileFormat(); virtual bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) = 0; virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) = 0; virtual QDialog* openOptionsDialog(); virtual QDialog* saveOptionsDialog(); void openStreamsOffline(const QString fileName, OstProto::StreamConfigList &streams, QString &error); void saveStreamsOffline(const OstProto::StreamConfigList streams, const QString fileName, QString &error); bool result(); static QStringList supportedFileTypes(); static AbstractFileFormat* fileFormatFromFile(const QString fileName); static AbstractFileFormat* fileFormatFromType(const QString fileType); #if 0 bool isMyFileFormat(const QString fileName) = 0; bool isMyFileType(const QString fileType) = 0; #endif signals: void status(QString text); void target(int value); void progress(int value); public slots: void cancel(); protected: void run(); bool stop_; private: enum kOp { kOpen, kSave }; QString fileName_; OstProto::StreamConfigList *openStreams_; OstProto::StreamConfigList saveStreams_; QString *error_; kOp op_; bool result_; }; #endif ostinato-0.5.1/common/abstractprotocol.cpp0000700000175300010010000006501312005505614020256 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "abstractprotocol.h" #include "streambase.h" #include "protocollistiterator.h" /*! \class AbstractProtocol AbstractProtocol is the base abstract class which provides the interface for all protocols. All protocols supported by Ostinato are derived from AbstractProtocol. Apart from defining the interface for a protocol, it also provides sensible default implementations for methods so that the subclasses need not re-implement. It also provides convenience functions for subclasses to use such as methods to retrieve payload size, checksum etc. A subclass typically needs to reimplement the following methods - - name() - shortName() - createInstance() - protocolNumber() - protoDataCopyInto() [pure virtual] - protoDataCopyFrom() [pure virtual] - fieldCount() - fieldFlags() - fieldData() - setFieldData() - configWidget() [pure virtual] - loadConfigWidget() [pure virtual] - storeConfigWidget() [pure virtual] Depending on certain conditions, subclasses may need to reimplement the following additional methods - - protocolIdType() - protocolId() - protocolFrameSize() - isProtocolFrameValueVariable() - isProtocolFrameSizeVariable() - protocolFrameVariableCount() See the description of the methods for more information. Most of the above methods just need some standard boilerplate code - the SampleProtocol implementation includes the boilerplate */ /*! Constructs an abstract protocol for the given stream and parent parent is typically NULL except for protocols which are part of a ComboProtocol */ AbstractProtocol::AbstractProtocol(StreamBase *stream, AbstractProtocol *parent) { //qDebug("%s: &prev = %p &next = %p", __FUNCTION__, &prev, &next); mpStream = stream; this->parent = parent; prev = next = NULL; _metaFieldCount = -1; _frameFieldCount = -1; protoSize = -1; _hasPayload = true; } /*! Destroys the abstract protocol */ AbstractProtocol::~AbstractProtocol() { } /*! Allocates and returns a new instance of the class. Caller is responsible for freeing up after use. Subclasses MUST implement this function */ AbstractProtocol* AbstractProtocol::createInstance(StreamBase* /* stream */, AbstractProtocol* /* parent */) { return NULL; } /*! Returns the protocol's field number as defined in message 'Protocol', enum 'k' (file: protocol.proto) Subclasses MUST implement this function */ quint32 AbstractProtocol::protocolNumber() const { qFatal("Something wrong!!!"); return 0xFFFFFFFF; } /*! \fn virtual void AbstractProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const = 0 Copy the protocol's protobuf as an extension into the passed in protocol In the base class this is a pure virtual function. Subclasses MUST implement this function. See the SampleProtocol for an example */ /*! \fn virtual void AbstractProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) = 0 Copy and update the protocol's protobuf member data variable from the passed in protocol In the base class this is a pure virtual function. Subclasses MUST implement this function. See the SampleProtocol for an example */ /*! Returns the full name of the protocol The default implementation returns a null string */ QString AbstractProtocol::name() const { return QString(); } /*! Returns the short name or abbreviation of the protocol The default implementation forms and returns an abbreviation composed of all the upper case chars in name() \n The default implementation caches the abbreviation on its first invocation and subsequently returns the cached abbreviation */ QString AbstractProtocol::shortName() const { if (protoAbbr.isNull()) { QString abbr; for (int i = 0; i < name().size(); i++) if (name().at(i).isUpper()) abbr.append(name().at(i)); if (abbr.size()) protoAbbr = abbr; else protoAbbr = QString(""); } return protoAbbr; } /*! Returns the number of fields in the protocol (both Frame fields and Meta fields) The default implementation returns zero. Subclasses MUST implement this function. */ int AbstractProtocol::fieldCount() const { return 0; } /*! Returns the number of meta fields The default implementation counts and returns the number of fields for which the MetaField flag is set\n The default implementation caches the count on its first invocation and subsequently returns the cached count */ int AbstractProtocol::metaFieldCount() const { if (_metaFieldCount < 0) { int c = 0; for (int i = 0; i < fieldCount() ; i++) if (fieldFlags(i).testFlag(MetaField)) c++; _metaFieldCount = c; } return _metaFieldCount; } /*! Returns the number of frame fields The default implementation counts and returns the number of fields for which the FrameField flag is set\n The default implementation caches the count on its first invocation and subsequently returns the cached count Subclasses which export different sets of fields based on a opcode/type (e.g. icmp) should re-implement this function */ int AbstractProtocol::frameFieldCount() const { if (_frameFieldCount < 0) { int c = 0; for (int i = 0; i < fieldCount() ; i++) if (fieldFlags(i).testFlag(FrameField)) c++; _frameFieldCount = c; } return _frameFieldCount; } /*! Returns the field flags for the passed in field index The default implementation assumes all fields to be frame fields and returns 'FrameField'. Subclasses must reimplement this method if they have any meta fields or checksum fields. See the SampleProtocol for an example. */ AbstractProtocol::FieldFlags AbstractProtocol::fieldFlags(int /*index*/) const { return FrameField; } /*! Returns the requested field attribute data Protocols which have meta fields that vary a frame field across streams may use the streamIndex to return the appropriate field value \n Some field attributes e.g. FieldName may be invariant across streams\n The FieldTextValue attribute may include additional information about the field's value e.g. a checksum field may include "(correct)" or "(incorrect)" alongwith the actual checksum value. \n The default implementation returns a empty string for FieldName and FieldTextValue; empty byte array of size 0 for FieldFrameValue; 0 for FieldValue; subclasses are expected to return meaning values for all these attributes. The only exception is the 'FieldBitSize' attribute - the default implementation takes the (byte) size of FieldFrameValue, multiplies it with 8 and returns the result - this can be used by subclasses for fields which are an integral multiple of bytes; for fields whose size are a non-integral multiple of bytes or smaller than a byte, subclasses should return the correct value. Also for fields which represent checksums, subclasses should return a value for FieldBitSize - even if it is an integral multiple of bytes. \note If a subclass uses any of the below functions to derive FieldFrameValue, the subclass should handle and return a value for FieldBitSize to prevent endless recursion - - protocolFrameCksum() - protocolFramePayloadSize() */ QVariant AbstractProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (attrib) { case FieldName: return QString(); case FieldBitSize: Q_ASSERT_X(!fieldFlags(index).testFlag(CksumField), "AbstractProtocol::fieldData()", "FieldBitSize for checksum fields need to be handled by the subclass"); return fieldData(index, FieldFrameValue, streamIndex). toByteArray().size() * 8; case FieldValue: return 0; case FieldFrameValue: return QByteArray(); case FieldTextValue: return QString(); default: qFatal("%s:%d: unhandled case %d\n", __FUNCTION__, __LINE__, attrib); } return QVariant(); } /*! Sets the value of a field corresponding to index This method is called by the GUI code to store a user specified value into the protocol's protoBuf. Currently this method is called with FieldAttrib = FieldValue only. Returns true if field is successfully set, false otherwise. The default implementation always returns false. Subclasses should reimplement this method. See SampleProtocol for an example. */ bool AbstractProtocol::setFieldData(int /*index*/, const QVariant& /*value*/, FieldAttrib /*attrib*/) { return false; } /*! Returns the protocolIdType for the protocol The default implementation returns ProtocolIdNone. If a subclass has a protocolId field it should return the appropriate value e.g. IP protocol will return ProtocolIdIp, Ethernet will return ProtocolIdEth etc. */ AbstractProtocol::ProtocolIdType AbstractProtocol::protocolIdType() const { return ProtocolIdNone; } /*! Returns the protocol id of the protocol for the given type The default implementation returns 0. If a subclass represents a protocol which has a particular protocol id, it should return the appropriate value. If a protocol does not have an id for the given type, it should defer to the base class. e.g. IGMP will return 2 for ProtocolIdIp, and defer to the base class for the remaining ProtocolIdTypes; IP will return 0x800 for ProtocolIdEth type, 0x060603 for ProtocolIdLlc and 0x04 for ProtocolIdIp etc. */ quint32 AbstractProtocol::protocolId(ProtocolIdType /*type*/) const { return 0; } /*! Returns the protocol id of the payload protocol (the protocol that immediately follows the current one) A subclass which has a protocol id field, can use this to retrieve the appropriate value */ quint32 AbstractProtocol::payloadProtocolId(ProtocolIdType type) const { quint32 id; if (next) id = next->protocolId(type); else if (parent) id = parent->payloadProtocolId(type); else id = 0xFFFFFFFF; qDebug("%s: payloadProtocolId = 0x%x", __FUNCTION__, id); return id; } /*! Returns the protocol's size in bytes The default implementation sums up the individual field bit sizes and returns it. The default implementation calculates the caches the size on the first invocation and subsequently returns the cached size. If the subclass protocol has a varying protocol size, it MUST reimplement this method, otherwise the default implementation is sufficient. */ int AbstractProtocol::protocolFrameSize(int streamIndex) const { if (protoSize < 0) { int bitsize = 0; for (int i = 0; i < fieldCount(); i++) { if (fieldFlags(i).testFlag(FrameField)) bitsize += fieldData(i, FieldBitSize, streamIndex).toUInt(); } protoSize = (bitsize+7)/8; } qDebug("%s: protoSize = %d", __FUNCTION__, protoSize); return protoSize; } /*! Returns the byte offset in the packet where the protocol starts This method is useful only for "padding" protocols i.e. protocols which fill up the remaining space for the user defined packet size e.g. the PatternPayload protocol */ int AbstractProtocol::protocolFrameOffset(int streamIndex) const { int size = 0; AbstractProtocol *p = prev; while (p) { size += p->protocolFrameSize(streamIndex); p = p->prev; } if (parent) size += parent->protocolFrameOffset(streamIndex); qDebug("%s: ofs = %d", __FUNCTION__, size); return size; } /*! Returns the size of the payload in bytes. The payload includes all protocols subsequent to the current This method is useful for protocols which need to fill in a payload size field */ int AbstractProtocol::protocolFramePayloadSize(int streamIndex) const { int size = 0; AbstractProtocol *p = next; while (p) { size += p->protocolFrameSize(streamIndex); p = p->next; } if (parent) size += parent->protocolFramePayloadSize(streamIndex); qDebug("%s: payloadSize = %d", __FUNCTION__, size); return size; } /*! Returns a byte array encoding the protocol (and its fields) which can be inserted into the stream's frame The default implementation forms and returns an ordered concatenation of the FrameValue of all the 'frame' fields of the protocol also taking care of fields which are not an integral number of bytes\n */ QByteArray AbstractProtocol::protocolFrameValue(int streamIndex, bool forCksum) const { QByteArray proto, field; uint bits, lastbitpos = 0; FieldFlags flags; for (int i=0; i < fieldCount() ; i++) { flags = fieldFlags(i); if (flags.testFlag(FrameField)) { bits = fieldData(i, FieldBitSize, streamIndex).toUInt(); if (bits == 0) continue; Q_ASSERT(bits > 0); if (forCksum && flags.testFlag(CksumField)) { field.resize((bits+7)/8); field.fill('\0'); } else field = fieldData(i, FieldFrameValue, streamIndex).toByteArray(); qDebug("<<< (%d, %db) %s >>>", proto.size(), lastbitpos, QString(proto.toHex()).toAscii().constData()); qDebug(" < %d: (%db/%dB) %s >", i, bits, field.size(), QString(field.toHex()).toAscii().constData()); if (bits == (uint) field.size() * 8) { if (lastbitpos == 0) proto.append(field); else { Q_ASSERT(field.size() > 0); char c = proto[proto.size() - 1]; proto[proto.size() - 1] = c | ((uchar)field.at(0) >> lastbitpos); for (int j = 0; j < field.size() - 1; j++) proto.append(field.at(j) << lastbitpos | (uchar)field.at(j+1) >> lastbitpos); proto.append(field.at(field.size() - 1) << lastbitpos); } } else if (bits < (uint) field.size() * 8) { uchar c; uint v; v = (field.size()*8) - bits; Q_ASSERT(v < 8); if (lastbitpos == 0) { for (int j = 0; j < field.size(); j++) { c = field.at(j) << v; if ((j+1) < field.size()) c |= ((uchar)field.at(j+1) >> (8-v)); proto.append(c); } lastbitpos = (lastbitpos + bits) % 8; } else { Q_ASSERT(proto.size() > 0); for (int j = 0; j < field.size(); j++) { uchar d; c = field.at(j) << v; if ((j+1) < field.size()) c |= ((uchar) field.at(j+1) >> (8-v)); d = proto[proto.size() - 1]; proto[proto.size() - 1] = d | ((uchar) c >> lastbitpos); if (bits > (8*j + (8 - v))) proto.append(c << (8-lastbitpos)); } lastbitpos = (lastbitpos + bits) % 8; } } else // if (bits > field.size() * 8) { qFatal("bitsize more than FrameValue size. skipping..."); continue; } } } return proto; } /*! Returns true if the protocol varies one or more of its fields at run-time, false otherwise The default implementation returns false. A subclass should reimplement if it has varying fields e.g. an IP protocol that increments/decrements the IP address with every packet */ bool AbstractProtocol::isProtocolFrameValueVariable() const { return (protocolFrameVariableCount() > 1); } /*! Returns true if the protocol varies its size at run-time, false otherwise The default implmentation returns false. A subclass should reimplement if it varies its size at run-time e.g. a Payload protocol for a stream with incrementing/decrementing frame lengths */ bool AbstractProtocol::isProtocolFrameSizeVariable() const { return false; } /*! Returns the minimum number of frames required for the protocol to vary its fields This is the lowest common multiple (LCM) of the counts of all the varying fields in the protocol. Use the AbstractProtocol::lcm() static utility function to calculate the LCM. The default implementation returns 1 implying that the protocol has no varying fields. A subclass should reimplement if it has varying fields e.g. an IP protocol that increments/decrements the IP address with every packet */ int AbstractProtocol::protocolFrameVariableCount() const { return 1; } /*! Returns true if the payload content for a protocol varies at run-time, false otherwise This is useful for subclasses which have fields dependent on payload content (e.g. UDP has a checksum field that varies if the payload varies) */ bool AbstractProtocol::isProtocolFramePayloadValueVariable() const { AbstractProtocol *p = next; while (p) { if (p->isProtocolFrameValueVariable()) return true; p = p->next; } if (parent && parent->isProtocolFramePayloadValueVariable()) return true; return false; } /*! Returns true if the payload size for a protocol varies at run-time, false otherwise This is useful for subclasses which have fields dependent on payload size (e.g. UDP has a checksum field that varies if the payload varies) */ bool AbstractProtocol::isProtocolFramePayloadSizeVariable() const { AbstractProtocol *p = next; while (p) { if (p->isProtocolFrameSizeVariable()) return true; p = p->next; } if (parent && parent->isProtocolFramePayloadSizeVariable()) return true; return false; } /*! Returns true if the payload size for a protocol varies at run-time, false otherwise This is useful for subclasses which have fields dependent on payload size (e.g. UDP has a checksum field that varies if the payload varies) */ int AbstractProtocol::protocolFramePayloadVariableCount() const { int count = 1; AbstractProtocol *p = next; while (p) { if (p->isProtocolFrameValueVariable() || p->isProtocolFrameSizeVariable()) count = lcm(count, p->protocolFrameVariableCount()); p = p->next; } if (parent && (parent->isProtocolFramePayloadValueVariable() || parent->isProtocolFramePayloadSizeVariable())) count = lcm(count, parent->protocolFramePayloadVariableCount()); return false; } /*! Returns true if the protocol typically contains a payload or other protocols following it e.g. TCP, UDP have payloads, while ARP, IGMP do not The default implementation returns true. If a subclass does not have a payload, it should set the _hasPayload data member to false */ bool AbstractProtocol::protocolHasPayload() const { return _hasPayload; } /*! Returns the checksum (of the requested type) of the protocol's contents Useful for protocols which have a checksum field \note If a subclass uses protocolFrameCksum() from within fieldData() to derive a cksum field, it MUST handle and return the 'FieldBitSize' attribute also for that particular field instead of using the default AbstractProtocol implementation for 'FieldBitSize' - this is required to prevent infinite recursion */ quint32 AbstractProtocol::protocolFrameCksum(int streamIndex, CksumType cksumType) const { static int recursionCount = 0; quint32 cksum = 0xFFFFFFFF; recursionCount++; Q_ASSERT_X(recursionCount < 10, "protocolFrameCksum", "potential infinite recursion - does a protocol checksum field not implement FieldBitSize?"); switch(cksumType) { case CksumIp: { QByteArray fv; quint16 *ip; quint32 len, sum = 0; fv = protocolFrameValue(streamIndex, true); ip = (quint16*) fv.constData(); len = fv.size(); while(len > 1) { sum += *ip; if(sum & 0x80000000) sum = (sum & 0xFFFF) + (sum >> 16); ip++; len -= 2; } if (len) sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); cksum = qFromBigEndian((quint16) ~sum); break; } case CksumTcpUdp: { quint16 cks; quint32 sum = 0; cks = protocolFrameCksum(streamIndex, CksumIp); sum += (quint16) ~cks; cks = protocolFramePayloadCksum(streamIndex, CksumIp); sum += (quint16) ~cks; cks = protocolFrameHeaderCksum(streamIndex, CksumIpPseudo); sum += (quint16) ~cks; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); cksum = (~sum) & 0xFFFF; break; } default: break; } recursionCount--; return cksum; } /*! Returns the checksum of the requested type for the protocol's header This is useful for subclasses which needs the header's checksum e.g. TCP/UDP require a "Pseudo-IP" checksum. The checksum is limited to the specified scope. Currently the default implementation supports only type CksumIpPseudo \note The default value for cksumScope is different for protocolFrameHeaderCksum() and protocolFramePayloadCksum() */ quint32 AbstractProtocol::protocolFrameHeaderCksum(int streamIndex, CksumType cksumType, CksumScope cksumScope) const { quint32 sum = 0; quint16 cksum; AbstractProtocol *p = prev; Q_ASSERT(cksumType == CksumIpPseudo); while (p) { cksum = p->protocolFrameCksum(streamIndex, cksumType); sum += (quint16) ~cksum; qDebug("%s: sum = %u, cksum = %u", __FUNCTION__, sum, cksum); if (cksumScope == CksumScopeAdjacentProtocol) goto out; p = p->prev; } if (parent) { cksum = parent->protocolFrameHeaderCksum(streamIndex, cksumType, cksumScope); sum += (quint16) ~cksum; } out: while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return (quint16) ~sum; } /*! Returns the checksum of the requested type for the protocol's payload This is useful for subclasses which needs the payload's checksum e.g. TCP/UDP require a IP checksum of the payload (to be combined with other checksums to derive the final checksum). The checksum is limited to the specified scope. Currently the default implementation supports only type CksumIp \note The default value for cksumScope is different for protocolFrameHeaderCksum() and protocolFramePayloadCksum() */ quint32 AbstractProtocol::protocolFramePayloadCksum(int streamIndex, CksumType cksumType, CksumScope cksumScope) const { quint32 sum = 0; quint16 cksum; AbstractProtocol *p = next; Q_ASSERT(cksumType == CksumIp); while (p) { cksum = p->protocolFrameCksum(streamIndex, cksumType); sum += (quint16) ~cksum; if (cksumScope == CksumScopeAdjacentProtocol) goto out; p = p->next; } if (parent) { cksum = parent->protocolFramePayloadCksum(streamIndex, cksumType, cksumScope); sum += (quint16) ~cksum; } out: while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return (quint16) ~sum; } /*! \fn virtual QWidget* AbstractProtocol::configWidget() = 0; Returns the configuration widget for the protocol. The protocol retains ownership of the configuration widget - the caller should not free it. In the base class this is a pure virtual function. Subclasses MUST implement this function. See the SampleProtocol for an example */ /*! \fn virtual void AbstractProtocol::loadConfigWidget() = 0; Loads data from the protocol's protobuf into the configuration widget of the protocol In the base class this is a pure virtual function. Subclasses MUST implement this function. See the SampleProtocol for an example */ /*! \fn virtual void AbstractProtocol::storeConfigWidget() = 0; Stores data from the configuration widget of the protocol into the protocol's protobuf In the base class this is a pure virtual function. Subclasses MUST implement this function. See the SampleProtocol for an example */ // Stein's binary GCD algo - from wikipedia quint64 AbstractProtocol::gcd(quint64 u, quint64 v) { int shift; /* GCD(0,x) := x */ if (u == 0 || v == 0) return u | v; /* Let shift := lg K, where K is the greatest power of 2 dividing both u and v. */ for (shift = 0; ((u | v) & 1) == 0; ++shift) { u >>= 1; v >>= 1; } while ((u & 1) == 0) u >>= 1; /* From here on, u is always odd. */ do { while ((v & 1) == 0) /* Loop X */ v >>= 1; /* Now u and v are both odd, so diff(u, v) is even. Let u = min(u, v), v = diff(u, v)/2. */ if (u < v) { v -= u; } else { quint64 diff = u - v; u = v; v = diff; } v >>= 1; } while (v != 0); return u << shift; } quint64 AbstractProtocol::lcm(quint64 u, quint64 v) { #if 0 /* LCM(0,x) := x */ if (u == 0 || v == 0) return u | v; #else /* For our use case, neither u nor v can ever be 0, the minimum value is 1; we do this correction silently here */ if (u == 0) u = 1; if (v == 0) v = 1; if (u == 1 || v == 1) return (u * v); #endif return (u * v)/gcd(u, v); } ostinato-0.5.1/common/abstractprotocol.h0000700000175300010010000001322212005505614017716 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _ABSTRACT_PROTOCOL_H #define _ABSTRACT_PROTOCOL_H #include #include #include #include #include #include //#include "../rpc/pbhelper.h" #include "protocol.pb.h" #define BASE_BIN (2) #define BASE_OCT (8) #define BASE_DEC (10) #define BASE_HEX (16) #define uintToHexStr(num, bytes) \ QString("%1").arg(num, bytes*2, BASE_HEX, QChar('0')) class StreamBase; class ProtocolListIterator; class AbstractProtocol { template friend class ComboProtocol; friend class ProtocolListIterator; private: mutable int _metaFieldCount; mutable int _frameFieldCount; mutable int protoSize; mutable QString protoAbbr; protected: StreamBase *mpStream; //!< Stream that this protocol belongs to AbstractProtocol *parent; //!< Parent protocol, if any AbstractProtocol *prev; //!< Protocol preceding this protocol AbstractProtocol *next; //!< Protocol succeeding this protocol //! Is protocol typically followed by payload or another protocol bool _hasPayload; public: //! Properties of a field, can be OR'd enum FieldFlag { FrameField = 0x1, //!< field appears in frame content MetaField = 0x2, //!< field does not appear in frame, is meta data CksumField = 0x4 //!< field is a checksum and appears in frame content }; Q_DECLARE_FLAGS(FieldFlags, FieldFlag); //!< \private abcd //! Various attributes of a field enum FieldAttrib { FieldName, //!< name FieldValue, //!< value in host byte order (user editable) FieldTextValue, //!< value as text FieldFrameValue, //!< frame encoded value in network byte order FieldBitSize, //!< size in bits }; //! Supported Protocol Id types enum ProtocolIdType { ProtocolIdNone, //!< Marker representing non-existent protocol id ProtocolIdLlc, //!< LLC (802.2) ProtocolIdEth, //!< Ethernet II ProtocolIdIp, //!< IP ProtocolIdTcpUdp, //!< TCP/UDP Port Number }; //! Supported checksum types enum CksumType { CksumIp, //!< Standard IP Checksum CksumIpPseudo, //!< Standard checksum for Pseudo-IP header CksumTcpUdp, //!< Standard TCP/UDP checksum including pseudo-IP CksumMax //!< Marker for number of cksum types }; //! Supported checksum scopes enum CksumScope { CksumScopeAdjacentProtocol, //!< Cksum only the adjacent protocol CksumScopeAllProtocols, //!< Cksum over all the protocols }; AbstractProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~AbstractProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const = 0; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol) = 0; virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; quint32 payloadProtocolId(ProtocolIdType type) const; virtual int fieldCount() const; int metaFieldCount() const; virtual int frameFieldCount() const; virtual FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); QByteArray protocolFrameValue(int streamIndex = 0, bool forCksum = false) const; virtual int protocolFrameSize(int streamIndex = 0) const; int protocolFrameOffset(int streamIndex = 0) const; int protocolFramePayloadSize(int streamIndex = 0) const; virtual bool isProtocolFrameValueVariable() const; virtual bool isProtocolFrameSizeVariable() const; virtual int protocolFrameVariableCount() const; bool isProtocolFramePayloadValueVariable() const; bool isProtocolFramePayloadSizeVariable() const; int protocolFramePayloadVariableCount() const; bool protocolHasPayload() const; virtual quint32 protocolFrameCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; quint32 protocolFrameHeaderCksum(int streamIndex = 0, CksumType cksumType = CksumIp, CksumScope cksumScope = CksumScopeAdjacentProtocol) const; quint32 protocolFramePayloadCksum(int streamIndex = 0, CksumType cksumType = CksumIp, CksumScope cksumScope = CksumScopeAllProtocols) const; virtual QWidget* configWidget() = 0; virtual void loadConfigWidget() = 0; virtual void storeConfigWidget() = 0; static quint64 lcm(quint64 u, quint64 v); static quint64 gcd(quint64 u, quint64 v); }; Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractProtocol::FieldFlags); #endif ostinato-0.5.1/common/arp.cpp0000700000175300010010000007631112005505614015456 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "arp.h" ArpConfigForm::ArpConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); opCodeCombo->setValidator(new QIntValidator(0, 0xFFFF, this)); opCodeCombo->addItem(1, "ARP Request"); opCodeCombo->addItem(2, "ARP Reply"); connect(senderHwAddrMode, SIGNAL(currentIndexChanged(int)), SLOT(on_senderHwAddrMode_currentIndexChanged(int))); connect(senderProtoAddrMode, SIGNAL(currentIndexChanged(int)), SLOT(on_senderProtoAddrMode_currentIndexChanged(int))); connect(targetHwAddrMode, SIGNAL(currentIndexChanged(int)), SLOT(on_targetHwAddrMode_currentIndexChanged(int))); connect(targetProtoAddrMode, SIGNAL(currentIndexChanged(int)), SLOT(on_targetProtoAddrMode_currentIndexChanged(int))); } void ArpConfigForm::on_senderHwAddrMode_currentIndexChanged(int index) { if (index == OstProto::Arp::kFixed) senderHwAddrCount->setDisabled(true); else senderHwAddrCount->setEnabled(true); } void ArpConfigForm::on_targetHwAddrMode_currentIndexChanged(int index) { if (index == OstProto::Arp::kFixed) targetHwAddrCount->setDisabled(true); else targetHwAddrCount->setEnabled(true); } void ArpConfigForm::on_senderProtoAddrMode_currentIndexChanged(int index) { if (index == OstProto::Arp::kFixedHost) { senderProtoAddrCount->setDisabled(true); senderProtoAddrMask->setDisabled(true); } else { senderProtoAddrCount->setEnabled(true); senderProtoAddrMask->setEnabled(true); } } void ArpConfigForm::on_targetProtoAddrMode_currentIndexChanged(int index) { if (index == OstProto::Arp::kFixedHost) { targetProtoAddrCount->setDisabled(true); targetProtoAddrMask->setDisabled(true); } else { targetProtoAddrCount->setEnabled(true); targetProtoAddrMask->setEnabled(true); } } ArpProtocol::ArpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { _hasPayload = false; configForm = NULL; } ArpProtocol::~ArpProtocol() { delete configForm; } AbstractProtocol* ArpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new ArpProtocol(stream, parent); } quint32 ArpProtocol::protocolNumber() const { return OstProto::Protocol::kArpFieldNumber; } void ArpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::arp)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void ArpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::arp)) data.MergeFrom(protocol.GetExtension(OstProto::arp)); } QString ArpProtocol::name() const { return QString("Address Resolution Protocol"); } QString ArpProtocol::shortName() const { return QString("ARP"); } /*! Return the ProtocolIdType for your protocol \n If your protocol doesn't have a protocolId field, you don't need to reimplement this method - the base class implementation will do the right thing */ #if 0 AbstractProtocol::ProtocolIdType ArpProtocol::protocolIdType() const { return ProtocolIdIp; } #endif /*! Return the protocolId for your protocol based on the 'type' requested \n If not all types are valid for your protocol, handle the valid type(s) and for the remaining fallback to the base class implementation; if your protocol doesn't have a protocolId at all, you don't need to reimplement this method - the base class will do the right thing */ quint32 ArpProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdEth: return 0x0806; default:break; } return AbstractProtocol::protocolId(type); } int ArpProtocol::fieldCount() const { return arp_fieldCount; } AbstractProtocol::FieldFlags ArpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case arp_hwType: case arp_protoType: case arp_hwAddrLen: case arp_protoAddrLen: case arp_opCode: case arp_senderHwAddr: case arp_senderProtoAddr: case arp_targetHwAddr: case arp_targetProtoAddr: break; case arp_senderHwAddrMode: case arp_senderHwAddrCount: case arp_senderProtoAddrMode: case arp_senderProtoAddrCount: case arp_senderProtoAddrMask: case arp_targetHwAddrMode: case arp_targetHwAddrCount: case arp_targetProtoAddrMode: case arp_targetProtoAddrCount: case arp_targetProtoAddrMask: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant ArpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case arp_hwType: { switch(attrib) { case FieldName: return QString("Hardware Type"); case FieldValue: return data.hw_type(); case FieldTextValue: return QString("%1").arg(data.hw_type()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.hw_type(), (uchar*) fv.data()); return fv; } default: break; } break; } case arp_protoType: { switch(attrib) { case FieldName: return QString("Protocol Type"); case FieldValue: return data.proto_type(); case FieldTextValue: return QString("%1").arg(data.proto_type(), 4, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.proto_type(), (uchar*) fv.data()); return fv; } default: break; } break; } case arp_hwAddrLen: { switch(attrib) { case FieldName: return QString("Hardware Address Length"); case FieldValue: return data.hw_addr_len(); case FieldTextValue: return QString("%1").arg(data.hw_addr_len()); case FieldFrameValue: return QByteArray(1, (char) data.hw_addr_len()); default: break; } break; } case arp_protoAddrLen: { switch(attrib) { case FieldName: return QString("Protocol Address Length"); case FieldValue: return data.proto_addr_len(); case FieldTextValue: return QString("%1").arg(data.proto_addr_len()); case FieldFrameValue: return QByteArray(1, (char) data.proto_addr_len()); default: break; } break; } case arp_opCode: { switch(attrib) { case FieldName: return QString("Operation Code"); case FieldValue: return data.op_code(); case FieldTextValue: return QString("%1").arg(data.op_code()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.op_code(), (uchar*) fv.data()); return fv; } default: break; } break; } case arp_senderHwAddr: { int u; const int hwAddrStep = 1; quint64 hwAddr = 0; switch (data.sender_hw_addr_mode()) { case OstProto::Arp::kFixed: hwAddr = data.sender_hw_addr(); break; case OstProto::Arp::kIncrement: u = (streamIndex % data.sender_hw_addr_count()) * hwAddrStep; hwAddr = data.sender_hw_addr() + u; break; case OstProto::Arp::kDecrement: u = (streamIndex % data.sender_hw_addr_count()) * hwAddrStep; hwAddr = data.sender_hw_addr() - u; break; default: qWarning("Unhandled hw_addr_mode %d", data.sender_hw_addr_mode()); } switch(attrib) { case FieldName: return QString("Sender Hardware Address"); case FieldValue: return hwAddr; case FieldTextValue: return uintToHexStr(hwAddr, 6); case FieldFrameValue: { QByteArray fv; fv.resize(8); qToBigEndian((quint64) hwAddr, (uchar*) fv.data()); fv.remove(0, 2); return fv; } default: break; } break; } case arp_senderProtoAddr: { int u; quint32 subnet, host, protoAddr = 0; switch(data.sender_proto_addr_mode()) { case OstProto::Arp::kFixedHost: protoAddr = data.sender_proto_addr(); break; case OstProto::Arp::kIncrementHost: u = streamIndex % data.sender_proto_addr_count(); subnet = data.sender_proto_addr() & data.sender_proto_addr_mask(); host = (((data.sender_proto_addr() & ~data.sender_proto_addr_mask()) + u) & ~data.sender_proto_addr_mask()); protoAddr = subnet | host; break; case OstProto::Arp::kDecrementHost: u = streamIndex % data.sender_proto_addr_count(); subnet = data.sender_proto_addr() & data.sender_proto_addr_mask(); host = (((data.sender_proto_addr() & ~data.sender_proto_addr_mask()) - u) & ~data.sender_proto_addr_mask()); protoAddr = subnet | host; break; case OstProto::Arp::kRandomHost: subnet = data.sender_proto_addr() & data.sender_proto_addr_mask(); host = (qrand() & ~data.sender_proto_addr_mask()); protoAddr = subnet | host; break; default: qWarning("Unhandled sender_proto_addr_mode = %d", data.sender_proto_addr_mode()); } switch(attrib) { case FieldName: return QString("Sender Protocol Address"); case FieldValue: return protoAddr; case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) protoAddr, (uchar*) fv.data()); return fv; } case FieldTextValue: return QHostAddress(protoAddr).toString(); default: break; } break; } case arp_targetHwAddr: { int u; const int hwAddrStep = 1; quint64 hwAddr = 0; switch (data.target_hw_addr_mode()) { case OstProto::Arp::kFixed: hwAddr = data.target_hw_addr(); break; case OstProto::Arp::kIncrement: u = (streamIndex % data.target_hw_addr_count()) * hwAddrStep; hwAddr = data.target_hw_addr() + u; break; case OstProto::Arp::kDecrement: u = (streamIndex % data.target_hw_addr_count()) * hwAddrStep; hwAddr = data.target_hw_addr() - u; break; default: qWarning("Unhandled hw_addr_mode %d", data.target_hw_addr_mode()); } switch(attrib) { case FieldName: return QString("Target Hardware Address"); case FieldValue: return hwAddr; case FieldTextValue: return uintToHexStr(hwAddr, 6); case FieldFrameValue: { QByteArray fv; fv.resize(8); qToBigEndian((quint64) hwAddr, (uchar*) fv.data()); fv.remove(0, 2); return fv; } default: break; } break; } case arp_targetProtoAddr: { int u; quint32 subnet, host, protoAddr = 0; switch(data.target_proto_addr_mode()) { case OstProto::Arp::kFixed: protoAddr = data.target_proto_addr(); break; case OstProto::Arp::kIncrementHost: u = streamIndex % data.target_proto_addr_count(); subnet = data.target_proto_addr() & data.target_proto_addr_mask(); host = (((data.target_proto_addr() & ~data.target_proto_addr_mask()) + u) & ~data.target_proto_addr_mask()); protoAddr = subnet | host; break; case OstProto::Arp::kDecrementHost: u = streamIndex % data.target_proto_addr_count(); subnet = data.target_proto_addr() & data.target_proto_addr_mask(); host = (((data.target_proto_addr() & ~data.target_proto_addr_mask()) - u) & ~data.target_proto_addr_mask()); protoAddr = subnet | host; break; case OstProto::Arp::kRandomHost: subnet = data.target_proto_addr() & data.target_proto_addr_mask(); host = (qrand() & ~data.target_proto_addr_mask()); protoAddr = subnet | host; break; default: qWarning("Unhandled target_proto_addr_mode = %d", data.target_proto_addr_mode()); } switch(attrib) { case FieldName: return QString("Target Protocol Address"); case FieldValue: return protoAddr; case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) protoAddr, (uchar*) fv.data()); return fv; } case FieldTextValue: return QHostAddress(protoAddr).toString(); default: break; } break; } // Meta fields case arp_senderHwAddrMode: switch(attrib) { case FieldName: return QString("Sender Hardware Address Mode"); case FieldValue: return data.sender_hw_addr_mode(); default: break; } break; case arp_senderHwAddrCount: switch(attrib) { case FieldName: return QString("Sender Hardware Address Count"); case FieldValue: return data.sender_hw_addr_count(); default: break; } break; case arp_senderProtoAddrMode: switch(attrib) { case FieldName: return QString("Sender Protocol Address Mode"); case FieldValue: return data.sender_proto_addr_mode(); default: break; } break; case arp_senderProtoAddrCount: switch(attrib) { case FieldName: return QString("Sender Protocol Address Count"); case FieldValue: return data.sender_proto_addr_count(); default: break; } break; case arp_senderProtoAddrMask: switch(attrib) { case FieldName: return QString("Sender Protocol Address Mask"); case FieldValue: return data.sender_proto_addr_mask(); default: break; } break; case arp_targetHwAddrMode: switch(attrib) { case FieldName: return QString("Target Hardware Address Mode"); case FieldValue: return data.target_hw_addr_mode(); default: break; } break; case arp_targetHwAddrCount: switch(attrib) { case FieldName: return QString("Target Hardware Address Count"); case FieldValue: return data.target_hw_addr_count(); default: break; } break; case arp_targetProtoAddrMode: switch(attrib) { case FieldName: return QString("Target Protocol Address Mode"); case FieldValue: return data.target_proto_addr_mode(); default: break; } break; case arp_targetProtoAddrCount: switch(attrib) { case FieldName: return QString("Target Protocol Address Count"); case FieldValue: return data.target_proto_addr_count(); default: break; } break; case arp_targetProtoAddrMask: switch(attrib) { case FieldName: return QString("Target Protocol Address Mask"); case FieldValue: return data.target_proto_addr_mask(); default: break; } break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool ArpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case arp_hwType: { uint hwType = value.toUInt(&isOk); if (isOk) data.set_hw_type(hwType); break; } case arp_protoType: { uint protoType = value.toUInt(&isOk); if (isOk) data.set_proto_type(protoType); break; } case arp_hwAddrLen: { uint hwAddrLen = value.toUInt(&isOk); if (isOk) data.set_hw_addr_len(hwAddrLen); break; } case arp_protoAddrLen: { uint protoAddrLen = value.toUInt(&isOk); if (isOk) data.set_proto_addr_len(protoAddrLen); break; } case arp_opCode: { uint opCode = value.toUInt(&isOk); if (isOk) data.set_op_code(opCode); break; } case arp_senderHwAddr: { quint64 hwAddr = value.toULongLong(&isOk); if (isOk) data.set_sender_hw_addr(hwAddr); break; } case arp_senderHwAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.HwAddrMode_IsValid(mode)) data.set_sender_hw_addr_mode((OstProto::Arp::HwAddrMode) mode); else isOk = false; break; } case arp_senderHwAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_sender_hw_addr_count(count); break; } case arp_senderProtoAddr: { uint protoAddr = value.toUInt(&isOk); if (isOk) data.set_sender_proto_addr(protoAddr); break; } case arp_senderProtoAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.ProtoAddrMode_IsValid(mode)) data.set_sender_proto_addr_mode( (OstProto::Arp::ProtoAddrMode)mode); else isOk = false; break; } case arp_senderProtoAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_sender_proto_addr_count(count); break; } case arp_senderProtoAddrMask: { uint mask = value.toUInt(&isOk); if (isOk) data.set_sender_proto_addr_mask(mask); break; } case arp_targetHwAddr: { quint64 hwAddr = value.toULongLong(&isOk); if (isOk) data.set_target_hw_addr(hwAddr); break; } case arp_targetHwAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.HwAddrMode_IsValid(mode)) data.set_target_hw_addr_mode((OstProto::Arp::HwAddrMode)mode); else isOk = false; break; } case arp_targetHwAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_target_hw_addr_count(count); break; } case arp_targetProtoAddr: { uint protoAddr = value.toUInt(&isOk); if (isOk) data.set_target_proto_addr(protoAddr); break; } case arp_targetProtoAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.ProtoAddrMode_IsValid(mode)) data.set_target_proto_addr_mode( (OstProto::Arp::ProtoAddrMode)mode); else isOk = false; break; } case arp_targetProtoAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_target_proto_addr_count(count); break; } case arp_targetProtoAddrMask: { uint mask = value.toUInt(&isOk); if (isOk) data.set_target_proto_addr_mask(mask); break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } bool ArpProtocol::isProtocolFrameValueVariable() const { if (fieldData(arp_senderHwAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed) || fieldData(arp_senderProtoAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed) || fieldData(arp_targetHwAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed) || fieldData(arp_targetProtoAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed)) return true; return false; } int ArpProtocol::protocolFrameVariableCount() const { int count = 1; if (fieldData(arp_senderHwAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed)) { count = AbstractProtocol::lcm(count, fieldData(arp_senderHwAddrCount, FieldValue).toUInt()); } if (fieldData(arp_senderProtoAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed)) { count = AbstractProtocol::lcm(count, fieldData(arp_senderProtoAddrCount, FieldValue).toUInt()); } if (fieldData(arp_targetHwAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed)) { count = AbstractProtocol::lcm(count, fieldData(arp_targetHwAddrCount, FieldValue).toUInt()); } if (fieldData(arp_targetProtoAddrMode, FieldValue).toUInt() != uint(OstProto::Arp::kFixed)) { count = AbstractProtocol::lcm(count, fieldData(arp_targetProtoAddrCount, FieldValue).toUInt()); } return count; } QWidget* ArpProtocol::configWidget() { if (configForm == NULL) { configForm = new ArpConfigForm; loadConfigWidget(); } return configForm; } void ArpProtocol::loadConfigWidget() { configWidget(); configForm->hwType->setText( fieldData(arp_hwType, FieldValue).toString()); configForm->protoType->setText(uintToHexStr( fieldData(arp_protoType, FieldValue).toUInt(), 2)); configForm->hwAddrLen->setText( fieldData(arp_hwAddrLen, FieldValue).toString()); configForm->protoAddrLen->setText( fieldData(arp_protoAddrLen, FieldValue).toString()); configForm->opCodeCombo->setValue( fieldData(arp_opCode, FieldValue).toUInt()); configForm->senderHwAddr->setText(uintToHexStr( fieldData(arp_senderHwAddr, FieldValue).toULongLong(), 6)); configForm->senderHwAddrMode->setCurrentIndex( fieldData(arp_senderHwAddrMode, FieldValue).toUInt()); configForm->senderHwAddrCount->setText( fieldData(arp_senderHwAddrCount, FieldValue).toString()); configForm->senderProtoAddr->setText(QHostAddress( fieldData(arp_senderProtoAddr, FieldValue).toUInt()).toString()); configForm->senderProtoAddrMode->setCurrentIndex( fieldData(arp_senderProtoAddrMode, FieldValue).toUInt()); configForm->senderProtoAddrCount->setText( fieldData(arp_senderProtoAddrCount, FieldValue).toString()); configForm->senderProtoAddrMask->setText(QHostAddress( fieldData(arp_senderProtoAddrMask, FieldValue).toUInt()).toString()); configForm->targetHwAddr->setText(uintToHexStr( fieldData(arp_targetHwAddr, FieldValue).toULongLong(), 6)); configForm->targetHwAddrMode->setCurrentIndex( fieldData(arp_targetHwAddrMode, FieldValue).toUInt()); configForm->targetHwAddrCount->setText( fieldData(arp_targetHwAddrCount, FieldValue).toString()); configForm->targetProtoAddr->setText(QHostAddress( fieldData(arp_targetProtoAddr, FieldValue).toUInt()).toString()); configForm->targetProtoAddrMode->setCurrentIndex( fieldData(arp_targetProtoAddrMode, FieldValue).toUInt()); configForm->targetProtoAddrCount->setText( fieldData(arp_targetProtoAddrCount, FieldValue).toString()); configForm->targetProtoAddrMask->setText(QHostAddress( fieldData(arp_targetProtoAddrMask, FieldValue).toUInt()).toString()); } void ArpProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(arp_hwType, configForm->hwType->text()); setFieldData(arp_protoType, configForm->protoType->text().toUInt( &isOk, BASE_HEX)); setFieldData(arp_hwAddrLen, configForm->hwAddrLen->text()); setFieldData(arp_protoAddrLen, configForm->protoAddrLen->text()); setFieldData(arp_opCode, configForm->opCodeCombo->currentValue()); setFieldData(arp_senderHwAddr, configForm->senderHwAddr->text() .remove(QChar(' ')).toULongLong(&isOk, BASE_HEX)); setFieldData(arp_senderHwAddrMode, configForm->senderHwAddrMode->currentIndex()); setFieldData(arp_senderHwAddrCount, configForm->senderHwAddrCount->text()); setFieldData(arp_senderProtoAddr, QHostAddress( configForm->senderProtoAddr->text()).toIPv4Address()); setFieldData(arp_senderProtoAddrMode, configForm->senderProtoAddrMode->currentIndex()); setFieldData(arp_senderProtoAddrCount, configForm->senderProtoAddrCount->text()); setFieldData(arp_senderProtoAddrMask, QHostAddress( configForm->senderProtoAddrMask->text()).toIPv4Address()); setFieldData(arp_targetHwAddr, configForm->targetHwAddr->text() .remove(QChar(' ')).toULongLong(&isOk, BASE_HEX)); setFieldData(arp_targetHwAddrMode, configForm->targetHwAddrMode->currentIndex()); setFieldData(arp_targetHwAddrCount, configForm->targetHwAddrCount->text()); setFieldData(arp_targetProtoAddr, QHostAddress( configForm->targetProtoAddr->text()).toIPv4Address()); setFieldData(arp_targetProtoAddrMode, configForm->targetProtoAddrMode->currentIndex()); setFieldData(arp_targetProtoAddrCount, configForm->targetProtoAddrCount->text()); setFieldData(arp_targetProtoAddrMask, QHostAddress( configForm->targetProtoAddrMask->text()).toIPv4Address()); } ostinato-0.5.1/common/arp.h0000700000175300010010000000652612005505614015124 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _ARP_H #define _ARP_H #include "arp.pb.h" #include "ui_arp.h" #include "abstractprotocol.h" /* Arp Protocol Frame Format - +------+------+------+------+------+---------+-------+---------+-------+ | HTYP | PTYP | HLEN | PLEN | OPER | SHA | SPA | THA | TPA | | (2) | (2) | (1) | (1) | (2) | (6) | (4) | (6) | (4) | +------+------+------+------+------+---------+-------+---------+-------+ Figures in brackets represent field width in bytes */ class ArpConfigForm : public QWidget, public Ui::Arp { Q_OBJECT public: ArpConfigForm(QWidget *parent = 0); private slots: void on_senderHwAddrMode_currentIndexChanged(int index); void on_senderProtoAddrMode_currentIndexChanged(int index); void on_targetHwAddrMode_currentIndexChanged(int index); void on_targetProtoAddrMode_currentIndexChanged(int index); }; class ArpProtocol : public AbstractProtocol { private: OstProto::Arp data; ArpConfigForm *configForm; enum arpfield { // Frame Fields arp_hwType, arp_protoType, arp_hwAddrLen, arp_protoAddrLen, arp_opCode, arp_senderHwAddr, arp_senderProtoAddr, arp_targetHwAddr, arp_targetProtoAddr, // Meta Fields arp_senderHwAddrMode, arp_senderHwAddrCount, arp_senderProtoAddrMode, arp_senderProtoAddrCount, arp_senderProtoAddrMask, arp_targetHwAddrMode, arp_targetHwAddrCount, arp_targetProtoAddrMode, arp_targetProtoAddrCount, arp_targetProtoAddrMask, arp_fieldCount }; public: ArpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~ArpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/arp.proto0000700000175300010010000000421612005505614016032 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // ARP Protocol message Arp { enum HwAddrMode { kFixed = 0; kIncrement = 1; kDecrement = 2; } enum ProtoAddrMode { kFixedHost = 0; kIncrementHost = 1; kDecrementHost = 2; kRandomHost = 3; } optional uint32 hw_type = 1 [default = 1]; optional uint32 proto_type = 2 [default = 0x800]; optional uint32 hw_addr_len = 3 [default = 6]; optional uint32 proto_addr_len = 4 [default = 4]; optional uint32 op_code = 5 [default = 1]; // 1 => ARP Request optional uint64 sender_hw_addr = 6; optional HwAddrMode sender_hw_addr_mode = 7 [default = kFixed]; optional uint32 sender_hw_addr_count = 8 [default = 16]; optional uint32 sender_proto_addr = 9; optional ProtoAddrMode sender_proto_addr_mode = 10 [default = kFixedHost]; optional uint32 sender_proto_addr_count = 11 [default = 16]; optional fixed32 sender_proto_addr_mask = 12 [default = 0xFFFFFF00]; optional uint64 target_hw_addr = 13; optional HwAddrMode target_hw_addr_mode = 14 [default = kFixed]; optional uint32 target_hw_addr_count = 15 [default = 16]; optional uint32 target_proto_addr = 16; optional ProtoAddrMode target_proto_addr_mode = 17 [default = kFixedHost]; optional uint32 target_proto_addr_count = 18 [default = 16]; optional fixed32 target_proto_addr_mask = 19 [default = 0xFFFFFF00]; } extend Protocol { optional Arp arp = 300; } ostinato-0.5.1/common/arp.ui0000700000175300010010000003452712005505614015314 0ustar srivatspNone Arp 0 0 528 286 Form Hardware Type hwType false Hardware Address Length hwAddrLen false Protocol Type protoType false Protocol Address Length protoAddrLen false Operation Code 1 0 true QComboBox::NoInsert Qt::Horizontal 161 20 false Qt::Horizontal 101 20 Address Mode Count Mask Sender Hardware senderHwAddr >HH HH HH HH HH HH; Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Decrement false 255 0 Sender Protocol senderProtoAddr 009.009.009.009; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false 255 0 false 009.009.009.009; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Target Hardware targetHwAddr 120 0 >HH HH HH HH HH HH; Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Decrement false 255 0 0 Target Protocol targetProtoAddr 000.000.000.000; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false 255 0 false 009.009.009.009; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 61 IntComboBox QComboBox
intcombobox.h
hwType protoType hwAddrLen protoAddrLen senderHwAddr senderHwAddrMode senderHwAddrCount senderProtoAddr senderProtoAddrMode senderProtoAddrCount senderProtoAddrMask targetHwAddr targetHwAddrMode targetHwAddrCount targetProtoAddr targetProtoAddrMode targetProtoAddrCount targetProtoAddrMask
ostinato-0.5.1/common/comboprotocol.h0000700000175300010010000001470012005505614017214 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _COMBO_PROTOCOL_H #define _COMBO_PROTOCOL_H #include "abstractprotocol.h" template class ComboProtocol : public AbstractProtocol { protected: ProtoA *protoA; ProtoB *protoB; QWidget *configForm; public: ComboProtocol(StreamBase *stream, AbstractProtocol *parent = 0) : AbstractProtocol(stream, parent) { protoA = new ProtoA(stream, this); protoB = new ProtoB(stream, this); protoA->next = protoB; protoB->prev = protoA; configForm = NULL; qDebug("%s: protoNumber = %d, %p <--> %p", __FUNCTION__, protoNumber, protoA, protoB); } virtual ~ComboProtocol() { if (configForm) { protoA->configWidget()->setParent(0); protoB->configWidget()->setParent(0); delete configForm; } delete protoA; delete protoB; } static ComboProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent) { return new ComboProtocol(stream, parent); } virtual quint32 protocolNumber() const { return protoNumber; } virtual void protoDataCopyInto(OstProto::Protocol &protocol) const { protoA->protoDataCopyInto(protocol); protoB->protoDataCopyInto(protocol); protocol.mutable_protocol_id()->set_id(protocolNumber()); } virtual void protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber()) { OstProto::Protocol proto; // NOTE: To use protoX->protoDataCopyFrom() we need to arrange // so that it sees its own protocolNumber() - but since the // input param 'protocol' is 'const', we work on a copy proto.CopyFrom(protocol); proto.mutable_protocol_id()->set_id(protoA->protocolNumber()); protoA->protoDataCopyFrom(proto); proto.mutable_protocol_id()->set_id(protoB->protocolNumber()); protoB->protoDataCopyFrom(proto); } } virtual QString name() const { return protoA->name() + "/" + protoB->name(); } virtual QString shortName() const { return protoA->shortName() + "/" + protoB->shortName(); } virtual ProtocolIdType protocolIdType() const { return protoB->protocolIdType(); } virtual quint32 protocolId(ProtocolIdType type) const { return protoA->protocolId(type); } //quint32 payloadProtocolId(ProtocolIdType type) const; virtual int fieldCount() const { return protoA->fieldCount() + protoB->fieldCount(); } //virtual int metaFieldCount() const; //int frameFieldCount() const; virtual FieldFlags fieldFlags(int index) const { int cnt = protoA->fieldCount(); if (index < cnt) return protoA->fieldFlags(index); else return protoB->fieldFlags(index - cnt); } virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const { int cnt = protoA->fieldCount(); if (index < cnt) return protoA->fieldData(index, attrib, streamIndex); else return protoB->fieldData(index - cnt, attrib, streamIndex); } virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue) { int cnt = protoA->fieldCount(); if (index < cnt) return protoA->setFieldData(index, value, attrib); else return protoB->setFieldData(index - cnt, value, attrib); } #if 0 QByteArray protocolFrameValue(int streamIndex = 0, bool forCksum = false) const; virtual int protocolFrameSize() const; int protocolFrameOffset() const; int protocolFramePayloadSize() const; #endif virtual bool isProtocolFrameValueVariable() const { return (protoA->isProtocolFrameValueVariable() || protoB->isProtocolFrameValueVariable()); } virtual bool isProtocolFrameSizeVariable() const { return (protoA->isProtocolFrameSizeVariable() || protoB->isProtocolFrameSizeVariable()); } virtual int protocolFrameVariableCount() const { return AbstractProtocol::lcm( protoA->protocolFrameVariableCount(), protoB->protocolFrameVariableCount()); } virtual quint32 protocolFrameCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const { // For a Pseudo IP cksum, we assume it is the succeeding protocol // that is requesting it and hence return protoB's cksum; if (cksumType == CksumIpPseudo) return protoB->protocolFrameCksum(streamIndex, cksumType); return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType); } #if 0 quint32 protocolFrameHeaderCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; quint32 protocolFramePayloadCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; #endif virtual QWidget* configWidget() { if (configForm == NULL) { QVBoxLayout *layout = new QVBoxLayout; configForm = new QWidget; layout->addWidget(protoA->configWidget()); layout->addWidget(protoB->configWidget()); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); configForm->setLayout(layout); } return configForm; } virtual void loadConfigWidget() { protoA->loadConfigWidget(); protoB->loadConfigWidget(); } virtual void storeConfigWidget() { protoA->storeConfigWidget(); protoB->storeConfigWidget(); } }; #endif ostinato-0.5.1/common/crc32c.cpp0000700000175300010010000001342312005505614015746 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ /******************************************************************* ** IMPORTANT NOTE: ** This code is from RFC 4960 Stream Control Transmission Protocol ** It has been modified suitably while keeping the algorithm intact. ********************************************************************/ #include "crc32c.h" #define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) quint32 crc_c[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, }; quint32 checksumCrc32C(quint8 *buffer, uint length) { uint i; quint32 crc32 = ~0L; quint32 result; quint8 byte0,byte1,byte2,byte3; for (i = 0; i < length; i++) { CRC32C(crc32, buffer[i]); } result = ~crc32; /* result now holds the negated polynomial remainder; * since the table and algorithm is "reflected" [williams95]. * That is, result has the same value as if we mapped the message * to a polynomial, computed the host-bit-order polynomial * remainder, performed final negation, then did an end-for-end * bit-reversal. * Note that a 32-bit bit-reversal is identical to four inplace * 8-bit reversals followed by an end-for-end byteswap. * In other words, the bytes of each bit are in the right order, * but the bytes have been byteswapped. So we now do an explicit * byteswap. On a little-endian machine, this byteswap and * the final ntohl cancel out and could be elided. */ byte0 = result & 0xff; byte1 = (result>>8) & 0xff; byte2 = (result>>16) & 0xff; byte3 = (result>>24) & 0xff; crc32 = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); return ( crc32 ); } ostinato-0.5.1/common/crc32c.h0000700000175300010010000000135512005505614015414 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include quint32 checksumCrc32C(quint8 *buffer, uint length); ostinato-0.5.1/common/dot2llc.h0000700000175300010010000000160212005505614015673 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _DOT2_LLC_H #define _DOT2_LLC_H #include "comboprotocol.h" #include "dot3.h" #include "llc.h" typedef ComboProtocol Dot2LlcProtocol; #endif ostinato-0.5.1/common/dot2llc.proto0000700000175300010010000000160012005505614016605 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "dot3.proto"; import "llc.proto"; package OstProto; // 802.2 LLC message Dot2Llc { // Empty since this is a 'combo' protocol } extend Protocol { optional Dot2Llc dot2Llc = 206; } ostinato-0.5.1/common/dot2snap.h0000700000175300010010000000161612005505614016067 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _DOT2_SNAP_H #define _DOT2_SNAP_H #include "comboprotocol.h" #include "dot2llc.h" #include "snap.h" typedef ComboProtocol Dot2SnapProtocol; #endif ostinato-0.5.1/common/dot2snap.proto0000700000175300010010000000153312005505614017001 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // 802.2 SNAP message Dot2Snap { // Empty since this is a 'combo' protocol } extend Protocol { optional Dot2Snap dot2Snap = 207; } ostinato-0.5.1/common/dot3.cpp0000700000175300010010000001342612005505614015543 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "dot3.h" #include "streambase.h" #include #include #include Dot3ConfigForm::Dot3ConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); leLength->setValidator(new QIntValidator(0, 16384, this)); } Dot3Protocol::Dot3Protocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } Dot3Protocol::~Dot3Protocol() { delete configForm; } AbstractProtocol* Dot3Protocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Dot3Protocol(stream, parent); } quint32 Dot3Protocol::protocolNumber() const { return OstProto::Protocol::kDot3FieldNumber; } void Dot3Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::dot3)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void Dot3Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::dot3)) data.MergeFrom(protocol.GetExtension(OstProto::dot3)); } QString Dot3Protocol::name() const { return QString("802.3"); } QString Dot3Protocol::shortName() const { return QString("802.3"); } int Dot3Protocol::fieldCount() const { return dot3_fieldCount; } AbstractProtocol::FieldFlags Dot3Protocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case dot3_length: break; case dot3_is_override_length: flags &= ~FrameField; flags |= MetaField; break; default: break; } return flags; } QVariant Dot3Protocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case dot3_length: switch(attrib) { case FieldName: return QString("Length"); case FieldValue: { quint16 len = data.is_override_length() ? data.length() : protocolFramePayloadSize(streamIndex); return len; } case FieldTextValue: { quint16 len = data.is_override_length() ? data.length() : protocolFramePayloadSize(streamIndex); return QString("%1").arg(len); } case FieldFrameValue: { quint16 len = data.is_override_length() ? data.length() : protocolFramePayloadSize(streamIndex); QByteArray fv; fv.resize(2); qToBigEndian(len, (uchar*) fv.data()); return fv; } case FieldBitSize: return 16; default: break; } break; // Meta fields case dot3_is_override_length: { switch(attrib) { case FieldValue: return data.is_override_length(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool Dot3Protocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) return false; switch (index) { case dot3_length: { uint len = value.toUInt(&isOk); if (isOk) data.set_length(len); break; } case dot3_is_override_length: { bool ovr = value.toBool(); data.set_is_override_length(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return isOk; } bool Dot3Protocol::isProtocolFrameValueVariable() const { return isProtocolFramePayloadSizeVariable(); } int Dot3Protocol::protocolFrameVariableCount() const { return protocolFramePayloadVariableCount(); } QWidget* Dot3Protocol::configWidget() { if (configForm == NULL) { configForm = new Dot3ConfigForm; loadConfigWidget(); } return configForm; } void Dot3Protocol::loadConfigWidget() { configWidget(); configForm->cbOverrideLength->setChecked( fieldData(dot3_is_override_length, FieldValue).toBool()); configForm->leLength->setText( fieldData(dot3_length, FieldValue).toString()); } void Dot3Protocol::storeConfigWidget() { configWidget(); setFieldData(dot3_is_override_length, configForm->cbOverrideLength->isChecked()); setFieldData(dot3_length,configForm->leLength->text()); } ostinato-0.5.1/common/dot3.h0000700000175300010010000000421612005505614015205 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _DOT3_H #define _DOT3_H #include "abstractprotocol.h" #include "dot3.pb.h" #include "ui_dot3.h" class Dot3ConfigForm : public QWidget, public Ui::dot3 { Q_OBJECT public: Dot3ConfigForm(QWidget *parent = 0); }; class Dot3Protocol : public AbstractProtocol { private: OstProto::Dot3 data; Dot3ConfigForm *configForm; enum Dot3field { dot3_length, // Meta-fields dot3_is_override_length, dot3_fieldCount }; public: Dot3Protocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~Dot3Protocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/dot3.proto0000700000175300010010000000154612005505614016124 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // 802.3 message Dot3 { optional bool is_override_length = 2; optional uint32 length = 1; } extend Protocol { optional Dot3 dot3 = 201; } ostinato-0.5.1/common/dot3.ui0000700000175300010010000000355312005505614015376 0ustar srivatspNone dot3 0 0 181 98 Form 802.3 Length false Qt::Horizontal 16 54 Qt::Vertical 20 40 cbOverrideLength toggled(bool) leLength setEnabled(bool) 55 39 84 43 ostinato-0.5.1/common/eth2.cpp0000700000175300010010000001306412005505614015532 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "eth2.h" Eth2ConfigForm::Eth2ConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } Eth2Protocol::Eth2Protocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } Eth2Protocol::~Eth2Protocol() { delete configForm; } AbstractProtocol* Eth2Protocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Eth2Protocol(stream, parent); } quint32 Eth2Protocol::protocolNumber() const { return OstProto::Protocol::kEth2FieldNumber; } void Eth2Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::eth2)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void Eth2Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::eth2)) data.MergeFrom(protocol.GetExtension(OstProto::eth2)); } QString Eth2Protocol::name() const { return QString("Ethernet II"); } QString Eth2Protocol::shortName() const { return QString("Eth II"); } AbstractProtocol::ProtocolIdType Eth2Protocol::protocolIdType() const { return ProtocolIdEth; } int Eth2Protocol::fieldCount() const { return eth2_fieldCount; } AbstractProtocol::FieldFlags Eth2Protocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case eth2_type: break; case eth2_is_override_type: flags &= ~FrameField; flags |= MetaField; break; default: break; } return flags; } QVariant Eth2Protocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case eth2_type: { switch(attrib) { case FieldName: return QString("Type"); case FieldValue: { quint16 type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); return type; } case FieldTextValue: { quint16 type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); return QString("0x%1").arg(type, 4, BASE_HEX, QChar('0')); } case FieldFrameValue: { QByteArray fv; quint16 type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); fv.resize(2); qToBigEndian((quint16) type, (uchar*) fv.data()); return fv; } default: break; } break; } // Meta fields case eth2_is_override_type: { switch(attrib) { case FieldValue: return data.is_override_type(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool Eth2Protocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) return false; switch (index) { case eth2_type: { uint type = value.toUInt(&isOk); if (isOk) data.set_type(type); break; } case eth2_is_override_type: { bool ovr = value.toBool(); data.set_is_override_type(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return isOk; } QWidget* Eth2Protocol::configWidget() { if (configForm == NULL) { configForm = new Eth2ConfigForm; loadConfigWidget(); } return configForm; } void Eth2Protocol::loadConfigWidget() { configWidget(); configForm->cbOverrideType->setChecked( fieldData(eth2_is_override_type, FieldValue).toBool()); configForm->leType->setText(uintToHexStr( fieldData(eth2_type, FieldValue).toUInt(), 2)); } void Eth2Protocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(eth2_is_override_type, configForm->cbOverrideType->isChecked()); data.set_type(configForm->leType->text().remove(QChar(' ')).toULong(&isOk, 16)); } ostinato-0.5.1/common/eth2.h0000700000175300010010000000407412005505614015200 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _ETH2_H #define _ETH2_H #include "abstractprotocol.h" #include "eth2.pb.h" #include "ui_eth2.h" class Eth2ConfigForm : public QWidget, public Ui::eth2 { Q_OBJECT public: Eth2ConfigForm(QWidget *parent = 0); }; class Eth2Protocol : public AbstractProtocol { private: OstProto::Eth2 data; Eth2ConfigForm *configForm; enum eth2field { eth2_type = 0, eth2_is_override_type, eth2_fieldCount }; public: Eth2Protocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~Eth2Protocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/eth2.proto0000700000175300010010000000155112005505614016111 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Ethernet II message Eth2 { optional bool is_override_type = 2; optional uint32 type = 1; } extend Protocol { optional Eth2 eth2 = 200; } ostinato-0.5.1/common/eth2.ui0000700000175300010010000000334312005505614015364 0ustar srivatspNone eth2 0 0 190 64 Form Ethernet Type false >HH HH; Qt::Horizontal 40 20 Qt::Vertical 20 40 cbOverrideType toggled(bool) leType setEnabled(bool) 98 27 118 27 ostinato-0.5.1/common/fileformat.cpp0000700000175300010010000003624612005505614017027 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "fileformat.h" #include "crc32c.h" #include #include #include #include const std::string FileFormat::kFileMagicValue = "\xa7\xb7OSTINATO"; FileFormat fileFormat; const int kBaseHex = 16; FileFormat::FileFormat() { /* * We don't have any "real" work to do here in the constructor. * What we do is run some "assert" tests so that these get caught * at init itself instead of while saving/restoring when a user * might lose some data! */ OstProto::FileMagic magic; OstProto::FileChecksum cksum; magic.set_value(kFileMagicValue); cksum.set_value(quint32(0)); // TODO: convert Q_ASSERT to something that will run in RELEASE mode also Q_ASSERT(magic.IsInitialized()); Q_ASSERT(cksum.IsInitialized()); Q_ASSERT(magic.ByteSize() == kFileMagicSize); Q_ASSERT(cksum.ByteSize() == kFileChecksumSize); } FileFormat::~FileFormat() { } bool FileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { QFile file(fileName); QByteArray buf; int size, contentOffset, contentSize; quint32 calcCksum; OstProto::FileMagic magic; OstProto::FileMeta meta; OstProto::FileContent content; OstProto::FileChecksum cksum, zeroCksum; if (!file.open(QIODevice::ReadOnly)) goto _open_fail; if (file.size() < kFileMagicSize) goto _magic_missing; if (file.size() < kFileMinSize) goto _checksum_missing; buf.resize(file.size()); size = file.read(buf.data(), buf.size()); if (size < 0) goto _read_fail; Q_ASSERT(file.atEnd()); file.close(); qDebug("%s: file.size() = %lld", __FUNCTION__, file.size()); qDebug("%s: size = %d", __FUNCTION__, size); //qDebug("Read %d bytes", buf.size()); //qDebug("%s", QString(buf.toHex()).toAscii().constData()); // Parse and verify magic if (!magic.ParseFromArray( (void*)(buf.constData() + kFileMagicOffset), kFileMagicSize)) { goto _magic_parse_fail; } if (magic.value() != kFileMagicValue) goto _magic_match_fail; // Parse and verify checksum if (!cksum.ParseFromArray( (void*)(buf.constData() + size - kFileChecksumSize), kFileChecksumSize)) { goto _cksum_parse_fail; } zeroCksum.set_value(0); if (!zeroCksum.SerializeToArray( (void*) (buf.data() + size - kFileChecksumSize), kFileChecksumSize)) { goto _zero_cksum_serialize_fail; } calcCksum = checksumCrc32C((quint8*) buf.constData(), size); qDebug("checksum \nExpected:%x Actual:%x", calcCksum, cksum.value()); if (cksum.value() != calcCksum) goto _cksum_verify_fail; // Parse the metadata first before we parse the full contents if (!meta.ParseFromArray( (void*)(buf.constData() + kFileMetaDataOffset), size - kFileMetaDataOffset)) { goto _metadata_parse_fail; } qDebug("%s: File MetaData (INFORMATION) - \n%s", __FUNCTION__, QString().fromStdString(meta.DebugString()).toAscii().constData()); // MetaData Validation(s) if (meta.data().file_type() != OstProto::kStreamsFileType) goto _unexpected_file_type; if (meta.data().format_version_major() != kFileFormatVersionMajor) goto _incompatible_file_version; if (meta.data().format_version_minor() > kFileFormatVersionMinor) goto _incompatible_file_version; if (meta.data().format_version_minor() < kFileFormatVersionMinor) { // TODO: need to modify 'buf' such that we can parse successfully // assuming the native minor version } if (meta.data().format_version_revision() > kFileFormatVersionRevision) { error = QString(tr("%1 was created using a newer version of Ostinato." " New features/protocols will not be available.")).arg(fileName); } Q_ASSERT(meta.data().format_version_major() == kFileFormatVersionMajor); // ByteSize() does not include the Tag/Key, so we add 2 for that contentOffset = kFileMetaDataOffset + meta.data().ByteSize() + 2; contentSize = size - contentOffset - kFileChecksumSize; // Parse full contents if (!content.ParseFromArray( (void*)(buf.constData() + contentOffset), contentSize)) { goto _content_parse_fail; } if (!content.matter().has_streams()) goto _missing_streams; postParseFixup(meta.data(), content); streams.CopyFrom(content.matter().streams()); return true; _missing_streams: error = QString(tr("%1 does not contain any streams")).arg(fileName); goto _fail; _content_parse_fail: error = QString(tr("Failed parsing %1 contents")).arg(fileName); qDebug("Error: %s", QString().fromStdString( content.matter().InitializationErrorString()) .toAscii().constData()); qDebug("Debug: %s", QString().fromStdString( content.matter().DebugString()).toAscii().constData()); goto _fail; _incompatible_file_version: error = QString(tr("%1 is in an incompatible format version - %2.%3.%4" " (Native version is %5.%6.%7)")) .arg(fileName) .arg(meta.data().format_version_major()) .arg(meta.data().format_version_minor()) .arg(meta.data().format_version_revision()) .arg(kFileFormatVersionMajor) .arg(kFileFormatVersionMinor) .arg(kFileFormatVersionRevision); goto _fail; _unexpected_file_type: error = QString(tr("%1 is not a streams file")).arg(fileName); goto _fail; _metadata_parse_fail: error = QString(tr("Failed parsing %1 meta data")).arg(fileName); qDebug("Error: %s", QString().fromStdString( meta.data().InitializationErrorString()) .toAscii().constData()); goto _fail; _cksum_verify_fail: error = QString(tr("%1 checksum validation failed!\nExpected:%2 Actual:%3")) .arg(fileName) .arg(calcCksum, 0, kBaseHex) .arg(cksum.value(), 0, kBaseHex); goto _fail; _zero_cksum_serialize_fail: error = QString(tr("Internal Error: Zero Checksum Serialize failed!\n" "Error: %1\nDebug: %2")) .arg(QString().fromStdString( cksum.InitializationErrorString())) .arg(QString().fromStdString(cksum.DebugString())); goto _fail; _cksum_parse_fail: error = QString(tr("Failed parsing %1 checksum")).arg(fileName); qDebug("Error: %s", QString().fromStdString( cksum.InitializationErrorString()) .toAscii().constData()); goto _fail; _magic_match_fail: error = QString(tr("%1 is not an Ostinato file")).arg(fileName); goto _fail; _magic_parse_fail: error = QString(tr("%1 does not look like an Ostinato file")).arg(fileName); qDebug("Error: %s", QString().fromStdString( magic.InitializationErrorString()) .toAscii().constData()); goto _fail; _read_fail: error = QString(tr("Error reading from %1")).arg(fileName); goto _fail; _checksum_missing: error = QString(tr("%1 is too small (missing checksum)")).arg(fileName); goto _fail; _magic_missing: error = QString(tr("%1 is too small (missing magic value)")) .arg(fileName); goto _fail; _open_fail: error = QString(tr("Error opening %1")).arg(fileName); goto _fail; _fail: qDebug("%s", error.toAscii().constData()); return false; } bool FileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) { OstProto::FileMagic magic; OstProto::FileMeta meta; OstProto::FileContent content; OstProto::FileChecksum cksum; QFile file(fileName); int metaSize, contentSize; int contentOffset, cksumOffset; QByteArray buf; quint32 calcCksum; magic.set_value(kFileMagicValue); Q_ASSERT(magic.IsInitialized()); cksum.set_value(0); Q_ASSERT(cksum.IsInitialized()); initFileMetaData(*(meta.mutable_data())); meta.mutable_data()->set_file_type(OstProto::kStreamsFileType); Q_ASSERT(meta.IsInitialized()); if (!streams.IsInitialized()) goto _stream_not_init; content.mutable_matter()->mutable_streams()->CopyFrom(streams); Q_ASSERT(content.IsInitialized()); metaSize = meta.ByteSize(); contentSize = content.ByteSize(); contentOffset = kFileMetaDataOffset + metaSize; cksumOffset = contentOffset + contentSize; Q_ASSERT(magic.ByteSize() == kFileMagicSize); Q_ASSERT(cksum.ByteSize() == kFileChecksumSize); buf.resize(kFileMagicSize + metaSize + contentSize + kFileChecksumSize); // Serialize everything if (!magic.SerializeToArray((void*) (buf.data() + kFileMagicOffset), kFileMagicSize)) { goto _magic_serialize_fail; } if (!meta.SerializeToArray((void*) (buf.data() + kFileMetaDataOffset), metaSize)) { goto _meta_serialize_fail; } if (!content.SerializeToArray((void*) (buf.data() + contentOffset), contentSize)) { goto _content_serialize_fail; } if (!cksum.SerializeToArray((void*) (buf.data() + cksumOffset), kFileChecksumSize)) { goto _zero_cksum_serialize_fail; } emit status("Calculating checksum..."); // Calculate and write checksum calcCksum = checksumCrc32C((quint8*)buf.constData(), buf.size()); cksum.set_value(calcCksum); if (!cksum.SerializeToArray( (void*) (buf.data() + cksumOffset), kFileChecksumSize)) { goto _cksum_serialize_fail; } qDebug("Writing %d bytes", buf.size()); //qDebug("%s", QString(buf.toHex()).toAscii().constData()); emit status("Writing to disk..."); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) goto _open_fail; if (file.write(buf) < 0) goto _write_fail; file.close(); return true; _write_fail: error = QString(tr("Error writing to %1")).arg(fileName); goto _fail; _open_fail: error = QString(tr("Error opening %1 (Error Code = %2)")) .arg(fileName) .arg(file.error()); goto _fail; _cksum_serialize_fail: error = QString(tr("Internal Error: Checksum Serialize failed\n%1\n%2")) .arg(QString().fromStdString( cksum.InitializationErrorString())) .arg(QString().fromStdString(cksum.DebugString())); goto _fail; _zero_cksum_serialize_fail: error = QString(tr("Internal Eror: Zero Checksum Serialize failed\n%1\n%2")) .arg(QString().fromStdString( cksum.InitializationErrorString())) .arg(QString().fromStdString(cksum.DebugString())); goto _fail; _content_serialize_fail: error = QString(tr("Internal Error: Content Serialize failed\n%1\n%2")) .arg(QString().fromStdString( content.InitializationErrorString())) .arg(QString().fromStdString(content.DebugString())); goto _fail; _meta_serialize_fail: error = QString(tr("Internal Error: Meta Data Serialize failed\n%1\n%2")) .arg(QString().fromStdString( meta.InitializationErrorString())) .arg(QString().fromStdString(meta.DebugString())); goto _fail; _magic_serialize_fail: error = QString(tr("Internal Error: Magic Serialize failed\n%1\n%2")) .arg(QString().fromStdString( magic.InitializationErrorString())) .arg(QString().fromStdString(magic.DebugString())); goto _fail; _stream_not_init: error = QString(tr("Internal Error: Streams not initialized\n%1\n%2")) .arg(QString().fromStdString( streams.InitializationErrorString())) .arg(QString().fromStdString(streams.DebugString())); goto _fail; _fail: qDebug("%s", error.toAscii().constData()); return false; } bool FileFormat::isMyFileFormat(const QString fileName) { bool ret = false; QFile file(fileName); QByteArray buf; OstProto::FileMagic magic; if (!file.open(QIODevice::ReadOnly)) goto _exit; buf = file.peek(kFileMagicOffset + kFileMagicSize); if (!magic.ParseFromArray((void*)(buf.constData() + kFileMagicOffset), kFileMagicSize)) goto _close_exit; if (magic.value() == kFileMagicValue) ret = true; _close_exit: file.close(); _exit: return ret; } bool FileFormat::isMyFileType(const QString fileType) { if (fileType.startsWith("Ostinato")) return true; else return false; } void FileFormat::initFileMetaData(OstProto::FileMetaData &metaData) { // Fill in the "native" file format version metaData.set_format_version_major(kFileFormatVersionMajor); metaData.set_format_version_minor(kFileFormatVersionMinor); metaData.set_format_version_revision(kFileFormatVersionRevision); metaData.set_generator_name( qApp->applicationName().toUtf8().constData()); metaData.set_generator_version( qApp->property("version").toString().toUtf8().constData()); metaData.set_generator_revision( qApp->property("revision").toString().toUtf8().constData()); } #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /*! Fixup content to what is expected in the native version */ void FileFormat::postParseFixup(OstProto::FileMetaData metaData, OstProto::FileContent &content) { Q_ASSERT(metaData.format_version_major() == kFileFormatVersionMajor); // Do fixups from oldest to newest versions switch (metaData.format_version_minor()) { case 1: { int n = content.matter().streams().stream_size(); for (int i = 0; i < n; i++) { OstProto::StreamControl *sctl = content.mutable_matter()->mutable_streams()->mutable_stream(i)->mutable_control(); sctl->set_packets_per_sec(sctl->obsolete_packets_per_sec()); sctl->set_bursts_per_sec(sctl->obsolete_bursts_per_sec()); } // fall-through to next higher version until native version } case kFileFormatVersionMinor: // native version break; case 0: default: qWarning("%s: minor version %u unhandled", __FUNCTION__, metaData.format_version_minor()); Q_ASSERT_X(false, "postParseFixup", "unhandled minor version"); } } #pragma GCC diagnostic warning "-Wdeprecated-declarations" ostinato-0.5.1/common/fileformat.h0000700000175300010010000000362012005505614016462 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _FILE_FORMAT_H #define _FILE_FORMAT_H #include "abstractfileformat.h" #include "fileformat.pb.h" class FileFormat : public AbstractFileFormat { public: FileFormat(); ~FileFormat(); virtual bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error); virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); bool isMyFileFormat(const QString fileName); bool isMyFileType(const QString fileType); private: void initFileMetaData(OstProto::FileMetaData &metaData); void postParseFixup(OstProto::FileMetaData metaData, OstProto::FileContent &content); static const int kFileMagicSize = 12; static const int kFileChecksumSize = 5; static const int kFileMinSize = kFileMagicSize + kFileChecksumSize; static const int kFileMagicOffset = 0; static const int kFileMetaDataOffset = kFileMagicSize; static const std::string kFileMagicValue; // Native file format version static const uint kFileFormatVersionMajor = 0; static const uint kFileFormatVersionMinor = 2; static const uint kFileFormatVersionRevision = 3; }; extern FileFormat fileFormat; #endif ostinato-0.5.1/common/fileformat.proto0000700000175300010010000000577712005505614017415 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; enum FileType { kReservedFileType = 0; kStreamsFileType = 1; } message FileMetaData { required FileType file_type = 1; required uint32 format_version_major = 2; required uint32 format_version_minor = 3; required uint32 format_version_revision = 4; required string generator_name = 5; required string generator_version = 6; required string generator_revision = 7; } message FileContentMatter { optional StreamConfigList streams = 1; } /* An Ostinato file is the binary encoding of the File message below STRICTLY in increasing order of field number for the top level fields We do not use field number '1' for magic value because its encoded key is '0a' (LF or \n) which occurs commonly in text files. Checksum should be the last field, so top level field numbers greater than 15 are not permitted. We use 15 as the checksum field number because it is the largest field number that can fit in a 1-byte tag The magic value is of a fixed length so that meta data has a fixed offset from the start in the encoded message. Checksum is fixed length so that it is at a fixed negative offset from the end in the encoded message. Because the protobuf serialization API does not _guarantee_ strict ordering, so we define wrapper messages for each top level field and serialize the individual wrapper messages. The field numbers MUST be the same in 'File' and the wrapper messages */ message File { // FieldNumber 1 is reserved and MUST not be used! required bytes magic_value = 2; required FileMetaData meta_data = 3; optional FileContent content_matter = 9; required fixed32 checksum_value = 15; } /* The magic value is 10 bytes - "\xa7\xb7OSTINATO" The 1st-2nd byte has the MSB set to avoid mixup with text files The 3rd-10th byte spell OSTINATO (duh!) Encoded Size : Key(1) + Length(1) + Value(10) = 12 bytes Encoded Value: 120aa7b7 4f535449 4e41544f */ message FileMagic { required bytes value = 2; } message FileMeta { required FileMetaData data = 3; } message FileContent { optional FileContentMatter matter = 9; } /* Encoded Size : Key(1) + Value(4) = 5 bytes Encoded Value: 7d xxXXxxXX */ message FileChecksum { required fixed32 value = 15; // should always be a fixed 32-bit size } ostinato-0.5.1/common/gmp.cpp0000700000175300010010000007707212005505614015464 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "gmp.h" #include #include QHash GmpProtocol::frameFieldCountMap; GmpConfigForm::GmpConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); auxData->setValidator(new QRegExpValidator( QRegExp("[0-9A-Fa-f]*"), this)); } GmpConfigForm::~GmpConfigForm() { } void GmpConfigForm::update() { // save the current group Record by simulating a currentItemChanged() on_groupList_currentItemChanged(groupList->currentItem(), groupList->currentItem()); } void GmpConfigForm::on_groupMode_currentIndexChanged(int index) { bool disabled = (index == 0); groupCount->setDisabled(disabled); groupPrefix->setDisabled(disabled); } void GmpConfigForm::on_addSource_clicked() { QListWidgetItem *item=new QListWidgetItem(_defaultSourceIp); item->setFlags(item->flags() | Qt::ItemIsEditable); sourceList->insertItem(sourceList->currentRow(), item); if (!overrideSourceCount->isChecked()) sourceCount->setText(QString().setNum(sourceList->count())); } void GmpConfigForm::on_deleteSource_clicked() { delete sourceList->takeItem(sourceList->currentRow()); if (!overrideSourceCount->isChecked()) sourceCount->setText(QString().setNum(sourceList->count())); } void GmpConfigForm::on_addGroupRecord_clicked() { OstProto::Gmp::GroupRecord defRec; QVariantMap grpRec; QListWidgetItem *item = new QListWidgetItem; grpRec["groupRecordType"] = defRec.type(); grpRec["groupRecordAddress"] = _defaultGroupIp; grpRec["overrideGroupRecordSourceCount"] =defRec.is_override_source_count(); grpRec["groupRecordSourceCount"] = defRec.source_count(); grpRec["groupRecordSourceList"] = QStringList(); grpRec["overrideAuxDataLength"] = defRec.is_override_aux_data_length(); grpRec["auxDataLength"] = defRec.aux_data_length(); grpRec["auxData"] = QByteArray().append( QString().fromStdString(defRec.aux_data())); item->setData(Qt::UserRole, grpRec); item->setText(QString("%1: %2") .arg(groupRecordType->itemText(grpRec["groupRecordType"].toInt())) .arg(grpRec["groupRecordAddress"].toString())); groupList->insertItem(groupList->currentRow(), item); if (!overrideGroupRecordCount->isChecked()) groupRecordCount->setText(QString().setNum(groupList->count())); } void GmpConfigForm::on_deleteGroupRecord_clicked() { delete groupList->takeItem(groupList->currentRow()); if (!overrideGroupRecordCount->isChecked()) groupRecordCount->setText(QString().setNum(groupList->count())); } void GmpConfigForm::on_groupList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) { QVariantMap rec; QStringList strList; qDebug("in %s", __FUNCTION__); // save previous record ... if (previous == NULL) goto _load_current_record; rec["groupRecordType"] = groupRecordType->currentIndex(); rec["groupRecordAddress"] = groupRecordAddress->text(); strList.clear(); while (groupRecordSourceList->count()) { QListWidgetItem *item = groupRecordSourceList->takeItem(0); strList.append(item->text()); delete item; } rec["groupRecordSourceList"] = strList; rec["overrideGroupRecordSourceCount"] = overrideGroupRecordSourceCount->isChecked(); rec["groupRecordSourceCount"] = groupRecordSourceCount->text().toUInt(); rec["overrideAuxDataLength"] = overrideAuxDataLength->isChecked(); rec["auxDataLength"] = auxDataLength->text().toUInt(); rec["auxData"] = QByteArray().fromHex(QByteArray().append(auxData->text())); previous->setData(Qt::UserRole, rec); previous->setText(QString("%1: %2") .arg(groupRecordType->itemText(rec["groupRecordType"].toInt())) .arg(rec["groupRecordAddress"].toString())); _load_current_record: // ... and load current record if (current == NULL) goto _exit; rec = current->data(Qt::UserRole).toMap(); groupRecordType->setCurrentIndex(rec["groupRecordType"].toInt()); groupRecordAddress->setText(rec["groupRecordAddress"].toString()); strList = rec["groupRecordSourceList"].toStringList(); groupRecordSourceList->clear(); foreach (QString str, strList) { QListWidgetItem *item = new QListWidgetItem(str, groupRecordSourceList); item->setFlags(item->flags() | Qt::ItemIsEditable); } overrideGroupRecordSourceCount->setChecked( rec["overrideGroupRecordSourceCount"].toBool()); groupRecordSourceCount->setText(QString().setNum( rec["groupRecordSourceCount"].toUInt())); overrideAuxDataLength->setChecked(rec["overrideAuxDataLength"].toBool()); auxDataLength->setText(QString().setNum(rec["auxDataLength"].toUInt())); auxData->setText(QString(rec["auxData"].toByteArray().toHex())); _exit: groupRecord->setEnabled(current != NULL); return; } void GmpConfigForm::on_addGroupRecordSource_clicked() { QListWidgetItem *item=new QListWidgetItem(_defaultSourceIp); item->setFlags(item->flags() | Qt::ItemIsEditable); groupRecordSourceList->insertItem(groupRecordSourceList->currentRow(),item); if (!overrideGroupRecordSourceCount->isChecked()) groupRecordSourceCount->setText(QString().setNum( groupRecordSourceList->count())); } void GmpConfigForm::on_deleteGroupRecordSource_clicked() { delete groupRecordSourceList->takeItem(groupRecordSourceList->currentRow()); if (!overrideGroupRecordSourceCount->isChecked()) groupRecordSourceCount->setText(QString().setNum( groupRecordSourceList->count())); } void GmpConfigForm::on_auxData_textChanged(const QString &text) { // auxDataLength is in units of words and each byte is 2 chars in text() if (!overrideAuxDataLength->isChecked()) auxDataLength->setText(QString().setNum((text.size()+7)/8)); } GmpProtocol::GmpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { /* The configWidget is created lazily */ configForm = NULL; } GmpProtocol::~GmpProtocol() { delete configForm; } AbstractProtocol::ProtocolIdType GmpProtocol::protocolIdType() const { return ProtocolIdIp; } int GmpProtocol::fieldCount() const { return FIELD_COUNT; } int GmpProtocol::frameFieldCount() const { int type = msgType(); // frameFieldCountMap contains the frameFieldCounts for each // msgType - this is built on demand and cached for subsequent use // lookup if we have already cached ... if (frameFieldCountMap.contains(type)) return frameFieldCountMap.value(type); // ... otherwise calculate and cache int count = 0; for (int i = 0; i < FIELD_COUNT; i++) { if (fieldFlags(i).testFlag(AbstractProtocol::FrameField)) count++; } frameFieldCountMap.insert(type, count); return count; } AbstractProtocol::FieldFlags GmpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); flags &= ~FrameField; switch(index) { // Frame Fields - check against msgType() case kType: case kRsvdMrtCode: flags |= FrameField; break; case kChecksum: flags |= FrameField; flags |= CksumField; break; case kMldMrt: case kMldRsvd: // MLD subclass should handle suitably break; case kGroupAddress: if (!isSsmReport()) flags |= FrameField; break; case kRsvd1: case kSFlag: case kQrv: case kQqic: case kSourceCount: case kSources: if (isSsmQuery()) flags |= FrameField; break; case kRsvd2: case kGroupRecordCount: case kGroupRecords: if (isSsmReport()) flags |= FrameField; break; // Meta Fields case kIsOverrideChecksum: case kGroupMode: case kGroupCount: case kGroupPrefix: case kIsOverrideSourceCount: case kIsOverrideGroupRecordCount: flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case kType: { uint type = data.type(); switch(attrib) { case FieldName: return QString("Type"); case FieldValue: return type; case FieldTextValue: return QString("%1").arg(quint8(type)); case FieldFrameValue: return QByteArray(1, quint8(type)); default: break; } break; } case kRsvdMrtCode: { quint8 rsvd = 0; switch(attrib) { case FieldName: return QString("Reserved"); case FieldValue: return rsvd; case FieldTextValue: return QString("%1").arg(rsvd); case FieldFrameValue: return QByteArray(1, rsvd); default: break; } break; } case kChecksum: { switch(attrib) { case FieldName: return QString("Checksum"); case FieldBitSize: return 16; default: break; } quint16 cksum = data.is_override_checksum() ? data.checksum() : checksum(streamIndex); switch(attrib) { case FieldValue: return cksum; case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(cksum, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("0x%1").arg(cksum, 4, BASE_HEX, QChar('0')); default: break; } break; } case kMldMrt: case kMldRsvd: // XXX: Present only in MLD - hence handled by the mld subclass break; case kGroupAddress: // XXX: Handled by each subclass break; case kRsvd1: { quint8 rsvd = 0; switch(attrib) { case FieldName: return QString("Reserved"); case FieldValue: return rsvd; case FieldTextValue: return QString("%1").arg(rsvd); case FieldFrameValue: return QByteArray(1, char(rsvd)); case FieldBitSize: return 4; default: break; } break; } case kSFlag: { switch(attrib) { case FieldName: return QString("S Flag"); case FieldValue: return data.s_flag(); case FieldTextValue: return data.s_flag() ? QString("True") : QString("False"); case FieldFrameValue: return QByteArray(1, char(data.s_flag())); case FieldBitSize: return 1; default: break; } break; } case kQrv: { int qrv = data.qrv() & 0x7; switch(attrib) { case FieldName: return QString("QRV"); case FieldValue: return qrv; case FieldTextValue: return QString("%1").arg(qrv); case FieldFrameValue: return QByteArray(1, char(qrv)); case FieldBitSize: return 3; default: break; } break; } case kQqic: { int qqi = data.qqi(); switch(attrib) { case FieldName: return QString("QQIC"); case FieldValue: return qqi; case FieldTextValue: return QString("%1").arg(qqi); case FieldFrameValue: { char qqicode = char(qqic(qqi)); return QByteArray(1, qqicode); } default: break; } break; } case kSourceCount: { quint16 count = data.sources_size(); if (data.is_override_source_count()) count = data.source_count(); switch(attrib) { case FieldName: return QString("Number of Sources"); case FieldValue: return count; case FieldTextValue: return QString("%1").arg(count); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(count, (uchar*) fv.data()); return fv; } default: break; } break; } case kSources: // XXX: Handled by each subclass break; case kRsvd2: { quint16 rsvd = 0; switch(attrib) { case FieldName: return QString("Reserved"); case FieldValue: return rsvd; case FieldTextValue: return QString("%1").arg(rsvd); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(rsvd, (uchar*) fv.data()); return fv; } default: break; } break; } case kGroupRecordCount: { quint16 count = data.group_records_size(); if (data.is_override_group_record_count()) count = data.group_record_count(); switch(attrib) { case FieldName: return QString("Number of Group Records"); case FieldValue: return count; case FieldTextValue: return QString("%1").arg(count); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(count, (uchar*) fv.data()); return fv; } default: break; } break; } case kGroupRecords: { switch(attrib) { case FieldName: return QString("Group List"); case FieldValue: { QVariantList grpRecords; for (int i = 0; i < data.group_records_size(); i++) { QVariantMap grpRec; OstProto::Gmp::GroupRecord rec = data.group_records(i); grpRec["groupRecordType"] = rec.type(); // grpRec["groupRecordAddress"] = subclass responsibility grpRec["overrideGroupRecordSourceCount"] = rec.is_override_source_count(); grpRec["groupRecordSourceCount"] = rec.source_count(); // grpRec["groupRecordSourceList"] = subclass responsibility grpRec["overrideAuxDataLength"] = rec.is_override_aux_data_length(); grpRec["auxDataLength"] = rec.aux_data_length(); grpRec["auxData"] = QByteArray().append( QString::fromStdString(rec.aux_data())); grpRecords.append(grpRec); } return grpRecords; } case FieldFrameValue: { QVariantList fv; for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QByteArray rv; quint16 srcCount; rv.resize(4); rv[0] = rec.type(); rv[1] = rec.is_override_aux_data_length() ? rec.aux_data_length() : rec.aux_data().size()/4; if (rec.is_override_source_count()) srcCount = rec.source_count(); else srcCount = rec.sources_size(); qToBigEndian(srcCount, (uchar*)(rv.data()+2)); // group_address => subclass responsibility // source list => subclass responsibility rv.append(QString().fromStdString(rec.aux_data())); fv.append(rv); } return fv; } case FieldTextValue: { QStringList list; for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QString str; str.append(" Type: "); switch(rec.type()) { case OstProto::Gmp::GroupRecord::kIsInclude: str.append("IS_INCLUDE"); break; case OstProto::Gmp::GroupRecord::kIsExclude: str.append("IS_EXCLUDE"); break; case OstProto::Gmp::GroupRecord::kToInclude: str.append("TO_INCLUDE"); break; case OstProto::Gmp::GroupRecord::kToExclude: str.append("TO_EXCLUDE"); break; case OstProto::Gmp::GroupRecord::kAllowNew: str.append("ALLOW_NEW"); break; case OstProto::Gmp::GroupRecord::kBlockOld: str.append("BLOCK_OLD"); break; default: str.append("UNKNOWN"); break; } str.append(QString("; AuxLen: %1").arg( rec.is_override_aux_data_length() ? rec.aux_data_length() : rec.aux_data().size()/4)); str.append(QString("; Source Count: %1").arg( rec.is_override_source_count() ? rec.source_count(): rec.sources_size())); // NOTE: subclass should replace the XXX below with // group address and source list str.append(QString("; XXX")); str.append(QString("; AuxData: ").append( QByteArray().append(QString().fromStdString( rec.aux_data())).toHex())); list.append(str); } return list; } default: break; } break; } // Meta Fields case kIsOverrideChecksum: { switch(attrib) { case FieldValue: return data.is_override_checksum(); default: break; } break; } case kGroupMode: { switch(attrib) { case FieldValue: return data.group_mode(); default: break; } break; } case kGroupCount: { switch(attrib) { case FieldValue: return data.group_count(); default: break; } break; } case kGroupPrefix: { switch(attrib) { case FieldValue: return data.group_prefix(); default: break; } break; } case kIsOverrideSourceCount: { switch(attrib) { case FieldValue: return data.is_override_source_count(); default: break; } break; } case kIsOverrideGroupRecordCount: { switch(attrib) { case FieldValue: return data.is_override_group_record_count(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool GmpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case kType: { uint type = value.toUInt(&isOk); if (isOk) data.set_type(type); break; } case kRsvdMrtCode: { uint val = value.toUInt(&isOk); if (isOk) data.set_rsvd_code(val); break; } case kChecksum: { uint csum = value.toUInt(&isOk); if (isOk) data.set_checksum(csum); break; } case kMldMrt: { uint mrt = value.toUInt(&isOk); if (isOk) data.set_max_response_time(mrt); break; } case kGroupAddress: // XXX: Handled by subclass isOk = false; break; case kRsvd1: isOk = false; break; case kSFlag: { bool flag = value.toBool(); data.set_s_flag(flag); isOk = true; break; } case kQrv: { uint qrv = value.toUInt(&isOk); if (isOk) data.set_qrv(qrv); break; } case kQqic: { uint qqi = value.toUInt(&isOk); if (isOk) data.set_qqi(qqi); break; } case kSourceCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_source_count(count); break; } case kSources: // XXX: Handled by subclass isOk = false; break; case kRsvd2: isOk = false; break; case kGroupRecordCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_group_record_count(count); break; } case kGroupRecords: { QVariantList list = value.toList(); data.clear_group_records(); for (int i = 0; i < list.count(); i++) { QVariantMap grpRec = list.at(i).toMap(); OstProto::Gmp::GroupRecord *rec = data.add_group_records(); rec->set_type(OstProto::Gmp::GroupRecord::RecordType( grpRec["groupRecordType"].toInt())); // NOTE: rec->group_address => subclass responsibility rec->set_is_override_source_count( grpRec["overrideGroupRecordSourceCount"].toBool()); rec->set_source_count(grpRec["groupRecordSourceCount"].toUInt()); // NOTE: rec->sources => subclass responsibility rec->set_is_override_aux_data_length( grpRec["overrideAuxDataLength"].toBool()); rec->set_aux_data_length(grpRec["auxDataLength"].toUInt()); QByteArray ba = grpRec["auxData"].toByteArray(); // pad to word boundary if (ba.size() % 4) ba.append(QByteArray(4 - (ba.size() % 4), char(0))); rec->set_aux_data(std::string(ba.constData(), ba.size())); } break; } // Meta Fields case kIsOverrideChecksum: { bool ovr = value.toBool(); data.set_is_override_checksum(ovr); isOk = true; break; } case kGroupMode: { uint mode = value.toUInt(&isOk); if (isOk && data.GroupMode_IsValid(mode)) data.set_group_mode((OstProto::Gmp::GroupMode)mode); break; } case kGroupCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_group_count(count); break; } case kGroupPrefix: { uint prefix = value.toUInt(&isOk); if (isOk) data.set_group_prefix(prefix); break; } case kIsOverrideSourceCount: { bool ovr = value.toBool(); data.set_is_override_source_count(ovr); isOk = true; break; } case kIsOverrideGroupRecordCount: { bool ovr = value.toBool(); data.set_is_override_group_record_count(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } int GmpProtocol::protocolFrameSize(int streamIndex) const { // TODO: Calculate to reduce processing cost return AbstractProtocol::protocolFrameValue(streamIndex, true).size(); } bool GmpProtocol::isProtocolFrameValueVariable() const { // No fields vary for Ssm Query and Report if (isSsmReport() || isSsmQuery()) return false; // For all other msg types, check the group mode if (fieldData(kGroupMode, FieldValue).toUInt() != uint(OstProto::Gmp::kFixed)) return true; return false; } int GmpProtocol::protocolFrameVariableCount() const { int count = 1; // No fields vary for Ssm Query and Report if (isSsmReport() || isSsmQuery()) return count; // For all other msg types, check the group mode if (fieldData(kGroupMode, FieldValue).toUInt() != uint(OstProto::Gmp::kFixed)) { count = AbstractProtocol::lcm(count, fieldData(kGroupCount, FieldValue).toUInt()); } return count; } void GmpProtocol::loadConfigWidget() { configWidget(); configForm->msgTypeCombo->setValue(fieldData(kType, FieldValue).toUInt()); // XXX: configForm->maxResponseTime set by subclass configForm->overrideChecksum->setChecked( fieldData(kIsOverrideChecksum, FieldValue).toBool()); configForm->checksum->setText(uintToHexStr( fieldData(kChecksum, FieldValue).toUInt(), 2)); configForm->groupAddress->setText( fieldData(kGroupAddress, FieldValue).toString()); configForm->groupMode->setCurrentIndex( fieldData(kGroupMode, FieldValue).toUInt()); configForm->groupCount->setText( fieldData(kGroupCount, FieldValue).toString()); configForm->groupPrefix->setText( fieldData(kGroupPrefix, FieldValue).toString()); configForm->sFlag->setChecked(fieldData(kSFlag, FieldValue).toBool()); configForm->qrv->setText(fieldData(kQrv, FieldValue).toString()); configForm->qqi->setText(fieldData(kQqic, FieldValue).toString()); QStringList sl = fieldData(kSources, FieldValue).toStringList(); configForm->sourceList->clear(); foreach(QString src, sl) { QListWidgetItem *item = new QListWidgetItem(src); item->setFlags(item->flags() | Qt::ItemIsEditable); configForm->sourceList->addItem(item); } // NOTE: SourceCount should be loaded after sourceList configForm->overrideSourceCount->setChecked( fieldData(kIsOverrideSourceCount, FieldValue).toBool()); configForm->sourceCount->setText( fieldData(kSourceCount, FieldValue).toString()); QVariantList list = fieldData(kGroupRecords, FieldValue).toList(); configForm->groupList->clear(); foreach (QVariant rec, list) { QVariantMap grpRec = rec.toMap(); QListWidgetItem *item = new QListWidgetItem; item->setData(Qt::UserRole, grpRec); item->setText(QString("%1: %2") .arg(configForm->groupRecordType->itemText( grpRec["groupRecordType"].toInt())) .arg(grpRec["groupRecordAddress"].toString())); configForm->groupList->addItem(item); } // NOTE: recordCount should be loaded after recordList configForm->overrideGroupRecordCount->setChecked( fieldData(kIsOverrideGroupRecordCount, FieldValue).toBool()); configForm->groupRecordCount->setText( fieldData(kGroupRecordCount, FieldValue).toString()); } void GmpProtocol::storeConfigWidget() { bool isOk; configWidget(); configForm->update(); setFieldData(kType, configForm->msgTypeCombo->currentValue()); // XXX: configForm->maxResponseTime handled by subclass setFieldData(kIsOverrideChecksum, configForm->overrideChecksum->isChecked()); setFieldData(kChecksum, configForm->checksum->text().toUInt(&isOk, BASE_HEX)); setFieldData(kGroupAddress, configForm->groupAddress->text()); setFieldData(kGroupMode, configForm->groupMode->currentIndex()); setFieldData(kGroupCount, configForm->groupCount->text()); setFieldData(kGroupPrefix, configForm->groupPrefix->text().remove('/')); setFieldData(kSFlag, configForm->sFlag->isChecked()); setFieldData(kQrv, configForm->qrv->text()); setFieldData(kQqic, configForm->qqi->text()); QStringList list; for (int i = 0; i < configForm->sourceList->count(); i++) list.append(configForm->sourceList->item(i)->text()); setFieldData(kSources, list); // sourceCount should be AFTER sources setFieldData(kIsOverrideSourceCount, configForm->overrideSourceCount->isChecked()); setFieldData(kSourceCount, configForm->sourceCount->text()); QVariantList grpList; for (int i = 0; i < configForm->groupList->count(); i++) { QVariant grp = configForm->groupList->item(i)->data(Qt::UserRole); grpList.append(grp.toMap()); } setFieldData(kGroupRecords, grpList); // groupRecordCount should be AFTER groupRecords setFieldData(kIsOverrideGroupRecordCount, configForm->overrideGroupRecordCount->isChecked()); setFieldData(kGroupRecordCount, configForm->groupRecordCount->text()); } ostinato-0.5.1/common/gmp.h0000700000175300010010000001014212005505614015112 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _GMP_H #define _GMP_H #include "gmp.pb.h" #include "ui_gmp.h" #include "abstractprotocol.h" #include /* Gmp Protocol Frame Format - TODO: for now see the respective RFCs */ class GmpProtocol; class GmpConfigForm : public QWidget, public Ui::Gmp { Q_OBJECT public: GmpConfigForm(QWidget *parent = 0); ~GmpConfigForm(); void update(); protected: QString _defaultGroupIp; QString _defaultSourceIp; enum { kSsmQueryPage = 0, kSsmReportPage = 1 }; private slots: void on_groupMode_currentIndexChanged(int index); void on_addSource_clicked(); void on_deleteSource_clicked(); void on_addGroupRecord_clicked(); void on_deleteGroupRecord_clicked(); void on_groupList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); void on_addGroupRecordSource_clicked(); void on_deleteGroupRecordSource_clicked(); void on_auxData_textChanged(const QString &text); }; class GmpProtocol : public AbstractProtocol { public: GmpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~GmpProtocol(); virtual ProtocolIdType protocolIdType() const; virtual int fieldCount() const; virtual int frameFieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual int protocolFrameSize(int streamIndex = 0) const; virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual void loadConfigWidget(); virtual void storeConfigWidget(); protected: enum GmpField { // ------------ // Frame Fields // ------------ // Fields used in all ASM and SSM messages, unless otherwise specified kType = 0, kRsvdMrtCode, kChecksum, kMldMrt, // MLD Only (except MLDv2 Report) kMldRsvd, // MLD Only (except MLDv2 Report) // Field used in ASM messages kGroupAddress, FIELD_COUNT_ASM_ALL, // Fields used in SSM Query kRsvd1 = FIELD_COUNT_ASM_ALL, kSFlag, kQrv, kQqic, kSourceCount, kSources, FIELD_COUNT_SSM_QUERY, // Fields used in SSM Report kRsvd2 = FIELD_COUNT_SSM_QUERY, kGroupRecordCount, kGroupRecords, FIELD_COUNT_SSM_REPORT, FRAME_FIELD_COUNT = FIELD_COUNT_SSM_REPORT, // ----------- // Meta Fields // ----------- kIsOverrideChecksum = FRAME_FIELD_COUNT, kGroupMode, kGroupCount, kGroupPrefix, kIsOverrideSourceCount, kIsOverrideGroupRecordCount, FIELD_COUNT }; OstProto::Gmp data; GmpConfigForm *configForm; int msgType() const; virtual bool isSsmReport() const = 0; virtual bool isQuery() const = 0; virtual bool isSsmQuery() const = 0; int qqic(int value) const; virtual quint16 checksum(int streamIndex) const = 0; private: static QHash frameFieldCountMap; }; inline int GmpProtocol::msgType() const { return fieldData(kType, FieldValue).toInt(); } inline int GmpProtocol::qqic(int value) const { return quint8(value); // TODO: if value > 128 convert to mantissa/exp form } #endif ostinato-0.5.1/common/gmp.proto0000700000175300010010000000550412005505614016034 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Group Management Protocol (i.e. IGMP and MLD) message Gmp { // // Common fields for both ASM and SSM messages // optional uint32 type = 1; optional bool is_override_rsvd_code = 2; optional uint32 rsvd_code = 3; // MaxRespTime is in milliseconds - MaxRespCode will be derived optional uint32 max_response_time = 4 [default = 100]; optional bool is_override_checksum = 5; optional uint32 checksum = 6; message IpAddress { optional fixed32 v4 = 1; optional fixed64 v6_hi = 2; optional fixed64 v6_lo = 3; } // // Fields used in ASM messages // enum GroupMode { kFixed = 0; kIncrementGroup = 1; kDecrementGroup = 2; kRandomGroup = 3; } optional IpAddress group_address = 10; optional GroupMode group_mode = 11 [default = kFixed]; optional uint32 group_count = 12 [default = 16]; optional uint32 group_prefix = 13 [default = 24]; // // Fields used in SSM Query // optional bool s_flag = 20; optional uint32 qrv = 21 [default = 2]; // QuerierQueryInterval is in seconds - QQIC will be derived optional uint32 qqi = 22 [default = 125]; repeated IpAddress sources = 23; optional bool is_override_source_count = 24; optional uint32 source_count = 25; // // Fields used in SSM Reports // message GroupRecord { enum RecordType { kReserved = 0; kIsInclude = 1; kIsExclude = 2; kToInclude = 3; kToExclude = 4; kAllowNew = 5; kBlockOld = 6; } optional RecordType type = 1 [default = kIsInclude]; optional IpAddress group_address = 2; repeated IpAddress sources = 3; optional bool is_override_source_count = 4; optional uint32 source_count = 5; optional bytes aux_data = 6; optional bool is_override_aux_data_length = 7; optional uint32 aux_data_length = 8; } repeated GroupRecord group_records = 30; optional bool is_override_group_record_count = 31; optional uint32 group_record_count = 32; } ostinato-0.5.1/common/gmp.ui0000700000175300010010000006235512005505614015315 0ustar srivatspNone Gmp 0 0 509 355 Form Message Type msgTypeCombo Max Response Time (1/10s) maxResponseTime 0 0 Checksum false 0 0 >HHHH; Group Address groupAddress Mode msgTypeCombo Count msgTypeCombo Prefix msgTypeCombo 1 0 Fixed Increment Host Decrement Host Random Host false 0 0 false 0 0 /900; 1 0 0 0 0 S Flag (Suppress Router Processing) QRV qrv Qt::Horizontal 40 20 QQI qqi Qt::Vertical 61 41 Source List groupRecordAddress Qt::Horizontal 16 20 + true QAbstractItemView::InternalMove Qt::Horizontal 40 20 Count false Qt::Vertical 20 40 0 0 0 0 Group Records groupRecordAddress Qt::Horizontal 16 20 + true QAbstractItemView::InternalMove Number of Groups false false 0 0 0 0 Record Type groupRecordType Reserved Is Include Is Exclude To Include To Exclude Allow New Block Old Group Address groupRecordAddress Source List groupRecordAddress Qt::Horizontal 191 20 + true QAbstractItemView::InternalMove Number of Sources false 0 0 Qt::Horizontal 81 20 Aux Data Qt::Horizontal 40 20 Length (x4) false 0 0 Qt::Vertical 101 21 IntComboBox QComboBox
intcombobox.h
msgTypeCombo maxResponseTime overrideChecksum checksum groupAddress groupMode groupCount groupPrefix overrideGroupRecordCount groupRecordCount groupRecordType groupRecordAddress overrideGroupRecordSourceCount groupRecordSourceCount overrideAuxDataLength auxDataLength auxData sFlag qrv qqi overrideSourceCount sourceCount overrideChecksum toggled(bool) checksum setEnabled(bool) 391 43 448 45 overrideGroupRecordSourceCount toggled(bool) groupRecordSourceCount setEnabled(bool) 402 202 436 204 overrideAuxDataLength toggled(bool) auxDataLength setEnabled(bool) 416 286 433 286 overrideGroupRecordCount toggled(bool) groupRecordCount setEnabled(bool) 112 309 138 312 overrideSourceCount toggled(bool) sourceCount setEnabled(bool) 413 154 434 151
ostinato-0.5.1/common/hexdump.cpp0000700000175300010010000001441212005505614016340 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "hexdump.h" #include "streambase.h" #include HexDumpConfigForm::HexDumpConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); hexEdit->setFont(QFont("Courier")); hexEdit->setOverwriteMode(false); } void HexDumpConfigForm::on_hexEdit_overwriteModeChanged(bool isOverwriteMode) { if (isOverwriteMode) mode->setText(tr("Ovr")); else mode->setText(tr("Ins")); } HexDumpProtocol::HexDumpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { /* The configWidget is created lazily */ configForm = NULL; } HexDumpProtocol::~HexDumpProtocol() { delete configForm; } AbstractProtocol* HexDumpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new HexDumpProtocol(stream, parent); } quint32 HexDumpProtocol::protocolNumber() const { return OstProto::Protocol::kHexDumpFieldNumber; } void HexDumpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::hexDump)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void HexDumpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::hexDump)) data.MergeFrom(protocol.GetExtension(OstProto::hexDump)); } QString HexDumpProtocol::name() const { return QString("HexDump"); } QString HexDumpProtocol::shortName() const { return QString("HexDump"); } int HexDumpProtocol::fieldCount() const { return hexDump_fieldCount; } AbstractProtocol::FieldFlags HexDumpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case hexDump_content: flags |= FrameField; break; case hexDump_pad_until_end: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant HexDumpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case hexDump_content: { QByteArray ba; QByteArray pad; switch(attrib) { case FieldValue: case FieldTextValue: case FieldFrameValue: ba.append(QString().fromStdString(data.content())); if (data.pad_until_end()) { pad = QByteArray( protocolFrameSize(streamIndex) - ba.size(), '\0'); } break; default: break; } switch(attrib) { case FieldName: return QString("Content"); case FieldValue: return ba; case FieldTextValue: return ba.append(pad).toHex(); case FieldFrameValue: return ba.append(pad); default: break; } break; } // Meta fields case hexDump_pad_until_end: { switch(attrib) { case FieldValue: return data.pad_until_end(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool HexDumpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case hexDump_content: { QByteArray ba = value.toByteArray(); data.set_content(ba.constData(), ba.size()); isOk = true; break; } case hexDump_pad_until_end: { bool pad = value.toBool(); data.set_pad_until_end(pad); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } int HexDumpProtocol::protocolFrameSize(int streamIndex) const { int len = data.content().size(); if (data.pad_until_end()) { int pad = mpStream->frameLen(streamIndex) - (protocolFrameOffset(streamIndex) + len + kFcsSize); if (pad < 0) pad = 0; len += pad; } return len; } QWidget* HexDumpProtocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new HexDumpConfigForm; loadConfigWidget(); } return configForm; } void HexDumpProtocol::loadConfigWidget() { configWidget(); configForm->hexEdit->setData( fieldData(hexDump_content, FieldValue).toByteArray()); configForm->padUntilEnd->setChecked( fieldData(hexDump_pad_until_end, FieldValue).toBool()); } void HexDumpProtocol::storeConfigWidget() { configWidget(); setFieldData(hexDump_content, configForm->hexEdit->data()); setFieldData(hexDump_pad_until_end, configForm->padUntilEnd->isChecked()); } ostinato-0.5.1/common/hexdump.h0000700000175300010010000000460412005505614016007 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _HEXDUMP_H #define _HEXDUMP_H #include "hexdump.pb.h" #include "ui_hexdump.h" #include "abstractprotocol.h" /* HexDump Protocol Frame Format - +---------+---------+ | User | Zero | | HexDump | Padding | +---------+---------+ */ class HexDumpConfigForm : public QWidget, public Ui::HexDump { Q_OBJECT public: HexDumpConfigForm(QWidget *parent = 0); private slots: void on_hexEdit_overwriteModeChanged(bool isOverwriteMode); }; class HexDumpProtocol : public AbstractProtocol { public: HexDumpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~HexDumpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual int protocolFrameSize(int streamIndex = 0) const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); private: OstProto::HexDump data; HexDumpConfigForm *configForm; enum hexDumpfield { // Frame Fields hexDump_content = 0, // Meta Fields hexDump_pad_until_end, hexDump_fieldCount }; }; #endif ostinato-0.5.1/common/hexdump.proto0000700000175300010010000000160612005505614016722 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // HexDump Protocol message HexDump { optional bytes content = 1; optional bool pad_until_end = 2 [default = true]; } extend Protocol { optional HexDump hexDump = 104; } ostinato-0.5.1/common/hexdump.ui0000700000175300010010000000337612005505614016202 0ustar srivatspNone HexDump 0 0 511 190 Form Pad until end of packet Qt::Horizontal 281 20 50 0 QFrame::Panel QFrame::Sunken 1 Qt::AlignCenter QHexEdit QWidget
qhexedit.h
1
ostinato-0.5.1/common/icmp.cpp0000700000175300010010000004114112005505614015615 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "icmp.h" #include #include enum IcmpType { kIcmpEchoReply = 0, kIcmpDestinationUnreachable = 3, kIcmpSourceQuench = 4, kIcmpRedirect = 5, kIcmpEchoRequest = 8, kIcmpTimeExceeded = 11, kIcmpParameterProblem = 12, kIcmpTimestampRequest = 13, kIcmpTimestampReply = 14, kIcmpInformationRequest = 15, kIcmpInformationReply = 16, kIcmpAddressMaskRequest = 17, kIcmpAddressMaskReply = 18 }; enum Icmp6Type { kIcmp6DestinationUnreachable = 1, kIcmp6PacketTooBig = 2, kIcmp6TimeExceeded = 3, kIcmp6ParameterProblem = 4, kIcmp6EchoRequest = 128, kIcmp6EchoReply = 129, kIcmp6RouterSolicitation = 133, kIcmp6RouterAdvertisement = 134, kIcmp6NeighbourSolicitation = 135, kIcmp6NeighbourAdvertisement = 136, kIcmp6Redirect = 137, kIcmp6InformationQuery = 139, kIcmp6InformationResponse = 140 }; static QSet icmpIdSeqSet = QSet() << kIcmpEchoRequest << kIcmpEchoReply << kIcmpInformationRequest << kIcmpInformationReply; static QSet icmp6IdSeqSet = QSet() << kIcmp6EchoRequest << kIcmp6EchoReply; static bool isIdSeqType(OstProto::Icmp::Version ver, int type) { //qDebug("%s: ver = %d, type = %d", __FUNCTION__, ver, type); switch(ver) { case OstProto::Icmp::kIcmp4: return icmpIdSeqSet.contains(type); case OstProto::Icmp::kIcmp6: return icmp6IdSeqSet.contains(type); default: break; } Q_ASSERT(false); // unreachable return false; } IcmpConfigForm::IcmpConfigForm(QWidget *parent) : QWidget(parent) { versionGroup = new QButtonGroup(this); setupUi(this); // auto-connect's not working, for some reason I can't figure out! // slot name changed to when_ instead of on_ so that connectSlotsByName() // doesn't complain connect(versionGroup, SIGNAL(buttonClicked(int)), SLOT(when_versionGroup_buttonClicked(int))); versionGroup->addButton(icmp4Button, OstProto::Icmp::kIcmp4); versionGroup->addButton(icmp6Button, OstProto::Icmp::kIcmp6); typeCombo->setValidator(new QIntValidator(0, 0xFF, this)); icmp4Button->click(); idEdit->setValidator(new QIntValidator(0, 0xFFFF, this)); seqEdit->setValidator(new QIntValidator(0, 0xFFFF, this)); } void IcmpConfigForm::on_typeCombo_currentIndexChanged(int /*index*/) { idSeqFrame->setVisible( isIdSeqType( OstProto::Icmp::Version(versionGroup->checkedId()), typeCombo->currentValue())); } void IcmpConfigForm::when_versionGroup_buttonClicked(int id) { int value = typeCombo->currentValue(); typeCombo->clear(); switch(id) { case OstProto::Icmp::kIcmp4: typeCombo->addItem(kIcmpEchoReply, "Echo Reply"); typeCombo->addItem(kIcmpDestinationUnreachable, "Destination Unreachable"); typeCombo->addItem(kIcmpSourceQuench, "Source Quench"); typeCombo->addItem(kIcmpRedirect, "Redirect"); typeCombo->addItem(kIcmpEchoRequest, "Echo Request"); typeCombo->addItem(kIcmpTimeExceeded, "Time Exceeded"); typeCombo->addItem(kIcmpParameterProblem, "Parameter Problem"); typeCombo->addItem(kIcmpTimestampRequest, "Timestamp Request"); typeCombo->addItem(kIcmpTimestampReply, "Timestamp Reply"); typeCombo->addItem(kIcmpInformationRequest, "Information Request"); typeCombo->addItem(kIcmpInformationReply, "Information Reply"); typeCombo->addItem(kIcmpAddressMaskRequest, "Address Mask Request"); typeCombo->addItem(kIcmpAddressMaskReply, "Address Mask Reply"); break; case OstProto::Icmp::kIcmp6: typeCombo->addItem(kIcmp6DestinationUnreachable, "Destination Unreachable"); typeCombo->addItem(kIcmp6PacketTooBig, "Packet Too Big"); typeCombo->addItem(kIcmp6TimeExceeded, "Time Exceeded"); typeCombo->addItem(kIcmp6ParameterProblem, "Parameter Problem"); typeCombo->addItem(kIcmp6EchoRequest, "Echo Request"); typeCombo->addItem(kIcmp6EchoReply, "Echo Reply"); typeCombo->addItem(kIcmp6RouterSolicitation, "Router Solicitation"); typeCombo->addItem(kIcmp6RouterAdvertisement, "Router Advertisement"); typeCombo->addItem(kIcmp6NeighbourSolicitation, "Neighbour Solicitation"); typeCombo->addItem(kIcmp6NeighbourAdvertisement, "Neighbour Advertisement"); typeCombo->addItem(kIcmp6Redirect, "Redirect"); typeCombo->addItem(kIcmp6InformationQuery, "Information Query"); typeCombo->addItem(kIcmp6InformationResponse, "Information Response"); break; default: Q_ASSERT(false); } typeCombo->setValue(value); } IcmpProtocol::IcmpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } IcmpProtocol::~IcmpProtocol() { delete configForm; } AbstractProtocol* IcmpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new IcmpProtocol(stream, parent); } quint32 IcmpProtocol::protocolNumber() const { return OstProto::Protocol::kIcmpFieldNumber; } void IcmpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::icmp)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void IcmpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::icmp)) data.MergeFrom(protocol.GetExtension(OstProto::icmp)); } QString IcmpProtocol::name() const { return QString("Internet Control Message Protocol"); } QString IcmpProtocol::shortName() const { return QString("ICMP"); } quint32 IcmpProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: switch(icmpVersion()) { case OstProto::Icmp::kIcmp4: return 0x1; case OstProto::Icmp::kIcmp6: return 0x3A; default:break; } default:break; } return AbstractProtocol::protocolId(type); } int IcmpProtocol::fieldCount() const { return icmp_fieldCount; } int IcmpProtocol::frameFieldCount() const { int count; if (isIdSeqType(icmpVersion(), icmpType())) count = icmp_idSeqFrameFieldCount; else count = icmp_commonFrameFieldCount; return count; } AbstractProtocol::FieldFlags IcmpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case icmp_type: case icmp_code: break; case icmp_checksum: flags |= CksumField; break; case icmp_identifier: case icmp_sequence: if (!isIdSeqType(icmpVersion(), icmpType())) flags &= ~FrameField; break; case icmp_version: case icmp_is_override_checksum: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant IcmpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case icmp_type: { unsigned char type = data.type() & 0xFF; switch(attrib) { case FieldName: return QString("Type"); case FieldValue: return type; case FieldTextValue: return QString("%1").arg((uint) type); case FieldFrameValue: return QByteArray(1, type); default: break; } break; } case icmp_code: { unsigned char code = data.code() & 0xFF; switch(attrib) { case FieldName: return QString("Code"); case FieldValue: return code; case FieldTextValue: return QString("%1").arg((uint)code); case FieldFrameValue: return QByteArray(1, code); default: break; } break; } case icmp_checksum: { quint16 cksum; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_checksum()) { cksum = data.checksum(); } else { quint16 cks; quint32 sum = 0; cks = protocolFrameCksum(streamIndex, CksumIp); sum += (quint16) ~cks; cks = protocolFramePayloadCksum(streamIndex, CksumIp); sum += (quint16) ~cks; if (icmpVersion() == OstProto::Icmp::kIcmp6) { cks = protocolFrameHeaderCksum(streamIndex, CksumIpPseudo); sum += (quint16) ~cks; } while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); cksum = (~sum) & 0xFFFF; } break; default: cksum = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Checksum"); case FieldValue: return cksum; case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(cksum, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("0x%1").arg( cksum, 4, BASE_HEX, QChar('0'));; case FieldBitSize: return 16; default: break; } break; } case icmp_identifier: { switch(attrib) { case FieldName: return QString("Identifier"); case FieldValue: return data.identifier(); case FieldTextValue: return QString("%1").arg(data.identifier()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.identifier(), (uchar*) fv.data()); return fv; } default: break; } break; } case icmp_sequence: { switch(attrib) { case FieldName: return QString("Sequence"); case FieldValue: return data.sequence(); case FieldTextValue: return QString("%1").arg(data.sequence()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.sequence(), (uchar*) fv.data()); return fv; } default: break; } break; } // Meta fields case icmp_version: { switch(attrib) { case FieldValue: return data.icmp_version(); default: break; } break; } case icmp_is_override_checksum: { switch(attrib) { case FieldValue: return data.is_override_checksum(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool IcmpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case icmp_type: { uint type = value.toUInt(&isOk); if (isOk) data.set_type(type & 0xFF); break; } case icmp_code: { uint code = value.toUInt(&isOk); if (isOk) data.set_code(code & 0xFF); break; } case icmp_checksum: { uint csum = value.toUInt(&isOk); if (isOk) data.set_checksum(csum); break; } case icmp_identifier: { uint id = value.toUInt(&isOk); if (isOk) data.set_identifier(id); break; } case icmp_sequence: { uint seq = value.toUInt(&isOk); if (isOk) data.set_sequence(seq); break; } case icmp_version: { int ver = value.toUInt(&isOk); if (isOk) data.set_icmp_version(OstProto::Icmp::Version(ver)); break; } case icmp_is_override_checksum: { bool ovr = value.toBool(); data.set_is_override_checksum(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } QWidget* IcmpProtocol::configWidget() { if (configForm == NULL) { configForm = new IcmpConfigForm; loadConfigWidget(); } return configForm; } void IcmpProtocol::loadConfigWidget() { configWidget(); configForm->versionGroup->button(icmpVersion())->click(); configForm->typeCombo->setValue(fieldData(icmp_type, FieldValue).toUInt()); configForm->codeEdit->setText(fieldData(icmp_code, FieldValue).toString()); configForm->overrideCksum->setChecked( fieldData(icmp_is_override_checksum, FieldValue).toBool()); configForm->cksumEdit->setText(uintToHexStr( fieldData(icmp_checksum, FieldValue).toUInt(), 2)); configForm->idEdit->setText( fieldData(icmp_identifier, FieldValue).toString()); configForm->seqEdit->setText( fieldData(icmp_sequence, FieldValue).toString()); } void IcmpProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(icmp_version, configForm->versionGroup->checkedId()); setFieldData(icmp_type, configForm->typeCombo->currentValue()); setFieldData(icmp_code, configForm->codeEdit->text()); setFieldData(icmp_is_override_checksum, configForm->overrideCksum->isChecked()); setFieldData(icmp_checksum, configForm->cksumEdit->text().toUInt(&isOk, BASE_HEX)); setFieldData(icmp_identifier, configForm->idEdit->text()); setFieldData(icmp_sequence, configForm->seqEdit->text()); } ostinato-0.5.1/common/icmp.h0000700000175300010010000000616512005505614015271 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _ICMP_H #define _ICMP_H #include "icmp.pb.h" #include "ui_icmp.h" #include "abstractprotocol.h" #include /* Icmp Protocol Frame Format - +-----+------+------+------+-------+ | TYP | CODE | CSUM | [ID] | [SEQ] | | (1) | (1) | (2) | (2) | (2) | +-----+------+------+------+-------+ Fields within [] are applicable only to certain TYPEs Figures in braces represent field width in bytes */ class IcmpConfigForm : public QWidget, public Ui::Icmp { Q_OBJECT public: QButtonGroup *versionGroup; IcmpConfigForm(QWidget *parent = 0); private slots: void on_typeCombo_currentIndexChanged(int index); void when_versionGroup_buttonClicked(int id); }; class IcmpProtocol : public AbstractProtocol { private: OstProto::Icmp data; IcmpConfigForm *configForm; enum icmpfield { // Frame Fields icmp_type = 0, icmp_code, icmp_checksum, icmp_commonFrameFieldCount, icmp_identifier = icmp_commonFrameFieldCount, icmp_sequence, icmp_idSeqFrameFieldCount, // Meta Fields icmp_is_override_checksum = icmp_idSeqFrameFieldCount, icmp_version, icmp_fieldCount }; OstProto::Icmp::Version icmpVersion() const { return OstProto::Icmp::Version( fieldData(icmp_version, FieldValue).toUInt()); } int icmpType() const { return fieldData(icmp_type, FieldValue).toInt(); } public: IcmpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~IcmpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual int frameFieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/icmp.proto0000700000175300010010000000224612005505614016201 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Icmp Protocol message Icmp { enum Version { kIcmp4 = 4; kIcmp6 = 6; } optional Version icmp_version = 1 [default = kIcmp4]; optional bool is_override_checksum = 2; optional uint32 type = 6 [default = 0x8]; // echo request optional uint32 code = 7; optional uint32 checksum = 8; optional uint32 identifier = 9 [default = 1234]; optional uint32 sequence = 10; } extend Protocol { optional Icmp icmp = 402; } ostinato-0.5.1/common/icmp.ui0000700000175300010010000001037412005505614015454 0ustar srivatspNone Icmp 0 0 373 166 Form Version ICMPv4 ICMPv6 Type typeCombo Code codeEdit Qt::Horizontal 31 20 Checksum false Identifier idEdit Sequence seqEdit Qt::Vertical 211 71 IntComboBox QComboBox
intcombobox.h
icmp4Button icmp6Button typeCombo codeEdit overrideCksum cksumEdit idEdit seqEdit overrideCksum toggled(bool) cksumEdit setEnabled(bool) 33 70 96 71
ostinato-0.5.1/common/igmp.cpp0000700000175300010010000003134612005505614015627 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "igmp.h" #include "ipv4addressdelegate.h" #include "iputils.h" #include #include IgmpConfigForm::IgmpConfigForm(QWidget *parent) : GmpConfigForm(parent) { connect(msgTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(on_msgTypeCombo_currentIndexChanged(int))); msgTypeCombo->setValueMask(0xFF); msgTypeCombo->addItem(kIgmpV1Query, "IGMPv1 Query"); msgTypeCombo->addItem(kIgmpV1Report, "IGMPv1 Report"); msgTypeCombo->addItem(kIgmpV2Query, "IGMPv2 Query"); msgTypeCombo->addItem(kIgmpV2Report, "IGMPv2 Report"); msgTypeCombo->addItem(kIgmpV2Leave, "IGMPv2 Leave"); msgTypeCombo->addItem(kIgmpV3Query, "IGMPv3 Query"); msgTypeCombo->addItem(kIgmpV3Report, "IGMPv3 Report"); _defaultGroupIp = "0.0.0.0"; _defaultSourceIp = "0.0.0.0"; groupAddress->setInputMask("009.009.009.009;"); // FIXME: use validator groupRecordAddress->setInputMask("009.009.009.009;"); // FIXME:use validator sourceList->setItemDelegate(new IPv4AddressDelegate(this)); groupRecordSourceList->setItemDelegate(new IPv4AddressDelegate(this)); } void IgmpConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/) { switch(msgTypeCombo->currentValue()) { case kIgmpV1Query: case kIgmpV1Report: case kIgmpV2Query: case kIgmpV2Report: case kIgmpV2Leave: asmGroup->show(); ssmWidget->hide(); break; case kIgmpV3Query: asmGroup->hide(); ssmWidget->setCurrentIndex(kSsmQueryPage); ssmWidget->show(); break; case kIgmpV3Report: asmGroup->hide(); ssmWidget->setCurrentIndex(kSsmReportPage); ssmWidget->show(); break; default: asmGroup->hide(); ssmWidget->hide(); break; } } IgmpProtocol::IgmpProtocol(StreamBase *stream, AbstractProtocol *parent) : GmpProtocol(stream, parent) { _hasPayload = false; data.set_type(kIgmpV2Query); } IgmpProtocol::~IgmpProtocol() { } AbstractProtocol* IgmpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new IgmpProtocol(stream, parent); } quint32 IgmpProtocol::protocolNumber() const { return OstProto::Protocol::kIgmpFieldNumber; } void IgmpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::igmp)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void IgmpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::igmp)) data.MergeFrom(protocol.GetExtension(OstProto::igmp)); } QString IgmpProtocol::name() const { return QString("Internet Group Management Protocol"); } QString IgmpProtocol::shortName() const { return QString("IGMP"); } quint32 IgmpProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: return 0x2; default:break; } return AbstractProtocol::protocolId(type); } QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case kRsvdMrtCode: { uint mrt = 0; quint8 mrcode = 0; if (msgType() == kIgmpV3Query) { mrt = data.max_response_time(); mrcode = quint8(mrc(mrt)); } else if (msgType() == kIgmpV2Query) { mrt = data.max_response_time(); mrcode = mrt & 0xFF; } switch(attrib) { case FieldName: if (isQuery()) return QString("Max Response Time"); else return QString("Reserved"); case FieldValue: return mrt; case FieldTextValue: return QString("%1").arg(mrt); case FieldFrameValue: return QByteArray(1, mrcode); default: break; } break; } case kGroupAddress: { quint32 grpIp = ipUtils::ipAddress( data.group_address().v4(), data.group_prefix(), ipUtils::AddrMode(data.group_mode()), data.group_count(), streamIndex); switch(attrib) { case FieldName: return QString("Group Address"); case FieldValue: case FieldTextValue: return QHostAddress(grpIp).toString(); case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian(grpIp, (uchar*) fv.data()); return fv; } default: break; } break; } case kSources: { switch(attrib) { case FieldName: return QString("Source List"); case FieldValue: { QStringList list; for (int i = 0; i < data.sources_size(); i++) list.append(QHostAddress(data.sources(i).v4()).toString()); return list; } case FieldFrameValue: { QByteArray fv; fv.resize(4 * data.sources_size()); for (int i = 0; i < data.sources_size(); i++) qToBigEndian(data.sources(i).v4(), (uchar*)(fv.data()+4*i)); return fv; } case FieldTextValue: { QStringList list; for (int i = 0; i < data.sources_size(); i++) list.append(QHostAddress(data.sources(i).v4()).toString()); return list.join(", "); } default: break; } break; } case kGroupRecords: { switch(attrib) { case FieldValue: { QVariantList grpRecords = GmpProtocol::fieldData( index, attrib, streamIndex).toList(); for (int i = 0; i < data.group_records_size(); i++) { QVariantMap grpRec = grpRecords.at(i).toMap(); OstProto::Gmp::GroupRecord rec = data.group_records(i); grpRec["groupRecordAddress"] = QHostAddress( rec.group_address().v4()).toString(); QStringList sl; for (int j = 0; j < rec.sources_size(); j++) sl.append(QHostAddress(rec.sources(j).v4()).toString()); grpRec["groupRecordSourceList"] = sl; grpRecords.replace(i, grpRec); } return grpRecords; } case FieldFrameValue: { QVariantList list = GmpProtocol::fieldData( index, attrib, streamIndex).toList(); QByteArray fv; for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QByteArray rv = list.at(i).toByteArray(); rv.insert(4, QByteArray(4+4*rec.sources_size(), char(0))); qToBigEndian(rec.group_address().v4(), (uchar*)(rv.data()+4)); for (int j = 0; j < rec.sources_size(); j++) { qToBigEndian(rec.sources(j).v4(), (uchar*)(rv.data()+8+4*j)); } fv.append(rv); } return fv; } case FieldTextValue: { QStringList list = GmpProtocol::fieldData( index, attrib, streamIndex).toStringList(); for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QString recStr = list.at(i); QString str; str.append(QString("Group: %1").arg( QHostAddress(rec.group_address().v4()).toString())); str.append("; Sources: "); QStringList sl; for (int j = 0; j < rec.sources_size(); j++) sl.append(QHostAddress(rec.sources(j).v4()).toString()); str.append(sl.join(", ")); recStr.replace("XXX", str); list.replace(i, recStr); } return list.join("\n").insert(0, "\n"); } default: break; } break; } default: break; } return GmpProtocol::fieldData(index, attrib, streamIndex); } bool IgmpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case kRsvdMrtCode: { uint mrt = value.toUInt(&isOk); if (isOk) data.set_max_response_time(mrt); break; } case kGroupAddress: { QHostAddress addr(value.toString()); quint32 ip = addr.toIPv4Address(); isOk = (addr.protocol() == QAbstractSocket::IPv4Protocol); if (isOk) data.mutable_group_address()->set_v4(ip); break; } case kSources: { QStringList list = value.toStringList(); data.clear_sources(); foreach(QString str, list) { quint32 ip = QHostAddress(str).toIPv4Address(); data.add_sources()->set_v4(ip); } break; } case kGroupRecords: { GmpProtocol::setFieldData(index, value, attrib); QVariantList list = value.toList(); for (int i = 0; i < list.count(); i++) { QVariantMap grpRec = list.at(i).toMap(); OstProto::Gmp::GroupRecord *rec = data.mutable_group_records(i); rec->mutable_group_address()->set_v4(QHostAddress( grpRec["groupRecordAddress"].toString()) .toIPv4Address()); QStringList srcList = grpRec["groupRecordSourceList"] .toStringList(); rec->clear_sources(); foreach (QString src, srcList) { rec->add_sources()->set_v4( QHostAddress(src).toIPv4Address()); } } break; } default: isOk = GmpProtocol::setFieldData(index, value, attrib); break; } _exit: return isOk; } QWidget* IgmpProtocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new IgmpConfigForm; loadConfigWidget(); } return configForm; } void IgmpProtocol::loadConfigWidget() { GmpProtocol::loadConfigWidget(); configForm->maxResponseTime->setText( fieldData(kRsvdMrtCode, FieldValue).toString()); } void IgmpProtocol::storeConfigWidget() { GmpProtocol::storeConfigWidget(); setFieldData(kRsvdMrtCode, configForm->maxResponseTime->text()); } quint16 IgmpProtocol::checksum(int streamIndex) const { quint16 cks; quint32 sum = 0; // TODO: add as a new CksumType (CksumIgmp?) and implement in AbsProto cks = protocolFrameCksum(streamIndex, CksumIp); sum += (quint16) ~cks; cks = protocolFramePayloadCksum(streamIndex, CksumIp); sum += (quint16) ~cks; while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16); cks = (~sum) & 0xFFFF; return cks; } ostinato-0.5.1/common/igmp.h0000700000175300010010000000561512005505614015274 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IGMP_H #define _IGMP_H #include "igmp.pb.h" #include "gmp.h" // IGMP uses the same msg type value for 'Query' messages across // versions despite the fields being different. To distinguish // Query messages of different versions, we use an additional // upper byte enum IgmpMsgType { kIgmpV1Query = 0x11, kIgmpV1Report = 0x12, kIgmpV2Query = 0xFF11, kIgmpV2Report = 0x16, kIgmpV2Leave = 0x17, kIgmpV3Query = 0xFE11, kIgmpV3Report = 0x22, }; class IgmpConfigForm : public GmpConfigForm { Q_OBJECT public: IgmpConfigForm(QWidget *parent = 0); private slots: void on_msgTypeCombo_currentIndexChanged(int index); }; class IgmpProtocol : public GmpProtocol { public: IgmpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~IgmpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); protected: virtual bool isSsmReport() const; virtual bool isQuery() const; virtual bool isSsmQuery() const; virtual quint16 checksum(int streamIndex) const; private: int mrc(int value) const; }; inline bool IgmpProtocol::isSsmReport() const { return (msgType() == kIgmpV3Report); } inline bool IgmpProtocol::isQuery() const { return ((msgType() == kIgmpV1Query) || (msgType() == kIgmpV2Query) || (msgType() == kIgmpV3Query)); } inline bool IgmpProtocol::isSsmQuery() const { return (msgType() == kIgmpV3Query); } inline int IgmpProtocol::mrc(int value) const { return quint8(value); // TODO: if value > 128, convert to mantissa/exp form } #endif ostinato-0.5.1/common/igmp.proto0000700000175300010010000000142412005505614016202 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "gmp.proto"; package OstProto; extend Protocol { optional Gmp igmp = 403; } ostinato-0.5.1/common/intcombobox.h0000700000175300010010000000327012005505614016656 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef __INT_COMBO_BOX #define __INT_COMBO_BOX #include class IntComboBox : public QComboBox { public: IntComboBox(QWidget *parent = 0) : QComboBox(parent) { valueMask_ = 0xFFFFFFFF; setEditable(true); } void addItem(int value, const QString &text) { QComboBox::addItem( QString("%1 - %2").arg(value & valueMask_).arg(text), value); } int currentValue() { bool isOk; int index = findText(currentText()); if (index >= 0) return itemData(index).toInt(); else return currentText().toInt(&isOk, 0); } void setValue(int value) { int index = findData(value); if (index >= 0) setCurrentIndex(index); else setEditText(QString().setNum(value)); } uint valueMask() { return valueMask_; } void setValueMask(uint mask) { valueMask_ = mask; } private: uint valueMask_; }; #endif ostinato-0.5.1/common/ip4.cpp0000700000175300010010000005731012005505614015366 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "ip4.h" Ip4ConfigForm::Ip4ConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); leIpVersion->setValidator(new QIntValidator(0, 15, this)); connect(cmbIpSrcAddrMode, SIGNAL(currentIndexChanged(int)), this, SLOT(on_cmbIpSrcAddrMode_currentIndexChanged(int))); connect(cmbIpDstAddrMode, SIGNAL(currentIndexChanged(int)), this, SLOT(on_cmbIpDstAddrMode_currentIndexChanged(int))); } Ip4ConfigForm::~Ip4ConfigForm() { qDebug("IPv4 Config Form destructor called"); } void Ip4ConfigForm::on_cmbIpSrcAddrMode_currentIndexChanged(int index) { if (index == OstProto::Ip4::e_im_fixed) { leIpSrcAddrCount->setDisabled(true); leIpSrcAddrMask->setDisabled(true); } else { leIpSrcAddrCount->setEnabled(true); leIpSrcAddrMask->setEnabled(true); } } void Ip4ConfigForm::on_cmbIpDstAddrMode_currentIndexChanged(int index) { if (index == OstProto::Ip4::e_im_fixed) { leIpDstAddrCount->setDisabled(true); leIpDstAddrMask->setDisabled(true); } else { leIpDstAddrCount->setEnabled(true); leIpDstAddrMask->setEnabled(true); } } Ip4Protocol::Ip4Protocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } Ip4Protocol::~Ip4Protocol() { delete configForm; } AbstractProtocol* Ip4Protocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Ip4Protocol(stream, parent); } quint32 Ip4Protocol::protocolNumber() const { return OstProto::Protocol::kIp4FieldNumber; } void Ip4Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::ip4)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void Ip4Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::ip4)) data.MergeFrom(protocol.GetExtension(OstProto::ip4)); } QString Ip4Protocol::name() const { return QString("Internet Protocol ver 4"); } QString Ip4Protocol::shortName() const { return QString("IPv4"); } AbstractProtocol::ProtocolIdType Ip4Protocol::protocolIdType() const { return ProtocolIdIp; } quint32 Ip4Protocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdLlc: return 0x060603; case ProtocolIdEth: return 0x0800; case ProtocolIdIp: return 0x04; default:break; } return AbstractProtocol::protocolId(type); } int Ip4Protocol::fieldCount() const { return ip4_fieldCount; } AbstractProtocol::FieldFlags Ip4Protocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case ip4_ver: case ip4_hdrLen: case ip4_tos: case ip4_totLen: case ip4_id: case ip4_flags: case ip4_fragOfs: case ip4_ttl: case ip4_proto: break; case ip4_cksum: flags |= CksumField; break; case ip4_srcAddr: case ip4_dstAddr: break; case ip4_isOverrideVer: case ip4_isOverrideHdrLen: case ip4_isOverrideTotLen: case ip4_isOverrideProto: case ip4_isOverrideCksum: case ip4_srcAddrMode: case ip4_srcAddrCount: case ip4_srcAddrMask: case ip4_dstAddrMode: case ip4_dstAddrCount: case ip4_dstAddrMask: flags &= ~FrameField; flags |= MetaField; break; default: break; } return flags; } QVariant Ip4Protocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case ip4_ver: { int ver; ver = data.is_override_ver() ? (data.ver_hdrlen() >> 4) & 0x0F : 4; switch(attrib) { case FieldName: return QString("Version"); case FieldValue: return ver; case FieldTextValue: return QString("%1").arg(ver, 1, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, (char) ver); case FieldBitSize: return 4; default: break; } break; } case ip4_hdrLen: { int hdrlen; hdrlen = data.is_override_hdrlen() ? data.ver_hdrlen() & 0x0F : 5; switch(attrib) { case FieldName: return QString("Header Length"); case FieldValue: return hdrlen; case FieldTextValue: return QString("%1").arg(hdrlen, 1, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, (char) hdrlen); case FieldBitSize: return 4; default: break; } break; } case ip4_tos: switch(attrib) { case FieldName: return QString("TOS/DSCP"); case FieldValue: return data.tos(); case FieldFrameValue: return QByteArray(1, (char) data.tos()); case FieldTextValue: return QString("0x%1"). arg(data.tos(), 2, BASE_HEX, QChar('0'));; default: break; } break; case ip4_totLen: { switch(attrib) { case FieldName: return QString("Total Length"); case FieldValue: { int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 20); return totlen; } case FieldFrameValue: { QByteArray fv; int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 20); fv.resize(2); qToBigEndian((quint16) totlen, (uchar*) fv.data()); return fv; } case FieldTextValue: { int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 20); return QString("%1").arg(totlen); } case FieldBitSize: return 16; default: break; } break; } case ip4_id: switch(attrib) { case FieldName: return QString("Identification"); case FieldValue: return data.id(); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.id(), (uchar*)fv.data()); return fv; } case FieldTextValue: return QString("0x%1"). arg(data.id(), 2, BASE_HEX, QChar('0'));; default: break; } break; case ip4_flags: switch(attrib) { case FieldName: return QString("Flags"); case FieldValue: return data.flags(); case FieldFrameValue: return QByteArray(1, (char) data.flags()); case FieldTextValue: { QString s; s.append("Unused:"); s.append(data.flags() & IP_FLAG_UNUSED ? "1" : "0"); s.append(" Don't Fragment:"); s.append(data.flags() & IP_FLAG_DF ? "1" : "0"); s.append(" More Fragments:"); s.append(data.flags() & IP_FLAG_MF ? "1" : "0"); return s; } case FieldBitSize: return 3; default: break; } break; case ip4_fragOfs: switch(attrib) { case FieldName: return QString("Fragment Offset"); case FieldValue: return data.frag_ofs(); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) (data.frag_ofs()), (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("%1").arg(data.frag_ofs()*8); case FieldBitSize: return 13; default: break; } break; case ip4_ttl: switch(attrib) { case FieldName: return QString("Time to Live"); case FieldValue: return data.ttl(); case FieldFrameValue: return QByteArray(1, (char)data.ttl()); case FieldTextValue: return QString("%1").arg(data.ttl()); default: break; } break; case ip4_proto: { switch(attrib) { case FieldName: return QString("Protocol"); case FieldValue: { unsigned char id = data.is_override_proto() ? data.proto() : payloadProtocolId(ProtocolIdIp); return id; } case FieldFrameValue: { unsigned char id = data.is_override_proto() ? data.proto() : payloadProtocolId(ProtocolIdIp); return QByteArray(1, (char) id); } case FieldTextValue: { unsigned char id = data.is_override_proto() ? data.proto() : payloadProtocolId(ProtocolIdIp); return QString("0x%1"). arg(id, 2, BASE_HEX, QChar('0')); } default: break; } break; } case ip4_cksum: { switch(attrib) { case FieldName: return QString("Header Checksum"); case FieldValue: { quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumIp); return cksum; } case FieldFrameValue: { QByteArray fv; quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumIp); fv.resize(2); qToBigEndian((quint16) cksum, (uchar*) fv.data()); return fv; } case FieldTextValue: { quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumIp); return QString("0x%1"). arg(cksum, 4, BASE_HEX, QChar('0'));; } case FieldBitSize: return 16; default: break; } break; } case ip4_srcAddr: { int u; quint32 subnet, host, srcIp = 0; switch(data.src_ip_mode()) { case OstProto::Ip4::e_im_fixed: srcIp = data.src_ip(); break; case OstProto::Ip4::e_im_inc_host: u = streamIndex % data.src_ip_count(); subnet = data.src_ip() & data.src_ip_mask(); host = (((data.src_ip() & ~data.src_ip_mask()) + u) & ~data.src_ip_mask()); srcIp = subnet | host; break; case OstProto::Ip4::e_im_dec_host: u = streamIndex % data.src_ip_count(); subnet = data.src_ip() & data.src_ip_mask(); host = (((data.src_ip() & ~data.src_ip_mask()) - u) & ~data.src_ip_mask()); srcIp = subnet | host; break; case OstProto::Ip4::e_im_random_host: subnet = data.src_ip() & data.src_ip_mask(); host = (qrand() & ~data.src_ip_mask()); srcIp = subnet | host; break; default: qWarning("Unhandled src_ip_mode = %d", data.src_ip_mode()); } switch(attrib) { case FieldName: return QString("Source"); case FieldValue: return srcIp; case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian(srcIp, (uchar*) fv.data()); return fv; } case FieldTextValue: return QHostAddress(srcIp).toString(); default: break; } break; } case ip4_dstAddr: { int u; quint32 subnet, host, dstIp = 0; switch(data.dst_ip_mode()) { case OstProto::Ip4::e_im_fixed: dstIp = data.dst_ip(); break; case OstProto::Ip4::e_im_inc_host: u = streamIndex % data.dst_ip_count(); subnet = data.dst_ip() & data.dst_ip_mask(); host = (((data.dst_ip() & ~data.dst_ip_mask()) + u) & ~data.dst_ip_mask()); dstIp = subnet | host; break; case OstProto::Ip4::e_im_dec_host: u = streamIndex % data.dst_ip_count(); subnet = data.dst_ip() & data.dst_ip_mask(); host = (((data.dst_ip() & ~data.dst_ip_mask()) - u) & ~data.dst_ip_mask()); dstIp = subnet | host; break; case OstProto::Ip4::e_im_random_host: subnet = data.dst_ip() & data.dst_ip_mask(); host = (qrand() & ~data.dst_ip_mask()); dstIp = subnet | host; break; default: qWarning("Unhandled dst_ip_mode = %d", data.dst_ip_mode()); } switch(attrib) { case FieldName: return QString("Destination"); case FieldValue: return dstIp; case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) dstIp, (uchar*) fv.data()); return fv; } case FieldTextValue: return QHostAddress(dstIp).toString(); default: break; } break; } // Meta fields case ip4_isOverrideVer: case ip4_isOverrideHdrLen: case ip4_isOverrideTotLen: case ip4_isOverrideProto: case ip4_isOverrideCksum: case ip4_srcAddrMode: case ip4_srcAddrCount: case ip4_srcAddrMask: case ip4_dstAddrMode: case ip4_dstAddrCount: case ip4_dstAddrMask: default: break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool Ip4Protocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) return false; switch (index) { case ip4_proto: { uint proto = value.toUInt(&isOk); if (isOk) data.set_proto(proto); } default: break; } return isOk; } bool Ip4Protocol::isProtocolFrameValueVariable() const { if ((data.src_ip_mode() != OstProto::Ip4::e_im_fixed) || (data.dst_ip_mode() != OstProto::Ip4::e_im_fixed)) return true; else return false; } int Ip4Protocol::protocolFrameVariableCount() const { int count = 1; if (data.src_ip_mode() != OstProto::Ip4::e_im_fixed) count = AbstractProtocol::lcm(count, data.src_ip_count()); if (data.dst_ip_mode() != OstProto::Ip4::e_im_fixed) count = AbstractProtocol::lcm(count, data.dst_ip_count()); return count; } quint32 Ip4Protocol::protocolFrameCksum(int streamIndex, CksumType cksumType) const { switch (cksumType) { case CksumIpPseudo: { quint32 sum; sum = fieldData(ip4_srcAddr, FieldValue, streamIndex).toUInt() >> 16; sum += fieldData(ip4_srcAddr, FieldValue, streamIndex).toUInt() & 0xFFFF; sum += fieldData(ip4_dstAddr, FieldValue, streamIndex).toUInt() >> 16; sum += fieldData(ip4_dstAddr, FieldValue, streamIndex).toUInt() & 0xFFFF; sum += fieldData(ip4_proto, FieldValue, streamIndex).toUInt() & 0x00FF; sum += (fieldData(ip4_totLen, FieldValue, streamIndex).toUInt() & 0xFFFF) - 20; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); // Above calculation done assuming 'big endian' // - so convert to host order //return qFromBigEndian(sum); return ~sum; } default: break; } return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType); } QWidget* Ip4Protocol::configWidget() { if (configForm == NULL) { configForm = new Ip4ConfigForm; loadConfigWidget(); } return configForm; } void Ip4Protocol::loadConfigWidget() { configWidget(); configForm->cbIpVersionOverride->setChecked(data.is_override_ver()); configForm->leIpVersion->setText(fieldData(ip4_ver, FieldValue).toString()); configForm->cbIpHdrLenOverride->setChecked(data.is_override_hdrlen()); configForm->leIpHdrLen->setText(fieldData(ip4_hdrLen, FieldValue).toString()); configForm->leIpTos->setText(uintToHexStr(data.tos(), 1)); configForm->cbIpLengthOverride->setChecked(data.is_override_totlen()); configForm->leIpLength->setText(fieldData(ip4_totLen, FieldValue).toString()); configForm->leIpId->setText(uintToHexStr(data.id(), 2)); configForm->leIpFragOfs->setText(QString().setNum(data.frag_ofs())); configForm->cbIpFlagsDf->setChecked((data.flags() & IP_FLAG_DF) > 0); configForm->cbIpFlagsMf->setChecked((data.flags() & IP_FLAG_MF) > 0); configForm->leIpTtl->setText(QString().setNum(data.ttl())); configForm->cbIpProtocolOverride->setChecked(data.is_override_proto()); configForm->leIpProto->setText(uintToHexStr( fieldData(ip4_proto, FieldValue).toUInt(), 1)); configForm->cbIpCksumOverride->setChecked(data.is_override_cksum()); configForm->leIpCksum->setText(uintToHexStr( fieldData(ip4_cksum, FieldValue).toUInt(), 2)); configForm->leIpSrcAddr->setText(QHostAddress(data.src_ip()).toString()); configForm->cmbIpSrcAddrMode->setCurrentIndex(data.src_ip_mode()); configForm->leIpSrcAddrCount->setText(QString().setNum(data.src_ip_count())); configForm->leIpSrcAddrMask->setText(QHostAddress(data.src_ip_mask()).toString()); configForm->leIpDstAddr->setText(QHostAddress(data.dst_ip()).toString()); configForm->cmbIpDstAddrMode->setCurrentIndex(data.dst_ip_mode()); configForm->leIpDstAddrCount->setText(QString().setNum(data.dst_ip_count())); configForm->leIpDstAddrMask->setText(QHostAddress(data.dst_ip_mask()).toString()); } void Ip4Protocol::storeConfigWidget() { uint ff = 0; bool isOk; configWidget(); data.set_is_override_ver(configForm->cbIpVersionOverride->isChecked()); data.set_ver_hdrlen(((configForm->leIpVersion->text().toULong(&isOk) & 0x0F) << 4) | (configForm->leIpHdrLen->text().toULong(&isOk) & 0x0F)); data.set_is_override_hdrlen(configForm->cbIpHdrLenOverride->isChecked()); data.set_tos(configForm->leIpTos->text().toULong(&isOk, 16)); data.set_totlen(configForm->leIpLength->text().toULong(&isOk)); data.set_is_override_totlen(configForm->cbIpLengthOverride->isChecked()); data.set_id(configForm->leIpId->text().remove(QChar(' ')).toULong(&isOk, 16)); data.set_frag_ofs(configForm->leIpFragOfs->text().toULong(&isOk)); if (configForm->cbIpFlagsDf->isChecked()) ff |= IP_FLAG_DF; if (configForm->cbIpFlagsMf->isChecked()) ff |= IP_FLAG_MF; data.set_flags(ff); data.set_ttl(configForm->leIpTtl->text().toULong(&isOk)); data.set_is_override_proto(configForm->cbIpProtocolOverride->isChecked()); data.set_proto(configForm->leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16)); data.set_is_override_cksum(configForm->cbIpCksumOverride->isChecked()); data.set_cksum(configForm->leIpCksum->text().remove(QChar(' ')).toULong(&isOk, 16)); data.set_src_ip(QHostAddress(configForm->leIpSrcAddr->text()).toIPv4Address()); data.set_src_ip_mode((OstProto::Ip4_IpAddrMode)configForm->cmbIpSrcAddrMode->currentIndex()); data.set_src_ip_count(configForm->leIpSrcAddrCount->text().toULong(&isOk)); data.set_src_ip_mask(QHostAddress(configForm->leIpSrcAddrMask->text()).toIPv4Address()); data.set_dst_ip(QHostAddress(configForm->leIpDstAddr->text()).toIPv4Address()); data.set_dst_ip_mode((OstProto::Ip4_IpAddrMode)configForm->cmbIpDstAddrMode->currentIndex()); data.set_dst_ip_count(configForm->leIpDstAddrCount->text().toULong(&isOk)); data.set_dst_ip_mask(QHostAddress(configForm->leIpDstAddrMask->text()).toIPv4Address()); } ostinato-0.5.1/common/ip4.h0000700000175300010010000000603312005505614015027 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IPV4_H #define _IPV4_H #include "abstractprotocol.h" #include "ip4.pb.h" #include "ui_ip4.h" #define IP_FLAG_MF 0x1 #define IP_FLAG_DF 0x2 #define IP_FLAG_UNUSED 0x4 class Ip4ConfigForm : public QWidget, public Ui::ip4 { Q_OBJECT public: Ip4ConfigForm(QWidget *parent = 0); ~Ip4ConfigForm(); private slots: void on_cmbIpSrcAddrMode_currentIndexChanged(int index); void on_cmbIpDstAddrMode_currentIndexChanged(int index); }; class Ip4Protocol : public AbstractProtocol { private: OstProto::Ip4 data; Ip4ConfigForm *configForm; enum ip4field { ip4_ver = 0, ip4_hdrLen, ip4_tos, ip4_totLen, ip4_id, ip4_flags, ip4_fragOfs, ip4_ttl, ip4_proto, ip4_cksum, ip4_srcAddr, ip4_dstAddr, ip4_isOverrideVer, ip4_isOverrideHdrLen, ip4_isOverrideTotLen, ip4_isOverrideProto, ip4_isOverrideCksum, ip4_srcAddrMode, ip4_srcAddrCount, ip4_srcAddrMask, ip4_dstAddrMode, ip4_dstAddrCount, ip4_dstAddrMask, ip4_fieldCount }; public: Ip4Protocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~Ip4Protocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual quint32 protocolFrameCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/ip4.proto0000700000175300010010000000377512005505614015755 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // IPv4 message Ip4 { enum IpAddrMode { e_im_fixed = 0; e_im_inc_host = 1; e_im_dec_host = 2; e_im_random_host = 3; } optional bool is_override_ver = 1; optional bool is_override_hdrlen = 2; optional bool is_override_totlen = 3; optional bool is_override_proto = 30; optional bool is_override_cksum = 4; optional uint32 ver_hdrlen = 5 [default = 0x45]; optional uint32 tos = 6; optional uint32 totlen = 7; optional uint32 id = 8 [default = 1234]; optional uint32 flags = 9; optional uint32 frag_ofs = 10; optional uint32 ttl = 11 [default = 127]; optional uint32 proto = 12; optional uint32 cksum = 13; // Source IP optional fixed32 src_ip = 14; optional IpAddrMode src_ip_mode = 15 [default = e_im_fixed]; optional uint32 src_ip_count = 16 [default = 16]; optional fixed32 src_ip_mask = 17 [default = 0xFFFFFF00]; // Destination IP optional fixed32 dst_ip = 18; optional IpAddrMode dst_ip_mode = 19 [default = e_im_fixed]; optional uint32 dst_ip_count = 20 [default = 16]; optional fixed32 dst_ip_mask = 21 [default = 0xFFFFFF00]; //! \todo (LOW) IPv4 Options } extend Protocol { optional Ip4 ip4 = 301; } ostinato-0.5.1/common/ip4.ui0000700000175300010010000003264012005505614015220 0ustar srivatspNone ip4 0 0 507 308 Form Override Version false Override Header Length (x4) false TOS/DSCP >HH; Override Length false Identification >HH HH; Fragment Offset (x8) Don't Fragment More Fragments Time To Live (TTL) false >HH; Override Checksum false >HH HH; Override Protocol false Qt::Horizontal 101 20 Mode Count Mask Source 009.009.009.009; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false false 009.009.009.009; ... Destination 000.000.000.000; ... Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false false 009.009.009.009; ... Options false TODO false ... Qt::Vertical 20 40 cbIpVersionOverride leIpVersion cbIpHdrLenOverride leIpHdrLen leIpTos cbIpLengthOverride leIpLength leIpId leIpFragOfs cbIpFlagsDf cbIpFlagsMf leIpTtl cbIpProtocolOverride leIpProto cbIpCksumOverride leIpCksum leIpSrcAddr cmbIpSrcAddrMode leIpSrcAddrCount leIpSrcAddrMask leIpDstAddr cmbIpDstAddrMode leIpDstAddrCount leIpDstAddrMask leIpOptions tbIpOptionsEdit cbIpVersionOverride toggled(bool) leIpVersion setEnabled(bool) 108 11 195 11 cbIpHdrLenOverride toggled(bool) leIpHdrLen setEnabled(bool) 113 67 166 43 cbIpLengthOverride toggled(bool) leIpLength setEnabled(bool) 89 118 236 119 cbIpCksumOverride toggled(bool) leIpCksum setEnabled(bool) 387 140 406 122 cbIpProtocolOverride toggled(bool) leIpProto setEnabled(bool) 363 95 398 94 ostinato-0.5.1/common/ip4over4.h0000700000175300010010000000572512005505614016016 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP_4_OVER_4_H #define _IP_4_OVER_4_H #include "ip4over4.pb.h" #include "comboprotocol.h" #include "ip4.h" typedef ComboProtocol Ip4over4Combo; class Ip4over4Protocol : public Ip4over4Combo { public: Ip4over4Protocol(StreamBase *stream, AbstractProtocol *parent = 0) : Ip4over4Combo(stream, parent) { } static Ip4over4Protocol* createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Ip4over4Protocol(stream, parent); } virtual void protoDataCopyInto(OstProto::Protocol &protocol) const { OstProto::Protocol tempProto; protoA->protoDataCopyInto(tempProto); protocol.MutableExtension(OstProto::ip4over4) ->MutableExtension(OstProto::ip4_outer) ->CopyFrom(tempProto.GetExtension(OstProto::ip4)); tempProto.Clear(); protoB->protoDataCopyInto(tempProto); protocol.MutableExtension(OstProto::ip4over4) ->MutableExtension(OstProto::ip4_inner) ->CopyFrom(tempProto.GetExtension(OstProto::ip4)); protocol.mutable_protocol_id()->set_id(protocolNumber()); } virtual void protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::ip4over4)) { OstProto::Protocol tempProto; // NOTE: To use protoX->protoDataCopyFrom() we need to arrange // so that it sees its own protocolNumber() and its own extension // in 'protocol' tempProto.mutable_protocol_id()->set_id(protoA->protocolNumber()); tempProto.MutableExtension(OstProto::ip4)->CopyFrom( protocol.GetExtension(OstProto::ip4over4).GetExtension( OstProto::ip4_outer)); protoA->protoDataCopyFrom(tempProto); tempProto.Clear(); tempProto.mutable_protocol_id()->set_id(protoB->protocolNumber()); tempProto.MutableExtension(OstProto::ip4)->CopyFrom( protocol.GetExtension(OstProto::ip4over4).GetExtension( OstProto::ip4_inner)); protoB->protoDataCopyFrom(tempProto); } } }; #endif ostinato-0.5.1/common/ip4over4.proto0000700000175300010010000000167712005505614016734 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "ip4.proto"; package OstProto; // IP 4over4 (also called IPIP) message Ip4over4 { extensions 1 to 2; } extend Ip4over4 { optional Ip4 ip4_outer = 1; optional Ip4 ip4_inner = 2; } extend Protocol { optional Ip4over4 ip4over4 = 305; } ostinato-0.5.1/common/ip4over6.h0000700000175300010010000000161012005505614016005 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP_4_OVER_6_H #define _IP_4_OVER_6_H #include "comboprotocol.h" #include "ip4.h" #include "ip6.h" typedef ComboProtocol Ip4over6Protocol; #endif ostinato-0.5.1/common/ip4over6.proto0000700000175300010010000000155212005505614016726 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // IP Tunelling - IP 4over6 message Ip4over6 { // Empty since this is a 'combo' protocol } extend Protocol { optional Ip4over6 ip4over6 = 304; } ostinato-0.5.1/common/ip6.cpp0000700000175300010010000007142612005505614015374 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "ip6.h" #include "ipv6addressvalidator.h" #include #include Ip6ConfigForm::Ip6ConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); version->setValidator(new QIntValidator(0, 0xF, this)); payloadLength->setValidator(new QIntValidator(0, 0xFFFF, this)); hopLimit->setValidator(new QIntValidator(0, 0xFF, this)); srcAddr->setValidator(new IPv6AddressValidator(this)); srcAddrCount->setValidator(new QIntValidator(this)); //srcAddrPrefix->setValidator(new QIntValidator(0, 128, this)); dstAddr->setValidator(new IPv6AddressValidator(this)); dstAddrCount->setValidator(new QIntValidator(this)); //dstAddrPrefix->setValidator(new QIntValidator(0, 128, this)); } void Ip6ConfigForm::on_srcAddr_editingFinished() { srcAddr->setText(QHostAddress(srcAddr->text()).toString()); } void Ip6ConfigForm::on_dstAddr_editingFinished() { dstAddr->setText(QHostAddress(dstAddr->text()).toString()); } void Ip6ConfigForm::on_srcAddrModeCombo_currentIndexChanged(int index) { bool enabled = (index > 0); srcAddrCount->setEnabled(enabled); srcAddrPrefix->setEnabled(enabled); } void Ip6ConfigForm::on_dstAddrModeCombo_currentIndexChanged(int index) { bool enabled = (index > 0); dstAddrCount->setEnabled(enabled); dstAddrPrefix->setEnabled(enabled); } Ip6Protocol::Ip6Protocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { /* The configWidget is created lazily */ configForm = NULL; } Ip6Protocol::~Ip6Protocol() { delete configForm; } AbstractProtocol* Ip6Protocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Ip6Protocol(stream, parent); } quint32 Ip6Protocol::protocolNumber() const { return OstProto::Protocol::kIp6FieldNumber; } void Ip6Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::ip6)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void Ip6Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::ip6)) data.MergeFrom(protocol.GetExtension(OstProto::ip6)); } QString Ip6Protocol::name() const { return QString("Internet Protocol ver 6"); } QString Ip6Protocol::shortName() const { return QString("IPv6"); } AbstractProtocol::ProtocolIdType Ip6Protocol::protocolIdType() const { return ProtocolIdIp; } quint32 Ip6Protocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdEth: return 0x86dd; case ProtocolIdIp: return 0x29; default:break; } return AbstractProtocol::protocolId(type); } int Ip6Protocol::fieldCount() const { return ip6_fieldCount; } AbstractProtocol::FieldFlags Ip6Protocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case ip6_version: case ip6_trafficClass: case ip6_flowLabel: case ip6_payloadLength: case ip6_nextHeader: case ip6_hopLimit: case ip6_srcAddress: case ip6_dstAddress: break; case ip6_isOverrideVersion: case ip6_isOverridePayloadLength: case ip6_isOverrideNextHeader: case ip6_srcAddrMode: case ip6_srcAddrCount: case ip6_srcAddrPrefix: case ip6_dstAddrMode: case ip6_dstAddrCount: case ip6_dstAddrPrefix: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant Ip6Protocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case ip6_version: { quint8 ver; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_version()) ver = data.version() & 0xF; else ver = 0x6; break; default: ver = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Version"); case FieldValue: return ver; case FieldTextValue: return QString("%1").arg(ver); case FieldFrameValue: return QByteArray(1, char(ver)); case FieldBitSize: return 4; default: break; } break; } case ip6_trafficClass: { switch(attrib) { case FieldName: return QString("Traffic Class"); case FieldValue: return data.traffic_class() & 0xFF; case FieldTextValue: return QString("%1").arg(data.traffic_class() & 0xFF, 2, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, char(data.traffic_class() & 0xFF)); default: break; } break; } case ip6_flowLabel: { switch(attrib) { case FieldName: return QString("Flow Label"); case FieldValue: return data.flow_label() & 0xFFFFF; case FieldTextValue: return QString("%1").arg(data.flow_label() & 0xFFFFF, 5, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) data.flow_label() & 0xFFFFF, (uchar*) fv.data()); fv = fv.right(3); return fv; } case FieldBitSize: return 20; default: break; } break; } case ip6_payloadLength: { quint16 len; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_payload_length()) len = data.payload_length(); else len = protocolFramePayloadSize(streamIndex); break; default: len = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Payload Length"); case FieldValue: return len; case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(len, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("%1").arg(len); case FieldBitSize: return 16; default: break; } break; } case ip6_nextHeader: { quint8 nextHdr; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_next_header()) nextHdr = data.next_header(); else nextHdr = payloadProtocolId(ProtocolIdIp); break; default: nextHdr = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Next Header"); case FieldValue: return nextHdr; case FieldTextValue: return QString("%1").arg(nextHdr, 2, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, char(nextHdr)); default: break; } break; } case ip6_hopLimit: { switch(attrib) { case FieldName: return QString("Hop Limit"); case FieldValue: return data.hop_limit() & 0xFF; case FieldTextValue: return QString("%1").arg(data.hop_limit() & 0xFF); case FieldFrameValue: return QByteArray(1, char(data.hop_limit() & 0xFF)); default: break; } break; } case ip6_srcAddress: { int u, p, q; quint64 maskHi = 0, maskLo = 0; quint64 prefixHi, prefixLo; quint64 hostHi = 0, hostLo = 0; quint64 srcHi = 0, srcLo = 0; switch(data.src_addr_mode()) { case OstProto::Ip6::kFixed: srcHi = data.src_addr_hi(); srcLo = data.src_addr_lo(); break; case OstProto::Ip6::kIncHost: case OstProto::Ip6::kDecHost: case OstProto::Ip6::kRandomHost: u = streamIndex % data.src_addr_count(); if (data.src_addr_prefix() > 64) { p = 64; q = data.src_addr_prefix() - 64; } else { p = data.src_addr_prefix(); q = 0; } if (p > 0) maskHi = ~((quint64(1) << p) - 1); if (q > 0) maskLo = ~((quint64(1) << q) - 1); prefixHi = data.src_addr_hi() & maskHi; prefixLo = data.src_addr_lo() & maskLo; if (data.src_addr_mode() == OstProto::Ip6::kIncHost) { hostHi = ((data.src_addr_hi() & ~maskHi) + u) & ~maskHi; hostLo = ((data.src_addr_lo() & ~maskLo) + u) & ~maskLo; } else if (data.src_addr_mode() == OstProto::Ip6::kDecHost) { hostHi = ((data.src_addr_hi() & ~maskHi) - u) & ~maskHi; hostLo = ((data.src_addr_lo() & ~maskLo) - u) & ~maskLo; } else if (data.src_addr_mode()==OstProto::Ip6::kRandomHost) { hostHi = qrand() & ~maskHi; hostLo = qrand() & ~maskLo; } srcHi = prefixHi | hostHi; srcLo = prefixLo | hostLo; break; default: qWarning("Unhandled src_addr_mode = %d", data.src_addr_mode()); } switch(attrib) { case FieldName: return QString("Source"); case FieldValue: case FieldFrameValue: case FieldTextValue: { QByteArray fv; fv.resize(16); qToBigEndian(srcHi, (uchar*) fv.data()); qToBigEndian(srcLo, (uchar*) (fv.data() + 8)); if (attrib == FieldTextValue) return QHostAddress((quint8*)fv.constData()).toString(); else return fv; } default: break; } break; } case ip6_dstAddress: { int u, p, q; quint64 maskHi = 0, maskLo = 0; quint64 prefixHi, prefixLo; quint64 hostHi = 0, hostLo = 0; quint64 dstHi = 0, dstLo = 0; switch(data.dst_addr_mode()) { case OstProto::Ip6::kFixed: dstHi = data.dst_addr_hi(); dstLo = data.dst_addr_lo(); break; case OstProto::Ip6::kIncHost: case OstProto::Ip6::kDecHost: case OstProto::Ip6::kRandomHost: u = streamIndex % data.dst_addr_count(); if (data.dst_addr_prefix() > 64) { p = 64; q = data.dst_addr_prefix() - 64; } else { p = data.dst_addr_prefix(); q = 0; } if (p > 0) maskHi = ~((quint64(1) << p) - 1); if (q > 0) maskLo = ~((quint64(1) << q) - 1); prefixHi = data.dst_addr_hi() & maskHi; prefixLo = data.dst_addr_lo() & maskLo; if (data.dst_addr_mode() == OstProto::Ip6::kIncHost) { hostHi = ((data.dst_addr_hi() & ~maskHi) + u) & ~maskHi; hostLo = ((data.dst_addr_lo() & ~maskLo) + u) & ~maskLo; } else if (data.dst_addr_mode() == OstProto::Ip6::kDecHost) { hostHi = ((data.dst_addr_hi() & ~maskHi) - u) & ~maskHi; hostLo = ((data.dst_addr_lo() & ~maskLo) - u) & ~maskLo; } else if (data.dst_addr_mode()==OstProto::Ip6::kRandomHost) { hostHi = qrand() & ~maskHi; hostLo = qrand() & ~maskLo; } dstHi = prefixHi | hostHi; dstLo = prefixLo | hostLo; break; default: qWarning("Unhandled dst_addr_mode = %d", data.dst_addr_mode()); } switch(attrib) { case FieldName: return QString("Destination"); case FieldValue: case FieldFrameValue: case FieldTextValue: { QByteArray fv; fv.resize(16); qToBigEndian(dstHi, (uchar*) fv.data()); qToBigEndian(dstLo, (uchar*) (fv.data() + 8)); if (attrib == FieldTextValue) return QHostAddress((quint8*)fv.constData()).toString(); else return fv; } default: break; } break; } // Meta-Fields case ip6_isOverrideVersion: { switch(attrib) { case FieldValue: return data.is_override_version(); default: break; } break; } case ip6_isOverridePayloadLength: { switch(attrib) { case FieldValue: return data.is_override_payload_length(); default: break; } break; } case ip6_isOverrideNextHeader: { switch(attrib) { case FieldValue: return data.is_override_next_header(); default: break; } break; } case ip6_srcAddrMode: { switch(attrib) { case FieldValue: return data.src_addr_mode(); default: break; } break; } case ip6_srcAddrCount: { switch(attrib) { case FieldValue: return data.src_addr_count(); default: break; } break; } case ip6_srcAddrPrefix: { switch(attrib) { case FieldValue: return data.src_addr_prefix(); default: break; } break; } case ip6_dstAddrMode: { switch(attrib) { case FieldValue: return data.dst_addr_mode(); default: break; } break; } case ip6_dstAddrCount: { switch(attrib) { case FieldValue: return data.dst_addr_count(); default: break; } break; } case ip6_dstAddrPrefix: { switch(attrib) { case FieldValue: return data.dst_addr_prefix(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool Ip6Protocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case ip6_version: { uint ver = value.toUInt(&isOk); if (isOk) data.set_version(ver & 0xF); break; } case ip6_trafficClass: { uint trfClass = value.toUInt(&isOk); if (isOk) data.set_traffic_class(trfClass & 0xFF); break; } case ip6_flowLabel: { uint fl = value.toUInt(&isOk); if (isOk) data.set_flow_label(fl & 0xFFFFF); break; } case ip6_payloadLength: { uint len = value.toUInt(&isOk); if (isOk) data.set_payload_length(len & 0xFFFF); break; } case ip6_nextHeader: { uint ver = value.toUInt(&isOk); if (isOk) data.set_next_header(ver & 0xFF); break; } case ip6_hopLimit: { uint hl = value.toUInt(&isOk); if (isOk) data.set_hop_limit(hl & 0xFF); break; } case ip6_srcAddress: { Q_IPV6ADDR addr = QHostAddress(value.toString()).toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); data.set_src_addr_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); data.set_src_addr_lo(x); break; } case ip6_dstAddress: { Q_IPV6ADDR addr = QHostAddress(value.toString()).toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); data.set_dst_addr_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); data.set_dst_addr_lo(x); break; } // Meta-Fields case ip6_isOverrideVersion: { bool ovr = value.toBool(); data.set_is_override_version(ovr); isOk = true; break; } case ip6_isOverridePayloadLength: { bool ovr = value.toBool(); data.set_is_override_payload_length(ovr); isOk = true; break; } case ip6_isOverrideNextHeader: { bool ovr = value.toBool(); data.set_is_override_next_header(ovr); isOk = true; break; } case ip6_srcAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.AddrMode_IsValid(mode)) data.set_src_addr_mode((OstProto::Ip6::AddrMode) mode); else isOk = false; break; } case ip6_srcAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_src_addr_count(count); break; } case ip6_srcAddrPrefix: { uint prefix = value.toUInt(&isOk); if (isOk) data.set_src_addr_prefix(prefix); break; } case ip6_dstAddrMode: { uint mode = value.toUInt(&isOk); if (isOk && data.AddrMode_IsValid(mode)) data.set_dst_addr_mode((OstProto::Ip6::AddrMode) mode); else isOk = false; break; } case ip6_dstAddrCount: { uint count = value.toUInt(&isOk); if (isOk) data.set_dst_addr_count(count); break; } case ip6_dstAddrPrefix: { uint prefix = value.toUInt(&isOk); if (isOk) data.set_dst_addr_prefix(prefix); break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } bool Ip6Protocol::isProtocolFrameValueVariable() const { if ((data.src_addr_mode() != OstProto::Ip6::kFixed) || (data.dst_addr_mode() != OstProto::Ip6::kFixed)) return true; else return false; } int Ip6Protocol::protocolFrameVariableCount() const { int count = 1; if (data.src_addr_mode() != OstProto::Ip6::kFixed) count = AbstractProtocol::lcm(count, data.src_addr_count()); if (data.dst_addr_mode() != OstProto::Ip6::kFixed) count = AbstractProtocol::lcm(count, data.dst_addr_count()); return count; } quint32 Ip6Protocol::protocolFrameCksum(int streamIndex, CksumType cksumType) const { if (cksumType == CksumIpPseudo) { QByteArray addr; quint32 sum = 0; addr = fieldData(ip6_srcAddress, FieldFrameValue, streamIndex) .toByteArray(); Q_ASSERT(addr.size() == 16); for (int i = 0; i < addr.size(); i+=2) sum += (quint8(addr.at(i)) << 8) + quint8(addr.at(i+1)); addr = fieldData(ip6_dstAddress, FieldFrameValue, streamIndex) .toByteArray(); Q_ASSERT(addr.size() == 16); for (int i = 0; i < addr.size(); i+=2) sum += (quint8(addr.at(i)) << 8) + quint8(addr.at(i+1)); sum += fieldData(ip6_payloadLength, FieldValue, streamIndex) .toUInt() & 0xFFFF; sum += fieldData(ip6_nextHeader, FieldValue, streamIndex) .toUInt() & 0xFF; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); return ~sum; } return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType); } QWidget* Ip6Protocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new Ip6ConfigForm; loadConfigWidget(); } return configForm; } void Ip6Protocol::loadConfigWidget() { configWidget(); configForm->isVersionOverride->setChecked( fieldData(ip6_isOverrideVersion, FieldValue).toBool()); configForm->version->setText( fieldData(ip6_version, FieldValue).toString()); configForm->trafficClass->setText(uintToHexStr( fieldData(ip6_trafficClass, FieldValue).toUInt(), 1)); configForm->flowLabel->setText(QString("%1").arg( fieldData(ip6_flowLabel, FieldValue).toUInt(),5, BASE_HEX, QChar('0'))); configForm->isPayloadLengthOverride->setChecked( fieldData(ip6_isOverridePayloadLength, FieldValue).toBool()); configForm->payloadLength->setText( fieldData(ip6_payloadLength, FieldValue).toString()); configForm->isNextHeaderOverride->setChecked( fieldData(ip6_isOverrideNextHeader, FieldValue).toBool()); configForm->nextHeader->setText(uintToHexStr( fieldData(ip6_nextHeader, FieldValue).toUInt(), 1)); configForm->hopLimit->setText( fieldData(ip6_hopLimit, FieldValue).toString()); configForm->srcAddr->setText( fieldData(ip6_srcAddress, FieldTextValue).toString()); configForm->srcAddrModeCombo->setCurrentIndex( fieldData(ip6_srcAddrMode, FieldValue).toUInt()); configForm->srcAddrCount->setText( fieldData(ip6_srcAddrCount, FieldValue).toString()); configForm->srcAddrPrefix->setText( fieldData(ip6_srcAddrPrefix, FieldValue).toString()); configForm->dstAddr->setText( fieldData(ip6_dstAddress, FieldTextValue).toString()); configForm->dstAddrModeCombo->setCurrentIndex( fieldData(ip6_dstAddrMode, FieldValue).toUInt()); configForm->dstAddrCount->setText( fieldData(ip6_dstAddrCount, FieldValue).toString()); configForm->dstAddrPrefix->setText( fieldData(ip6_dstAddrPrefix, FieldValue).toString()); } void Ip6Protocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(ip6_isOverrideVersion, configForm->isVersionOverride->isChecked()); setFieldData(ip6_version, configForm->version->text()); setFieldData(ip6_trafficClass, configForm->trafficClass->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX)); setFieldData(ip6_flowLabel, configForm->flowLabel->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX)); setFieldData(ip6_isOverridePayloadLength, configForm->isPayloadLengthOverride->isChecked()); setFieldData(ip6_payloadLength, configForm->payloadLength->text()); setFieldData(ip6_isOverrideNextHeader, configForm->isNextHeaderOverride->isChecked()); setFieldData(ip6_nextHeader, configForm->nextHeader->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX)); setFieldData(ip6_hopLimit, configForm->hopLimit->text()); setFieldData(ip6_srcAddress, configForm->srcAddr->text()); setFieldData(ip6_srcAddrMode, configForm->srcAddrModeCombo->currentIndex()); setFieldData(ip6_srcAddrCount, configForm->srcAddrCount->text()); setFieldData(ip6_srcAddrPrefix, configForm->srcAddrPrefix->text()); setFieldData(ip6_dstAddress, configForm->dstAddr->text()); setFieldData(ip6_dstAddrMode, configForm->dstAddrModeCombo->currentIndex()); setFieldData(ip6_dstAddrCount, configForm->dstAddrCount->text()); setFieldData(ip6_dstAddrPrefix, configForm->dstAddrPrefix->text()); } ostinato-0.5.1/common/ip6.h0000700000175300010010000000752112005505614015034 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP6_H #define _IP6_H #include "ip6.pb.h" #include "ui_ip6.h" #include "abstractprotocol.h" /* IPv6 Protocol Frame Format - +-----+----------+-----------------------+ | Ver | TrfClass | FlowLabel | | (4) | (8) | (20) | +-----+-------------+---------+----------+ | Payload Length | NextHdr | HopLimit | | (16) | (8) | (8) | +-------------------+---------+----------+ | | | Source Address | | (128) | | | +-----+------+------+------+------+------+ | | | Destination Address | | (128) | | | +-----+------+------+------+------+------+ Figures in brackets represent field width in bits */ class Ip6ConfigForm : public QWidget, public Ui::Ip6 { Q_OBJECT public: Ip6ConfigForm(QWidget *parent = 0); private slots: void on_srcAddr_editingFinished(); void on_dstAddr_editingFinished(); void on_srcAddrModeCombo_currentIndexChanged(int index); void on_dstAddrModeCombo_currentIndexChanged(int index); }; class Ip6Protocol : public AbstractProtocol { private: OstProto::Ip6 data; Ip6ConfigForm *configForm; enum ip6field { // Frame Fields ip6_version = 0, ip6_trafficClass, ip6_flowLabel, ip6_payloadLength, ip6_nextHeader, ip6_hopLimit, ip6_srcAddress, ip6_dstAddress, // Meta Fields ip6_isOverrideVersion, ip6_isOverridePayloadLength, ip6_isOverrideNextHeader, ip6_srcAddrMode, ip6_srcAddrCount, ip6_srcAddrPrefix, ip6_dstAddrMode, ip6_dstAddrCount, ip6_dstAddrPrefix, ip6_fieldCount }; public: Ip6Protocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~Ip6Protocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual quint32 protocolFrameCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/ip6.proto0000700000175300010010000000343012005505614015743 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Ip6 Protocol message Ip6 { enum AddrMode { kFixed = 0; kIncHost = 1; kDecHost = 2; kRandomHost = 3; } optional bool is_override_version = 1; optional bool is_override_payload_length = 2; optional bool is_override_next_header = 3; optional uint32 version = 4 [default = 0x6]; optional uint32 traffic_class = 5; optional uint32 flow_label = 6; optional uint32 payload_length = 7; optional uint32 next_header = 8; optional uint32 hop_limit = 9 [default = 127]; optional uint64 src_addr_hi = 10; optional uint64 src_addr_lo = 11; optional AddrMode src_addr_mode = 12 [default = kFixed]; optional uint32 src_addr_count = 13 [default = 16]; optional uint32 src_addr_prefix = 14 [default = 64]; optional uint64 dst_addr_hi = 15; optional uint64 dst_addr_lo = 16; optional AddrMode dst_addr_mode = 17 [default = kFixed]; optional uint32 dst_addr_count = 18 [default = 16]; optional uint32 dst_addr_prefix = 19 [default = 64]; } extend Protocol { optional Ip6 ip6 = 302; } ostinato-0.5.1/common/ip6.ui0000700000175300010010000003053112005505614015217 0ustar srivatspNone Ip6 0 0 506 233 Form Version false Qt::Vertical Payload Length false Traffic Class trafficClass >HH; Next Header false HH; Flow Label flowLabel >H HH HH; Hop Limit hopLimit false Qt::Horizontal 51 20 Address Mode Count Prefix Source 1 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false 0 0 50 16777215 10 false 0 0 50 16777215 /009; /64 Destination 1 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Fixed Increment Host Decrement Host Random Host false 0 0 50 16777215 10 false 0 0 50 16777215 /009; /64 Qt::Vertical 20 40 isVersionOverride version trafficClass flowLabel isPayloadLengthOverride payloadLength isNextHeaderOverride nextHeader hopLimit srcAddr srcAddrModeCombo srcAddrCount srcAddrPrefix dstAddr dstAddrModeCombo dstAddrCount dstAddrPrefix isVersionOverride toggled(bool) version setEnabled(bool) 67 22 195 11 isPayloadLengthOverride toggled(bool) payloadLength setEnabled(bool) 319 28 493 29 isNextHeaderOverride toggled(bool) nextHeader setEnabled(bool) 316 41 348 46 ostinato-0.5.1/common/ip6over4.h0000700000175300010010000000161012005505614016005 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP_6_OVER_4_H #define _IP_6_OVER_4_H #include "comboprotocol.h" #include "ip4.h" #include "ip6.h" typedef ComboProtocol Ip6over4Protocol; #endif ostinato-0.5.1/common/ip6over4.proto0000700000175300010010000000155212005505614016726 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // IP Tunelling - IP 6over4 message Ip6over4 { // Empty since this is a 'combo' protocol } extend Protocol { optional Ip6over4 ip6over4 = 303; } ostinato-0.5.1/common/ip6over6.h0000700000175300010010000000572512005505614016022 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP_6_OVER_6_H #define _IP_6_OVER_6_H #include "ip6over6.pb.h" #include "comboprotocol.h" #include "ip6.h" typedef ComboProtocol Ip6over6Combo; class Ip6over6Protocol : public Ip6over6Combo { public: Ip6over6Protocol(StreamBase *stream, AbstractProtocol *parent = 0) : Ip6over6Combo(stream, parent) { } static Ip6over6Protocol* createInstance(StreamBase *stream, AbstractProtocol *parent) { return new Ip6over6Protocol(stream, parent); } virtual void protoDataCopyInto(OstProto::Protocol &protocol) const { OstProto::Protocol tempProto; protoA->protoDataCopyInto(tempProto); protocol.MutableExtension(OstProto::ip6over6) ->MutableExtension(OstProto::ip6_outer) ->CopyFrom(tempProto.GetExtension(OstProto::ip6)); tempProto.Clear(); protoB->protoDataCopyInto(tempProto); protocol.MutableExtension(OstProto::ip6over6) ->MutableExtension(OstProto::ip6_inner) ->CopyFrom(tempProto.GetExtension(OstProto::ip6)); protocol.mutable_protocol_id()->set_id(protocolNumber()); } virtual void protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::ip6over6)) { OstProto::Protocol tempProto; // NOTE: To use protoX->protoDataCopyFrom() we need to arrange // so that it sees its own protocolNumber() and its own extension // in 'protocol' tempProto.mutable_protocol_id()->set_id(protoA->protocolNumber()); tempProto.MutableExtension(OstProto::ip6)->CopyFrom( protocol.GetExtension(OstProto::ip6over6).GetExtension( OstProto::ip6_outer)); protoA->protoDataCopyFrom(tempProto); tempProto.Clear(); tempProto.mutable_protocol_id()->set_id(protoB->protocolNumber()); tempProto.MutableExtension(OstProto::ip6)->CopyFrom( protocol.GetExtension(OstProto::ip6over6).GetExtension( OstProto::ip6_inner)); protoB->protoDataCopyFrom(tempProto); } } }; #endif ostinato-0.5.1/common/ip6over6.proto0000700000175300010010000000167412005505614016735 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "ip6.proto"; package OstProto; // IP Tunnelling - IP 6over6 message Ip6over6 { extensions 1 to 2; } extend Ip6over6 { optional Ip6 ip6_outer = 1; optional Ip6 ip6_inner = 2; } extend Protocol { optional Ip6over6 ip6over6 = 306; } ostinato-0.5.1/common/iputils.h0000700000175300010010000000636412005505614016033 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IP_UTILS_H #define _IP_UTILS_H namespace ipUtils { enum AddrMode { kFixed = 0, kIncrement = 1, kDecrement = 2, kRandom = 3 }; quint32 inline ipAddress(quint32 baseIp, int prefix, AddrMode mode, int count, int index) { int u; quint32 mask = ((1< 64) { p = 64; q = prefix - 64; } else { p = prefix; q = 0; } if (p > 0) maskHi = ~((quint64(1) << p) - 1); if (q > 0) maskLo = ~((quint64(1) << q) - 1); prefixHi = baseIpHi & maskHi; prefixLo = baseIpLo & maskLo; if (mode == kIncrement) { hostHi = ((baseIpHi & ~maskHi) + 0) & ~maskHi; hostLo = ((baseIpLo & ~maskLo) + u) & ~maskLo; } else if (mode == kDecrement) { hostHi = ((baseIpHi & ~maskHi) - 0) & ~maskHi; hostLo = ((baseIpLo & ~maskLo) - u) & ~maskLo; } else if (mode==kRandom) { hostHi = qrand() & ~maskHi; hostLo = qrand() & ~maskLo; } ipHi = prefixHi | hostHi; ipLo = prefixLo | hostLo; break; default: qWarning("Unhandled mode = %d", mode); } } } // namespace ipUtils #endif ostinato-0.5.1/common/ipv4addressdelegate.h0000700000175300010010000000306712005505614020262 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IPV4_ADDRESS_DELEGATE #define _IPV4_ADDRESS_DELEGATE #include #include class IPv4AddressDelegate : public QItemDelegate { Q_OBJECT public: IPv4AddressDelegate(QObject *parent = 0); ~IPv4AddressDelegate(); QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; inline IPv4AddressDelegate::IPv4AddressDelegate(QObject *parent) : QItemDelegate(parent) { } inline IPv4AddressDelegate::~IPv4AddressDelegate() { } inline QWidget* IPv4AddressDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QLineEdit *ipEdit; ipEdit = static_cast(QItemDelegate::createEditor( parent, option, index)); ipEdit->setInputMask("009.009.009.009;"); // FIXME: use validator return ipEdit; } #endif ostinato-0.5.1/common/ipv6addressdelegate.h0000700000175300010010000000312012005505614020252 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IPV4_ADDRESS_DELEGATE #define _IPV4_ADDRESS_DELEGATE #include "ipv6addressvalidator.h" #include #include class IPv6AddressDelegate : public QItemDelegate { Q_OBJECT public: IPv6AddressDelegate(QObject *parent = 0); ~IPv6AddressDelegate(); QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; inline IPv6AddressDelegate::IPv6AddressDelegate(QObject *parent) : QItemDelegate(parent) { } inline IPv6AddressDelegate::~IPv6AddressDelegate() { } inline QWidget* IPv6AddressDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QLineEdit *ipEdit; ipEdit = static_cast(QItemDelegate::createEditor( parent, option, index)); ipEdit->setValidator(new IPv6AddressValidator(ipEdit)); return ipEdit; } #endif ostinato-0.5.1/common/ipv6addressvalidator.h0000700000175300010010000000414412005505614020474 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _IPV6_ADDRESS_VALIDATOR_H #define _IPV6_ADDRESS_VALIDATOR_H #include #include class IPv6AddressValidator : public QValidator { public: IPv6AddressValidator(QObject *parent = 0) : QValidator(parent) { _ip6ValidChars.setPattern("[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){0,7}"); } ~IPv6AddressValidator() {} virtual QValidator::State validate(QString &input, int& /*pos*/) const { QValidator::State state; QHostAddress addr(input); //qDebug("%s: %s (%d)", __FUNCTION__, input.toAscii().constData(), pos); if (addr.protocol() == QAbstractSocket::IPv6Protocol) state = Acceptable; else if (_ip6ValidChars.exactMatch(input)) state = Intermediate; else state = Invalid; //qDebug("%s(%d): %s (%d), ", __FUNCTION__, state, //input.toAscii().constData(), pos); return state; } virtual void fixup(QString &input) const { input.append("::"); QHostAddress addr(input); int len = input.size(); //qDebug("%s: %s", __FUNCTION__, input.toAscii().constData()); while (addr.protocol() != QAbstractSocket::IPv6Protocol) { len--; Q_ASSERT(len >= 0); addr.setAddress(input.left(len)); } input = addr.toString(); } private: QRegExp _ip6ValidChars; }; #endif ostinato-0.5.1/common/llc.cpp0000700000175300010010000002061612005505614015443 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "llc.h" LlcConfigForm::LlcConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } LlcProtocol::LlcProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } LlcProtocol::~LlcProtocol() { delete configForm; } AbstractProtocol* LlcProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new LlcProtocol(stream, parent); } quint32 LlcProtocol::protocolNumber() const { return OstProto::Protocol::kLlcFieldNumber; } void LlcProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::llc)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void LlcProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::llc)) data.MergeFrom(protocol.GetExtension(OstProto::llc)); } QString LlcProtocol::name() const { return QString("802.3 Logical Link Control"); } QString LlcProtocol::shortName() const { return QString("LLC"); } AbstractProtocol::ProtocolIdType LlcProtocol::protocolIdType() const { return ProtocolIdLlc; } int LlcProtocol::fieldCount() const { return llc_fieldCount; } AbstractProtocol::FieldFlags LlcProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case llc_dsap: case llc_ssap: case llc_ctl: break; case llc_is_override_dsap: case llc_is_override_ssap: case llc_is_override_ctl: flags &= ~FrameField; flags |= MetaField; break; default: break; } return flags; } QVariant LlcProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { quint32 id; quint8 dsap, ssap, ctl; id = payloadProtocolId(ProtocolIdLlc); dsap = data.is_override_dsap() ? data.dsap() : (id >> 16) & 0xFF; ssap = data.is_override_ssap() ? data.ssap() : (id >> 8) & 0xFF; ctl = data.is_override_ctl() ? data.ctl() : (id >> 0) & 0xFF; switch (index) { case llc_dsap: switch(attrib) { case FieldName: return QString("DSAP"); case FieldValue: return dsap; case FieldTextValue: return QString("%1").arg(dsap, 2, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, (char)(dsap)); default: break; } break; case llc_ssap: switch(attrib) { case FieldName: return QString("SSAP"); case FieldValue: return ssap; case FieldTextValue: return QString("%1").arg(ssap, 2, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, (char)(ssap)); default: break; } break; case llc_ctl: switch(attrib) { case FieldName: return QString("Control"); case FieldValue: return ctl; case FieldTextValue: return QString("%1").arg(ctl, 2, BASE_HEX, QChar('0')); case FieldFrameValue: return QByteArray(1, (char)(ctl)); default: break; } break; // Meta fields case llc_is_override_dsap: { switch(attrib) { case FieldValue: return data.is_override_dsap(); default: break; } break; } case llc_is_override_ssap: { switch(attrib) { case FieldValue: return data.is_override_ssap(); default: break; } break; } case llc_is_override_ctl: { switch(attrib) { case FieldValue: return data.is_override_ctl(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool LlcProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) return false; switch (index) { case llc_dsap: { uint dsap = value.toUInt(&isOk) & 0xFF; if (isOk) data.set_dsap(dsap); break; } case llc_ssap: { uint ssap = value.toUInt(&isOk) & 0xFF; if (isOk) data.set_ssap(ssap); break; } case llc_ctl: { uint ctl = value.toUInt(&isOk) & 0xFF; if (isOk) data.set_ctl(ctl); break; } case llc_is_override_dsap: { bool ovr = value.toBool(); data.set_is_override_dsap(ovr); isOk = true; break; } case llc_is_override_ssap: { bool ovr = value.toBool(); data.set_is_override_ssap(ovr); isOk = true; break; } case llc_is_override_ctl: { bool ovr = value.toBool(); data.set_is_override_ctl(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return isOk; } QWidget* LlcProtocol::configWidget() { if (configForm == NULL) { configForm = new LlcConfigForm; loadConfigWidget(); } return configForm; } void LlcProtocol::loadConfigWidget() { #define uintToHexStr(num, bytes) \ QString("%1").arg(num, bytes*2, BASE_HEX, QChar('0')) configWidget(); configForm->cbOverrideDsap->setChecked( fieldData(llc_is_override_dsap, FieldValue).toBool()); configForm->leDsap->setText(uintToHexStr( fieldData(llc_dsap, FieldValue).toUInt(), 1)); configForm->cbOverrideSsap->setChecked( fieldData(llc_is_override_ssap, FieldValue).toBool()); configForm->leSsap->setText(uintToHexStr( fieldData(llc_ssap, FieldValue).toUInt(), 1)); configForm->cbOverrideControl->setChecked( fieldData(llc_is_override_ctl, FieldValue).toBool()); configForm->leControl->setText(uintToHexStr( fieldData(llc_ctl, FieldValue).toUInt(), 1)); #undef uintToHexStr } void LlcProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(llc_is_override_dsap, configForm->cbOverrideDsap->isChecked()); setFieldData(llc_dsap, configForm->leDsap->text().toUInt(&isOk, BASE_HEX)); setFieldData(llc_is_override_ssap, configForm->cbOverrideSsap->isChecked()); setFieldData(llc_ssap, configForm->leSsap->text().toUInt(&isOk, BASE_HEX)); setFieldData(llc_is_override_ctl, configForm->cbOverrideControl->isChecked()); setFieldData(llc_ctl, configForm->leControl->text().toUInt(&isOk, BASE_HEX)); } ostinato-0.5.1/common/llc.h0000700000175300010010000000430712005505614015107 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _LLC_H #define _LLC_H #include #include #include "abstractprotocol.h" #include "llc.pb.h" #include "ui_llc.h" class LlcConfigForm : public QWidget, public Ui::llc { Q_OBJECT public: LlcConfigForm(QWidget *parent = 0); }; class LlcProtocol : public AbstractProtocol { private: OstProto::Llc data; LlcConfigForm *configForm; enum llcfield { llc_dsap = 0, llc_ssap, llc_ctl, // Meta fields llc_is_override_dsap, llc_is_override_ssap, llc_is_override_ctl, llc_fieldCount }; public: LlcProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~LlcProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/llc.proto0000700000175300010010000000174112005505614016022 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; message Llc { optional bool is_override_dsap = 4; optional bool is_override_ssap = 5; optional bool is_override_ctl = 6; optional uint32 dsap = 1; optional uint32 ssap = 2; optional uint32 ctl = 3; } extend Protocol { optional Llc llc = 202; } ostinato-0.5.1/common/llc.ui0000700000175300010010000000725112005505614015276 0ustar srivatspNone llc 0 0 396 98 0 0 Form LLC DSAP false >HH; SSAP false >HH; Control false >HH; Qt::Horizontal 20 20 Qt::Vertical 20 40 cbOverrideDsap toggled(bool) leDsap setEnabled(bool) 54 34 92 33 cbOverrideSsap toggled(bool) leSsap setEnabled(bool) 167 34 192 33 cbOverrideControl toggled(bool) leControl setEnabled(bool) 285 34 310 33 ostinato-0.5.1/common/mac.cpp0000700000175300010010000002223012005505614015423 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "mac.h" MacConfigForm::MacConfigForm(QWidget *parent) : QWidget(parent) { QRegExp reMac("([0-9,a-f,A-F]{2,2}[:-]){5,5}[0-9,a-f,A-F]{2,2}"); setupUi(this); 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)); } MacConfigForm::~MacConfigForm() { qDebug("In MacConfigForm destructor"); } void MacConfigForm::on_cmbDstMacMode_currentIndexChanged(int index) { if (index == OstProto::Mac::e_mm_fixed) { leDstMacCount->setEnabled(false); leDstMacStep->setEnabled(false); } else { leDstMacCount->setEnabled(true); leDstMacStep->setEnabled(true); } } void MacConfigForm::on_cmbSrcMacMode_currentIndexChanged(int index) { if (index == OstProto::Mac::e_mm_fixed) { leSrcMacCount->setEnabled(false); leSrcMacStep->setEnabled(false); } else { leSrcMacCount->setEnabled(true); leSrcMacStep->setEnabled(true); } } MacProtocol::MacProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } MacProtocol::~MacProtocol() { delete configForm; } AbstractProtocol* MacProtocol::createInstance(StreamBase *stream , AbstractProtocol *parent) { return new MacProtocol(stream, parent); } quint32 MacProtocol::protocolNumber() const { return OstProto::Protocol::kMacFieldNumber; } void MacProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::mac)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void MacProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::mac)) data.MergeFrom(protocol.GetExtension(OstProto::mac)); } QString MacProtocol::name() const { return QString("Media Access Protocol"); } QString MacProtocol::shortName() const { return QString("MAC"); } int MacProtocol::fieldCount() const { return mac_fieldCount; } AbstractProtocol::FieldFlags MacProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case mac_dstAddr: case mac_srcAddr: break; case mac_dstMacMode: case mac_dstMacCount: case mac_dstMacStep: case mac_srcMacMode: case mac_srcMacCount: case mac_srcMacStep: flags &= ~FrameField; flags |= MetaField; break; } return flags; } QVariant MacProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case mac_dstAddr: { int u; quint64 dstMac = 0; switch (data.dst_mac_mode()) { case OstProto::Mac::e_mm_fixed: dstMac = data.dst_mac(); break; case OstProto::Mac::e_mm_inc: u = (streamIndex % data.dst_mac_count()) * data.dst_mac_step(); dstMac = data.dst_mac() + u; break; case OstProto::Mac::e_mm_dec: u = (streamIndex % data.dst_mac_count()) * data.dst_mac_step(); dstMac = data.dst_mac() - u; break; default: qWarning("Unhandled dstMac_mode %d", data.dst_mac_mode()); } switch(attrib) { case FieldName: return QString("Desination"); case FieldValue: return dstMac; case FieldTextValue: return uintToHexStr(dstMac, 6); case FieldFrameValue: { QByteArray fv; fv.resize(8); qToBigEndian(dstMac, (uchar*) fv.data()); fv.remove(0, 2); return fv; } default: break; } break; } case mac_srcAddr: { int u; quint64 srcMac = 0; switch (data.src_mac_mode()) { case OstProto::Mac::e_mm_fixed: srcMac = data.src_mac(); break; case OstProto::Mac::e_mm_inc: u = (streamIndex % data.src_mac_count()) * data.src_mac_step(); srcMac = data.src_mac() + u; break; case OstProto::Mac::e_mm_dec: u = (streamIndex % data.src_mac_count()) * data.src_mac_step(); srcMac = data.src_mac() - u; break; default: qWarning("Unhandled srcMac_mode %d", data.src_mac_mode()); } switch(attrib) { case FieldName: return QString("Source"); case FieldValue: return srcMac; case FieldTextValue: return uintToHexStr(srcMac, 6); case FieldFrameValue: { QByteArray fv; fv.resize(8); qToBigEndian(srcMac, (uchar*) fv.data()); fv.remove(0, 2); return fv; } default: break; } break; } // Meta fields case mac_dstMacMode: case mac_dstMacCount: case mac_dstMacStep: case mac_srcMacMode: case mac_srcMacCount: case mac_srcMacStep: default: break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool MacProtocol::setFieldData(int /*index*/, const QVariant& /*value*/, FieldAttrib /*attrib*/) { return false; } bool MacProtocol::isProtocolFrameValueVariable() const { if ((data.dst_mac_mode() != OstProto::Mac::e_mm_fixed) || (data.src_mac_mode() != OstProto::Mac::e_mm_fixed)) return true; else return false; } int MacProtocol::protocolFrameVariableCount() const { int count = 1; if (data.dst_mac_mode() != OstProto::Mac::e_mm_fixed) count = AbstractProtocol::lcm(count, data.dst_mac_count()); if (data.src_mac_mode() != OstProto::Mac::e_mm_fixed) count = AbstractProtocol::lcm(count, data.src_mac_count()); return count; } QWidget* MacProtocol::configWidget() { if (configForm == NULL) { configForm = new MacConfigForm; loadConfigWidget(); } return configForm; } void MacProtocol::loadConfigWidget() { configWidget(); configForm->leDstMac->setText(uintToHexStr(data.dst_mac(), 6)); configForm->cmbDstMacMode->setCurrentIndex(data.dst_mac_mode()); configForm->leDstMacCount->setText(QString().setNum(data.dst_mac_count())); configForm->leDstMacStep->setText(QString().setNum(data.dst_mac_step())); configForm->leSrcMac->setText(uintToHexStr(data.src_mac(), 6)); configForm->cmbSrcMacMode->setCurrentIndex(data.src_mac_mode()); configForm->leSrcMacCount->setText(QString().setNum(data.src_mac_count())); configForm->leSrcMacStep->setText(QString().setNum(data.src_mac_step())); } void MacProtocol::storeConfigWidget() { bool isOk; configWidget(); data.set_dst_mac(configForm->leDstMac->text().remove(QChar(' ')). toULongLong(&isOk, 16)); data.set_dst_mac_mode((OstProto::Mac::MacAddrMode) configForm-> cmbDstMacMode->currentIndex()); data.set_dst_mac_count(configForm->leDstMacCount->text().toULong(&isOk)); data.set_dst_mac_step(configForm->leDstMacStep->text().toULong(&isOk)); data.set_src_mac(configForm->leSrcMac->text().remove(QChar(' ')). toULongLong(&isOk, 16)); data.set_src_mac_mode((OstProto::Mac::MacAddrMode) configForm-> cmbSrcMacMode->currentIndex()); data.set_src_mac_count(configForm->leSrcMacCount->text().toULong(&isOk)); data.set_src_mac_step(configForm->leSrcMacStep->text().toULong(&isOk)); } ostinato-0.5.1/common/mac.h0000700000175300010010000000466612005505614015105 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _MAC_H #define _MAC_H #include "abstractprotocol.h" #include "mac.pb.h" #include "ui_mac.h" #define MAX_MAC_ITER_COUNT 256 class MacConfigForm : public QWidget, public Ui::mac { Q_OBJECT public: MacConfigForm(QWidget *parent = 0); virtual ~MacConfigForm(); private slots: void on_cmbDstMacMode_currentIndexChanged(int index); void on_cmbSrcMacMode_currentIndexChanged(int index); }; class MacProtocol : public AbstractProtocol { private: OstProto::Mac data; MacConfigForm *configForm; enum macfield { mac_dstAddr = 0, mac_srcAddr, mac_dstMacMode, mac_dstMacCount, mac_dstMacStep, mac_srcMacMode, mac_srcMacCount, mac_srcMacStep, mac_fieldCount }; public: MacProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~MacProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/mac.proto0000700000175300010010000000260012005505614016003 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Ethernet message Mac { enum MacAddrMode { e_mm_fixed = 0; e_mm_inc = 1; e_mm_dec = 2; } // Dst Mac optional uint64 dst_mac = 1; optional MacAddrMode dst_mac_mode = 2 [default = e_mm_fixed]; optional uint32 dst_mac_count = 3 [default = 16]; optional uint32 dst_mac_step = 4 [default = 1]; // Src Mac optional uint64 src_mac = 5; optional MacAddrMode src_mac_mode = 6 [default = e_mm_fixed]; optional uint32 src_mac_count = 7 [default = 16]; optional uint32 src_mac_step = 8 [default = 1]; } extend Protocol { optional Mac mac = 100; } ostinato-0.5.1/common/mac.ui0000700000175300010010000001055012005505614015260 0ustar srivatspNone mac 0 0 391 116 Form Address Mode Count Step Destination 120 0 >HH HH HH HH HH HH; Fixed Increment Decrement false 0 false 0 Source >HH HH HH HH HH HH; Fixed Increment Decrement false false 0 Qt::Vertical 20 40 ostinato-0.5.1/common/mld.cpp0000700000175300010010000004623712005505614015454 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "mld.h" #include "ipv6addressdelegate.h" #include "ipv6addressvalidator.h" #include "iputils.h" #include #include MldConfigForm::MldConfigForm(QWidget *parent) : GmpConfigForm(parent) { connect(msgTypeCombo, SIGNAL(currentIndexChanged(int)), SLOT(on_msgTypeCombo_currentIndexChanged(int))); msgTypeCombo->setValueMask(0xFF); msgTypeCombo->addItem(kMldV1Query, "MLDv1 Query"); msgTypeCombo->addItem(kMldV1Report, "MLDv1 Report"); msgTypeCombo->addItem(kMldV1Done, "MLDv1 Done"); msgTypeCombo->addItem(kMldV2Query, "MLDv2 Query"); msgTypeCombo->addItem(kMldV2Report, "MLDv2 Report"); _defaultGroupIp = "::"; _defaultSourceIp = "::"; groupAddress->setValidator(new IPv6AddressValidator(this)); groupRecordAddress->setValidator(new IPv6AddressValidator(this)); sourceList->setItemDelegate(new IPv6AddressDelegate(this)); groupRecordSourceList->setItemDelegate(new IPv6AddressDelegate(this)); } void MldConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/) { switch(msgTypeCombo->currentValue()) { case kMldV1Query: case kMldV1Report: case kMldV1Done: asmGroup->show(); ssmWidget->hide(); break; case kMldV2Query: asmGroup->hide(); ssmWidget->setCurrentIndex(kSsmQueryPage); ssmWidget->show(); break; case kMldV2Report: asmGroup->hide(); ssmWidget->setCurrentIndex(kSsmReportPage); ssmWidget->show(); break; default: asmGroup->hide(); ssmWidget->hide(); break; } } MldProtocol::MldProtocol(StreamBase *stream, AbstractProtocol *parent) : GmpProtocol(stream, parent) { _hasPayload = false; data.set_type(kMldV1Query); } MldProtocol::~MldProtocol() { } AbstractProtocol* MldProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new MldProtocol(stream, parent); } quint32 MldProtocol::protocolNumber() const { return OstProto::Protocol::kMldFieldNumber; } void MldProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::mld)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void MldProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::mld)) data.MergeFrom(protocol.GetExtension(OstProto::mld)); } QString MldProtocol::name() const { return QString("Multicast Listener Discovery"); } QString MldProtocol::shortName() const { return QString("MLD"); } quint32 MldProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: return 0x3a; default:break; } return AbstractProtocol::protocolId(type); } AbstractProtocol::FieldFlags MldProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = GmpProtocol::fieldFlags(index); switch(index) { case kMldMrt: case kMldRsvd: if (msgType() != kMldV2Report) flags |= FrameField; break; default: break; } return flags; } QVariant MldProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case kRsvdMrtCode: { switch(attrib) { case FieldName: return QString("Code"); default: break; } break; } case kMldMrt: { quint16 mrt = 0, mrcode = 0; if (msgType() == kMldV2Query) { mrt = data.max_response_time(); mrcode = mrc(mrt); } else if (msgType() == kMldV1Query) mrcode = mrt = data.max_response_time() & 0xFFFF; switch(attrib) { case FieldName: if (isQuery()) return QString("Max Response Time"); return QString("Reserved"); case FieldValue: return mrt; case FieldTextValue: return QString("%1 ms").arg(mrt); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(mrcode, (uchar*) fv.data()); return fv; } default: break; } break; } case kMldRsvd: { quint16 rsvd = 0; switch(attrib) { case FieldName: return QString("Reserved"); case FieldValue: return rsvd; case FieldTextValue: return QString("%1").arg(rsvd); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(rsvd, (uchar*) fv.data()); return fv; } default: break; } break; } case kGroupAddress: { quint64 grpHi = 0, grpLo = 0; ipUtils::ipAddress( data.group_address().v6_hi(), data.group_address().v6_lo(), data.group_prefix(), ipUtils::AddrMode(data.group_mode()), data.group_count(), streamIndex, grpHi, grpLo); switch(attrib) { case FieldName: return QString("Group Address"); case FieldValue: case FieldTextValue: case FieldFrameValue: { QByteArray fv; fv.resize(16); qToBigEndian(grpHi, (uchar*) fv.data()); qToBigEndian(grpLo, (uchar*) (fv.data() + 8)); if (attrib == FieldFrameValue) return fv; else return QHostAddress((quint8*)fv.constData()).toString(); } default: break; } break; } case kSources: { switch(attrib) { case FieldName: return QString("Source List"); case FieldValue: { QStringList list; QByteArray fv; fv.resize(16); for (int i = 0; i < data.sources_size(); i++) { qToBigEndian(data.sources(i).v6_hi(), (uchar*)fv.data()); qToBigEndian(data.sources(i).v6_lo(), (uchar*)fv.data()+8); list << QHostAddress((quint8*)fv.constData()).toString(); } return list; } case FieldFrameValue: { QByteArray fv; fv.resize(16 * data.sources_size()); for (int i = 0; i < data.sources_size(); i++) { qToBigEndian(data.sources(i).v6_hi(), (uchar*)(fv.data() + i*16)); qToBigEndian(data.sources(i).v6_lo(), (uchar*)(fv.data() + i*16 + 8)); } return fv; } case FieldTextValue: { QStringList list; QByteArray fv; fv.resize(16); for (int i = 0; i < data.sources_size(); i++) { qToBigEndian(data.sources(i).v6_hi(), (uchar*)fv.data()); qToBigEndian(data.sources(i).v6_lo(), (uchar*)fv.data()+8); list << QHostAddress((quint8*)fv.constData()).toString(); } return list.join(", "); } default: break; } break; } case kGroupRecords: { switch(attrib) { case FieldValue: { QVariantList grpRecords = GmpProtocol::fieldData( index, attrib, streamIndex).toList(); QByteArray ip; ip.resize(16); for (int i = 0; i < data.group_records_size(); i++) { QVariantMap grpRec = grpRecords.at(i).toMap(); OstProto::Gmp::GroupRecord rec = data.group_records(i); qToBigEndian(quint64(rec.group_address().v6_hi()), (uchar*)(ip.data())); qToBigEndian(quint64(rec.group_address().v6_lo()), (uchar*)(ip.data() + 8)); grpRec["groupRecordAddress"] = QHostAddress( (quint8*)ip.constData()).toString(); QStringList sl; for (int j = 0; j < rec.sources_size(); j++) { qToBigEndian(rec.sources(j).v6_hi(), (uchar*)(ip.data())); qToBigEndian(rec.sources(j).v6_lo(), (uchar*)(ip.data() + 8)); sl.append(QHostAddress( (quint8*)ip.constData()).toString()); } grpRec["groupRecordSourceList"] = sl; grpRecords.replace(i, grpRec); } return grpRecords; } case FieldFrameValue: { QVariantList list = GmpProtocol::fieldData( index, attrib, streamIndex).toList(); QByteArray fv; QByteArray ip; ip.resize(16); for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QByteArray rv = list.at(i).toByteArray(); rv.insert(4, QByteArray(16+16*rec.sources_size(), char(0))); qToBigEndian(rec.group_address().v6_hi(), (uchar*)(rv.data()+4)); qToBigEndian(rec.group_address().v6_lo(), (uchar*)(rv.data()+4+8)); for (int j = 0; j < rec.sources_size(); j++) { qToBigEndian(rec.sources(j).v6_hi(), (uchar*)(rv.data()+20+16*j)); qToBigEndian(rec.sources(j).v6_lo(), (uchar*)(rv.data()+20+16*j+8)); } fv.append(rv); } return fv; } case FieldTextValue: { QStringList list = GmpProtocol::fieldData( index, attrib, streamIndex).toStringList(); QByteArray ip; ip.resize(16); for (int i = 0; i < data.group_records_size(); i++) { OstProto::Gmp::GroupRecord rec = data.group_records(i); QString recStr = list.at(i); QString str; qToBigEndian(rec.group_address().v6_hi(), (uchar*)(ip.data())); qToBigEndian(rec.group_address().v6_lo(), (uchar*)(ip.data() + 8)); str.append(QString("Group: %1").arg( QHostAddress((quint8*)ip.constData()).toString())); str.append("; Sources: "); QStringList sl; for (int j = 0; j < rec.sources_size(); j++) { qToBigEndian(rec.sources(j).v6_hi(), (uchar*)(ip.data())); qToBigEndian(rec.sources(j).v6_lo(), (uchar*)(ip.data() + 8)); sl.append(QHostAddress( (quint8*)ip.constData()).toString()); } str.append(sl.join(", ")); recStr.replace("XXX", str); list.replace(i, recStr); } return list.join("\n").insert(0, "\n"); } default: break; } break; } default: break; } return GmpProtocol::fieldData(index, attrib, streamIndex); } bool MldProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case kGroupAddress: { Q_IPV6ADDR addr = QHostAddress(value.toString()).toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); data.mutable_group_address()->set_v6_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); data.mutable_group_address()->set_v6_lo(x); break; } case kSources: { QStringList list = value.toStringList(); data.clear_sources(); foreach(QString str, list) { OstProto::Gmp::IpAddress *src = data.add_sources(); Q_IPV6ADDR addr = QHostAddress(str).toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); src->set_v6_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); src->set_v6_lo(x); } break; } case kGroupRecords: { GmpProtocol::setFieldData(index, value, attrib); QVariantList list = value.toList(); for (int i = 0; i < list.count(); i++) { QVariantMap grpRec = list.at(i).toMap(); OstProto::Gmp::GroupRecord *rec = data.mutable_group_records(i); Q_IPV6ADDR addr = QHostAddress( grpRec["groupRecordAddress"].toString()) .toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); rec->mutable_group_address()->set_v6_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); rec->mutable_group_address()->set_v6_lo(x); QStringList srcList = grpRec["groupRecordSourceList"] .toStringList(); rec->clear_sources(); foreach (QString str, srcList) { OstProto::Gmp::IpAddress *src = rec->add_sources(); Q_IPV6ADDR addr = QHostAddress(str).toIPv6Address(); quint64 x; x = (quint64(addr[0]) << 56) | (quint64(addr[1]) << 48) | (quint64(addr[2]) << 40) | (quint64(addr[3]) << 32) | (quint64(addr[4]) << 24) | (quint64(addr[5]) << 16) | (quint64(addr[6]) << 8) | (quint64(addr[7]) << 0); src->set_v6_hi(x); x = (quint64(addr[ 8]) << 56) | (quint64(addr[ 9]) << 48) | (quint64(addr[10]) << 40) | (quint64(addr[11]) << 32) | (quint64(addr[12]) << 24) | (quint64(addr[13]) << 16) | (quint64(addr[14]) << 8) | (quint64(addr[15]) << 0); src->set_v6_lo(x); } } break; } default: isOk = GmpProtocol::setFieldData(index, value, attrib); break; } _exit: return isOk; } QWidget* MldProtocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new MldConfigForm; loadConfigWidget(); } return configForm; } void MldProtocol::loadConfigWidget() { GmpProtocol::loadConfigWidget(); configForm->maxResponseTime->setText( fieldData(kMldMrt, FieldValue).toString()); } void MldProtocol::storeConfigWidget() { GmpProtocol::storeConfigWidget(); setFieldData(kMldMrt, configForm->maxResponseTime->text()); } quint16 MldProtocol::checksum(int streamIndex) const { return AbstractProtocol::protocolFrameCksum(streamIndex, CksumTcpUdp); } ostinato-0.5.1/common/mld.h0000700000175300010010000000553312005505614015113 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _MLD_H #define _MLD_H #include "mld.pb.h" #include "gmp.h" // MLD uses the same msg type value for 'Query' messages across // versions despite the fields being different. To distinguish // Query messages of different versions, we use an additional // upper byte enum MldMsgType { kMldV1Query = 0x82, kMldV1Report = 0x83, kMldV1Done = 0x84, kMldV2Query = 0xFF82, kMldV2Report = 0x8F }; class MldConfigForm : public GmpConfigForm { Q_OBJECT public: MldConfigForm(QWidget *parent = 0); private slots: void on_msgTypeCombo_currentIndexChanged(int index); }; class MldProtocol : public GmpProtocol { public: MldProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~MldProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); protected: virtual bool isSsmReport() const; virtual bool isQuery() const; virtual bool isSsmQuery() const; virtual quint16 checksum(int streamIndex) const; private: int mrc(int value) const; }; inline bool MldProtocol::isSsmReport() const { return (msgType() == kMldV2Report); } inline bool MldProtocol::isQuery() const { return ((msgType() == kMldV1Query) || (msgType() == kMldV2Query)); } inline bool MldProtocol::isSsmQuery() const { return (msgType() == kMldV2Query); } inline int MldProtocol::mrc(int value) const { return quint16(value); // TODO: if value > 128, convert to mantissa/exp form } #endif ostinato-0.5.1/common/mld.proto0000700000175300010010000000142312005505614016021 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "gmp.proto"; package OstProto; extend Protocol { optional Gmp mld = 404; } ostinato-0.5.1/common/ostproto.pro0000700000175300010010000000472712005505614016605 0ustar srivatspNoneTEMPLATE = lib CONFIG += qt staticlib QT += network script xml INCLUDEPATH += "../extra/qhexedit2/src" LIBS += \ -lprotobuf FORMS += \ pcapfileimport.ui \ mac.ui \ payload.ui \ eth2.ui \ dot3.ui \ llc.ui \ snap.ui \ vlan.ui \ arp.ui \ ip4.ui \ ip6.ui \ icmp.ui \ gmp.ui \ tcp.ui \ udp.ui \ textproto.ui \ userscript.ui \ hexdump.ui \ sample.ui PROTOS += \ protocol.proto \ fileformat.proto \ mac.proto \ payload.proto \ eth2.proto \ dot3.proto \ llc.proto \ snap.proto \ dot2llc.proto \ dot2snap.proto \ vlan.proto \ svlan.proto \ vlanstack.proto \ arp.proto \ ip4.proto \ ip6.proto \ ip6over4.proto \ ip4over6.proto \ ip4over4.proto \ ip6over6.proto \ icmp.proto \ gmp.proto \ igmp.proto \ mld.proto \ tcp.proto \ udp.proto \ textproto.proto \ userscript.proto \ hexdump.proto \ sample.proto HEADERS += \ ostprotolib.h \ abstractprotocol.h \ comboprotocol.h \ abstractfileformat.h \ fileformat.h \ pcapfileformat.h \ pdmlfileformat.h \ pdmlprotocol.h \ pdmlprotocols.h \ pdmlreader.h \ protocolmanager.h \ protocollist.h \ protocollistiterator.h \ streambase.h \ mac.h \ payload.h \ eth2.h \ dot3.h \ llc.h \ snap.h \ dot2llc.h \ dot2snap.h \ vlan.h \ svlan.h \ vlanstack.h \ arp.h \ ip4.h \ ip6.h \ ipv4addressdelegate.h \ ipv6addressdelegate.h \ ip6over4.h \ ip4over6.h \ ip4over4.h \ ip6over6.h \ icmp.h \ gmp.h \ igmp.h \ mld.h \ tcp.h \ udp.h \ textproto.h \ userscript.h \ hexdump.h \ sample.h SOURCES += \ ostprotolib.cpp \ abstractprotocol.cpp \ crc32c.cpp \ abstractfileformat.cpp \ fileformat.cpp \ pcapfileformat.cpp \ pdmlfileformat.cpp \ pdmlprotocol.cpp \ pdmlprotocols.cpp \ pdmlreader.cpp \ protocolmanager.cpp \ protocollist.cpp \ protocollistiterator.cpp \ streambase.cpp \ mac.cpp \ payload.cpp \ eth2.cpp \ dot3.cpp \ llc.cpp \ snap.cpp \ vlan.cpp \ svlan.cpp \ arp.cpp \ ip4.cpp \ ip6.cpp \ icmp.cpp \ gmp.cpp \ igmp.cpp \ mld.cpp \ tcp.cpp \ udp.cpp \ textproto.cpp \ userscript.cpp \ hexdump.cpp \ sample.cpp QMAKE_DISTCLEAN += object_script.* include(../protobuf.pri) ostinato-0.5.1/common/ostprotolib.cpp0000700000175300010010000000243312005505614017246 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "ostprotolib.h" QString OstProtoLib::tsharkPath_; QString OstProtoLib::gzipPath_; QString OstProtoLib::diffPath_; QString OstProtoLib::awkPath_; void OstProtoLib::setExternalApplicationPaths(QString tsharkPath, QString gzipPath, QString diffPath, QString awkPath) { tsharkPath_ = tsharkPath; gzipPath_ = gzipPath; diffPath_ = diffPath; awkPath_ = awkPath; } QString OstProtoLib::tsharkPath() { return tsharkPath_; } QString OstProtoLib::gzipPath() { return gzipPath_; } QString OstProtoLib::diffPath() { return diffPath_; } QString OstProtoLib::awkPath() { return awkPath_; } ostinato-0.5.1/common/ostprotolib.h0000700000175300010010000000222212005505614016707 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _OST_PROTO_LIB_H #define _OST_PROTO_LIB_H #include class OstProtoLib { public: static void setExternalApplicationPaths(QString tsharkPath, QString gzipPath, QString diffPath, QString awkPath); static QString tsharkPath(); static QString gzipPath(); static QString diffPath(); static QString awkPath(); private: static QString tsharkPath_; static QString gzipPath_; static QString diffPath_; static QString awkPath_; }; #endif ostinato-0.5.1/common/payload.cpp0000700000175300010010000001714512005505614016325 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include //#include "../client/stream.h" #include "payload.h" #include "streambase.h" PayloadConfigForm::PayloadConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } void PayloadConfigForm::on_cmbPatternMode_currentIndexChanged(int index) { switch(index) { case OstProto::Payload::e_dp_fixed_word: lePattern->setEnabled(true); break; case OstProto::Payload::e_dp_inc_byte: case OstProto::Payload::e_dp_dec_byte: case OstProto::Payload::e_dp_random: lePattern->setDisabled(true); break; default: qWarning("Unhandled/Unknown PatternMode = %d",index); } } PayloadProtocol::PayloadProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } PayloadProtocol::~PayloadProtocol() { delete configForm; } AbstractProtocol* PayloadProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new PayloadProtocol(stream, parent); } quint32 PayloadProtocol::protocolNumber() const { return OstProto::Protocol::kPayloadFieldNumber; } void PayloadProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::payload)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void PayloadProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::payload)) data.MergeFrom(protocol.GetExtension(OstProto::payload)); } QString PayloadProtocol::name() const { return QString("Payload Data"); } QString PayloadProtocol::shortName() const { return QString("DATA"); } int PayloadProtocol::protocolFrameSize(int streamIndex) const { int len; len = mpStream->frameLen(streamIndex) - protocolFrameOffset(streamIndex) - kFcsSize; if (len < 0) len = 0; qDebug("%s: this = %p, streamIndex = %d, len = %d", __FUNCTION__, this, streamIndex, len); return len; } int PayloadProtocol::fieldCount() const { return payload_fieldCount; } AbstractProtocol::FieldFlags PayloadProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case payload_dataPattern: break; // Meta fields case payload_dataPatternMode: flags &= ~FrameField; flags |= MetaField; break; } return flags; } QVariant PayloadProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case payload_dataPattern: switch(attrib) { case FieldName: return QString("Data"); case FieldValue: return data.pattern(); case FieldTextValue: return QString(fieldData(index, FieldFrameValue, streamIndex).toByteArray().toHex()); case FieldFrameValue: { QByteArray fv; int dataLen; dataLen = protocolFrameSize(streamIndex); // FIXME: Hack! Bad! Bad! Very Bad!!! if (dataLen <= 0) dataLen = 1; fv.resize(dataLen+4); switch(data.pattern_mode()) { case OstProto::Payload::e_dp_fixed_word: for (int i = 0; i < (dataLen/4)+1; i++) qToBigEndian((quint32) data.pattern(), (uchar*)(fv.data()+(i*4)) ); break; case OstProto::Payload::e_dp_inc_byte: for (int i = 0; i < dataLen; i++) fv[i] = i % (0xFF + 1); break; case OstProto::Payload::e_dp_dec_byte: for (int i = 0; i < dataLen; i++) fv[i] = 0xFF - (i % (0xFF + 1)); break; case OstProto::Payload::e_dp_random: //! \todo (HIGH) cksum is incorrect for random pattern for (int i = 0; i < dataLen; i++) fv[i] = qrand() % (0xFF + 1); break; default: qWarning("Unhandled data pattern %d", data.pattern_mode()); } fv.resize(dataLen); return fv; } default: break; } break; // Meta fields case payload_dataPatternMode: default: break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool PayloadProtocol::setFieldData(int /*index*/, const QVariant &/*value*/, FieldAttrib /*attrib*/) { return false; } bool PayloadProtocol::isProtocolFrameValueVariable() const { if (isProtocolFrameSizeVariable() || data.pattern_mode() == OstProto::Payload::e_dp_random) return true; else return false; } bool PayloadProtocol::isProtocolFrameSizeVariable() const { if (mpStream->lenMode() == StreamBase::e_fl_fixed) return false; else return true; } int PayloadProtocol::protocolFrameVariableCount() const { int count = 1; if (data.pattern_mode() == OstProto::Payload::e_dp_random) { switch(mpStream->sendUnit()) { case OstProto::StreamControl::e_su_packets: return mpStream->numPackets(); case OstProto::StreamControl::e_su_bursts: return int(mpStream->numBursts() * mpStream->burstSize() * mpStream->burstRate()); } } if (mpStream->lenMode() != StreamBase::e_fl_fixed) { count = AbstractProtocol::lcm(count, mpStream->frameLenMax() - mpStream->frameLenMin() + 1); } return count; } QWidget* PayloadProtocol::configWidget() { if (configForm == NULL) { configForm = new PayloadConfigForm; loadConfigWidget(); } return configForm; } void PayloadProtocol::loadConfigWidget() { configWidget(); configForm->cmbPatternMode->setCurrentIndex(data.pattern_mode()); configForm->lePattern->setText(uintToHexStr(data.pattern(), 4)); } void PayloadProtocol::storeConfigWidget() { bool isOk; configWidget(); data.set_pattern_mode((OstProto::Payload::DataPatternMode) configForm->cmbPatternMode->currentIndex()); data.set_pattern(configForm->lePattern->text().remove(QChar(' ')).toULong(&isOk, 16)); } ostinato-0.5.1/common/payload.h0000700000175300010010000000460712005505614015771 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PAYLOAD_H #define _PAYLOAD_H #include "abstractprotocol.h" #include "payload.pb.h" #include "ui_payload.h" class PayloadConfigForm : public QWidget, public Ui::payload { Q_OBJECT public: PayloadConfigForm(QWidget *parent = 0); private slots: void on_cmbPatternMode_currentIndexChanged(int index); }; class PayloadProtocol : public AbstractProtocol { private: OstProto::Payload data; PayloadConfigForm *configForm; enum payloadfield { payload_dataPattern, // Meta fields payload_dataPatternMode, payload_fieldCount }; public: PayloadProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~PayloadProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual int protocolFrameSize(int streamIndex = 0) const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual bool isProtocolFrameSizeVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/payload.proto0000700000175300010010000000213312005505614016675 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; message Payload { enum DataPatternMode { e_dp_fixed_word = 0; e_dp_inc_byte = 1; e_dp_dec_byte = 2; e_dp_random = 3; } // Data Pattern optional DataPatternMode pattern_mode = 1; optional uint32 pattern = 2; //optional uint32 data_start_ofs = 13; } extend Protocol { optional Payload payload = 101; } ostinato-0.5.1/common/payload.ui0000700000175300010010000000465412005505614016161 0ustar srivatspNone payload 0 0 299 114 Form Type cmbPatternMode Fixed Word Increment Byte Decrement Byte Random Qt::Horizontal 40 20 Pattern lePattern >HH HH HH HH; 11 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 40 ostinato-0.5.1/common/pcapfileformat.cpp0000700000175300010010000004456112005505614017672 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pcapfileformat.h" #include "pdmlreader.h" #include "ostprotolib.h" #include "streambase.h" #include "hexdump.pb.h" #include #include #include #include #include #include static inline quint32 swap32(quint32 val) { return (((val >> 24) && 0x000000FF) | ((val >> 16) && 0x0000FF00) | ((val << 16) && 0x00FF0000) | ((val << 24) && 0xFF000000)); } static inline quint16 swap16(quint16 val) { return (((val >> 8) && 0x00FF) | ((val << 8) && 0xFF00)); } const quint32 kPcapFileMagic = 0xa1b2c3d4; const quint32 kPcapFileMagicSwapped = 0xd4c3b2a1; const quint16 kPcapFileVersionMajor = 2; const quint16 kPcapFileVersionMinor = 4; const quint32 kMaxSnapLen = 65535; const quint32 kDltEthernet = 1; PcapFileFormat pcapFileFormat; PcapImportOptionsDialog::PcapImportOptionsDialog(QVariantMap *options) : QDialog(NULL) { setupUi(this); options_ = options; viaPdml->setChecked(options_->value("ViaPdml").toBool()); doDiff->setChecked(options_->value("DoDiff").toBool()); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); } PcapImportOptionsDialog::~PcapImportOptionsDialog() { } void PcapImportOptionsDialog::accept() { options_->insert("ViaPdml", viaPdml->isChecked()); options_->insert("DoDiff", doDiff->isChecked()); QDialog::accept(); } PcapFileFormat::PcapFileFormat() { importOptions_.insert("ViaPdml", true); importOptions_.insert("DoDiff", true); importDialog_ = NULL; } PcapFileFormat::~PcapFileFormat() { delete importDialog_; } bool PcapFileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { bool isOk = false; QFile file(fileName); QTemporaryFile file2; quint32 magic; uchar gzipMagic[2]; int len; PcapFileHeader fileHdr; PcapPacketHeader pktHdr; OstProto::Stream *prevStream = NULL; uint lastUsec = 0; int pktCount; qint64 byteCount = 0; qint64 byteTotal; QByteArray pktBuf; if (!file.open(QIODevice::ReadOnly)) goto _err_open; len = file.peek((char*)gzipMagic, sizeof(gzipMagic)); if (len < int(sizeof(gzipMagic))) goto _err_reading_magic; if ((gzipMagic[0] == 0x1f) && (gzipMagic[1] == 0x8b)) { QProcess gzip; emit status("Decompressing..."); emit target(0); if (!file2.open()) { error.append("Unable to open temporary file to uncompress .gz\n"); goto _err_unzip_fail; } qDebug("decompressing to %s", file2.fileName().toAscii().constData()); gzip.setStandardOutputFile(file2.fileName()); gzip.start(OstProtoLib::gzipPath(), QStringList() << "-d" << "-c" << fileName); if (!gzip.waitForStarted(-1)) { error.append(QString("Unable to start gzip. Check path in Preferences.\n")); goto _err_unzip_fail; } if (!gzip.waitForFinished(-1)) { error.append(QString("Error running gzip\n")); goto _err_unzip_fail; } file2.seek(0); fd_.setDevice(&file2); } else { fd_.setDevice(&file); } byteTotal = fd_.device()->size() - sizeof(fileHdr); emit status("Reading File Header..."); emit target(0); fd_ >> magic; qDebug("magic = %08x", magic); if (magic == kPcapFileMagicSwapped) { // Toggle Byte order if (fd_.byteOrder() == QDataStream::BigEndian) fd_.setByteOrder(QDataStream::LittleEndian); else fd_.setByteOrder(QDataStream::BigEndian); } else if (magic != kPcapFileMagic) goto _err_bad_magic; fd_ >> fileHdr.versionMajor; fd_ >> fileHdr.versionMinor; fd_ >> fileHdr.thisZone; fd_ >> fileHdr.sigfigs; fd_ >> fileHdr.snapLen; fd_ >> fileHdr.network; if ((fileHdr.versionMajor != kPcapFileVersionMajor) || (fileHdr.versionMinor != kPcapFileVersionMinor)) goto _err_unsupported_version; #if 1 // XXX: we support only Ethernet, for now if (fileHdr.network != kDltEthernet) goto _err_unsupported_encap; #endif pktBuf.resize(fileHdr.snapLen); if (importOptions_.value("ViaPdml").toBool()) { QProcess tshark; QTemporaryFile pdmlFile; PdmlReader reader(&streams); if (!pdmlFile.open()) { error.append("Unable to open temporary file to create PDML\n"); goto _non_pdml; } qDebug("generating PDML %s", pdmlFile.fileName().toAscii().constData()); emit status("Generating PDML..."); emit target(0); tshark.setStandardOutputFile(pdmlFile.fileName()); tshark.start(OstProtoLib::tsharkPath(), QStringList() << QString("-r%1").arg(fileName) << "-otcp.desegment_tcp_streams:FALSE" << "-Tpdml"); if (!tshark.waitForStarted(-1)) { error.append(QString("Unable to start tshark. Check path in preferences.\n")); goto _non_pdml; } if (!tshark.waitForFinished(-1)) { error.append(QString("Error running tshark\n")); goto _non_pdml; } connect(&reader, SIGNAL(progress(int)), this, SIGNAL(progress(int))); emit status("Reading PDML packets..."); emit target(100); // in percentage isOk = reader.read(&pdmlFile, this, &stop_); if (stop_) goto _user_cancel; if (!isOk) { error.append(QString("Error processing PDML (%1, %2): %3\n") .arg(reader.lineNumber()) .arg(reader.columnNumber()) .arg(reader.errorString())); goto _exit; } if (!importOptions_.value("DoDiff").toBool()) goto _exit; // !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-! // Let's do the diff ... // !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-! QProcess awk; QProcess diff; QTemporaryFile originalTextFile; QTemporaryFile importedPcapFile; QTemporaryFile importedTextFile; QTemporaryFile diffFile; const QString kAwkFilter = "/^[^0]/ { " "printf \" %s \", $1;" "for (i=4; i %s", originalTextFile.fileName().toAscii().constData(), importedTextFile.fileName().toAscii().constData(), diffFile.fileName().toAscii().constData()); emit status("Taking diff..."); emit target(0); diff.setStandardOutputFile(diffFile.fileName()); diff.start(OstProtoLib::diffPath(), QStringList() << "-u" << "-F^ [1-9]" << QString("--label=%1 (actual)") .arg(QFileInfo(fileName).fileName()) << QString("--label=%1 (imported)") .arg(QFileInfo(fileName).fileName()) << originalTextFile.fileName() << importedTextFile.fileName()); if (!diff.waitForStarted(-1)) { error.append(QString("Unable to start diff. Check path in Preferences.\n") .arg(diff.exitCode())); goto _diff_fail; } if (!diff.waitForFinished(-1)) { error.append(QString("Error running diff\n")); goto _diff_fail; } diffFile.close(); if (diffFile.size()) { error.append("There is a diff between the original and imported streams. See details for diff.\n\n\n\n"); diffFile.open(); diffFile.seek(0); error.append(QString(diffFile.readAll())); } goto _exit; } _non_pdml: emit status("Reading Packets..."); emit target(100); // in percentage pktCount = 1; while (!fd_.atEnd()) { OstProto::Stream *stream = streams.add_stream(); OstProto::Protocol *proto = stream->add_protocol(); OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kHexDumpFieldNumber); readPacket(pktHdr, pktBuf); // validations on inclLen <= origLen && inclLen <= snapLen Q_ASSERT(pktHdr.inclLen <= fileHdr.snapLen); // TODO: convert to if hexDump->set_content(pktBuf.data(), pktHdr.inclLen); hexDump->set_pad_until_end(false); stream->mutable_stream_id()->set_id(pktCount); stream->mutable_core()->set_is_enabled(true); stream->mutable_core()->set_frame_len(pktHdr.inclLen+4); // FCS // setup packet rate to the timing in pcap (as close as possible) const uint kUsecsInSec = uint(1e6); uint usec = (pktHdr.tsSec*kUsecsInSec + pktHdr.tsUsec); uint delta = usec - lastUsec; if ((pktCount != 1) && delta) stream->mutable_control()->set_packets_per_sec(kUsecsInSec/delta); if (prevStream) prevStream->mutable_control()->CopyFrom(stream->control()); lastUsec = usec; prevStream = stream; pktCount++; qDebug("pktCount = %d", pktCount); byteCount += pktHdr.inclLen + sizeof(pktHdr); emit progress(int(byteCount*100/byteTotal)); // in percentage if (stop_) goto _user_cancel; } isOk = true; goto _exit; _user_cancel: isOk = true; goto _exit; _diff_fail: goto _exit; _err_unsupported_encap: error = QString(tr("%1 has non-ethernet encapsulation (%2) which is " "not supported - Sorry!")) .arg(QFileInfo(fileName).fileName()).arg(fileHdr.network); goto _exit; _err_unsupported_version: error = QString(tr("%1 is in PCAP version %2.%3 format which is " "not supported - Sorry!")) .arg(fileName).arg(fileHdr.versionMajor).arg(fileHdr.versionMinor); goto _exit; _err_bad_magic: error = QString(tr("%1 is not a valid PCAP file")).arg(fileName); goto _exit; #if 0 _err_truncated: error = QString(tr("%1 is too short")).arg(fileName); goto _exit; #endif _err_unzip_fail: goto _exit; _err_reading_magic: error = QString(tr("Unable to read magic from %1")).arg(fileName); goto _exit; _err_open: error = QString(tr("Unable to open file: %1")).arg(fileName); goto _exit; _exit: file.close(); return isOk; } /*! Reads packet meta data into pktHdr and packet content into buf. Returns true if packet is read successfully, false otherwise. */ bool PcapFileFormat::readPacket(PcapPacketHeader &pktHdr, QByteArray &pktBuf) { quint32 len; // TODO: chk fd_.status() // read PcapPacketHeader fd_ >> pktHdr.tsSec; fd_ >> pktHdr.tsUsec; fd_ >> pktHdr.inclLen; fd_ >> pktHdr.origLen; // TODO: chk fd_.status() // XXX: should never be required, but we play safe if (quint32(pktBuf.size()) < pktHdr.inclLen) pktBuf.resize(pktHdr.inclLen); // read Pkt contents len = fd_.readRawData(pktBuf.data(), pktHdr.inclLen); // TODO: use while? Q_ASSERT(len == pktHdr.inclLen); // TODO: remove assert pktBuf.resize(len); return true; } bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) { bool isOk = false; QFile file(fileName); PcapFileHeader fileHdr; PcapPacketHeader pktHdr; QByteArray pktBuf; if (!file.open(QIODevice::WriteOnly)) goto _err_open; fd_.setDevice(&file); fileHdr.magicNumber = kPcapFileMagic; fileHdr.versionMajor = kPcapFileVersionMajor; fileHdr.versionMinor = kPcapFileVersionMinor; fileHdr.thisZone = 0; fileHdr.sigfigs = 0; fileHdr.snapLen = kMaxSnapLen; fileHdr.network = kDltEthernet; fd_ << fileHdr.magicNumber; fd_ << fileHdr.versionMajor; fd_ << fileHdr.versionMinor; fd_ << fileHdr.thisZone; fd_ << fileHdr.sigfigs; fd_ << fileHdr.snapLen; fd_ << fileHdr.network; pktBuf.resize(kMaxSnapLen); emit status("Writing Packets..."); emit target(streams.stream_size()); pktHdr.tsSec = 0; pktHdr.tsUsec = 0; for (int i = 0; i < streams.stream_size(); i++) { StreamBase s; s.setId(i); s.protoDataCopyFrom(streams.stream(i)); // TODO: expand frameIndex for each stream s.frameValue((uchar*)pktBuf.data(), pktBuf.size(), 0); pktHdr.inclLen = s.frameProtocolLength(0); // FIXME: stream index = 0 pktHdr.origLen = s.frameLen() - 4; // FCS; FIXME: Hardcoding qDebug("savepcap i=%d, incl/orig len = %d/%d", i, pktHdr.inclLen, pktHdr.origLen); if (pktHdr.inclLen > fileHdr.snapLen) pktHdr.inclLen = fileHdr.snapLen; fd_ << pktHdr.tsSec; fd_ << pktHdr.tsUsec; fd_ << pktHdr.inclLen; fd_ << pktHdr.origLen; fd_.writeRawData(pktBuf.data(), pktHdr.inclLen); if (s.packetRate()) pktHdr.tsUsec += 1000000/s.packetRate(); if (pktHdr.tsUsec >= 1000000) { pktHdr.tsSec++; pktHdr.tsUsec -= 1000000; } emit progress(i); } file.close(); isOk = true; goto _exit; _err_open: error = QString(tr("Unable to open file: %1")).arg(fileName); goto _exit; _exit: return isOk; } QDialog* PcapFileFormat::openOptionsDialog() { if (!importDialog_) importDialog_ = new PcapImportOptionsDialog(&importOptions_); return importDialog_; } bool PcapFileFormat::isMyFileFormat(const QString /*fileName*/) { // TODO return true; } bool PcapFileFormat::isMyFileType(const QString fileType) { if (fileType.startsWith("PCAP")) return true; else return false; } ostinato-0.5.1/common/pcapfileformat.h0000700000175300010010000000504112005505614017325 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PCAP_FILE_FORMAT_H #define _PCAP_FILE_FORMAT_H #include "abstractfileformat.h" #include "ui_pcapfileimport.h" #include #include class PcapImportOptionsDialog: public QDialog, public Ui::PcapFileImport { public: PcapImportOptionsDialog(QVariantMap *options); ~PcapImportOptionsDialog(); private slots: void accept(); private: QVariantMap *options_; }; class PdmlReader; class PcapFileFormat : public AbstractFileFormat { friend class PdmlReader; public: PcapFileFormat(); ~PcapFileFormat(); bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error); bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); virtual QDialog* openOptionsDialog(); bool isMyFileFormat(const QString fileName); bool isMyFileType(const QString fileType); private: typedef struct { quint32 magicNumber; /* magic number */ quint16 versionMajor; /* major version number */ quint16 versionMinor; /* minor version number */ qint32 thisZone; /* GMT to local correction */ quint32 sigfigs; /* accuracy of timestamps */ quint32 snapLen; /* max length of captured packets, in octets */ quint32 network; /* data link type */ } PcapFileHeader; typedef struct { quint32 tsSec; /* timestamp seconds */ quint32 tsUsec; /* timestamp microseconds */ quint32 inclLen; /* number of octets of packet saved in file */ quint32 origLen; /* actual length of packet */ } PcapPacketHeader; bool readPacket(PcapPacketHeader &pktHdr, QByteArray &pktBuf); QDataStream fd_; QVariantMap importOptions_; PcapImportOptionsDialog *importDialog_; }; extern PcapFileFormat pcapFileFormat; #endif ostinato-0.5.1/common/pcapfileimport.ui0000700000175300010010000000575312005505614017547 0ustar srivatspNone PcapFileImport 0 0 326 93 PCAP import options Intelligent Import (via PDML) 0 0 16 16 false Do a diff after import Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok buttonBox accepted() PcapFileImport accept() 249 81 157 90 buttonBox rejected() PcapFileImport reject() 249 81 258 90 viaPdml toggled(bool) doDiff setEnabled(bool) 15 16 37 42 viaPdml toggled(bool) doDiff setChecked(bool) 151 14 150 34 ostinato-0.5.1/common/pdmlfileformat.cpp0000700000175300010010000000756212005505614017703 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pdmlfileformat.h" #include "ostprotolib.h" #include "pdmlreader.h" #include #include PdmlFileFormat pdmlFileFormat; PdmlFileFormat::PdmlFileFormat() { } PdmlFileFormat::~PdmlFileFormat() { } bool PdmlFileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { bool isOk = false; QFile file(fileName); PdmlReader *reader = new PdmlReader(&streams); if (!file.open(QIODevice::ReadOnly)) goto _open_fail; connect(reader, SIGNAL(progress(int)), this, SIGNAL(progress(int))); emit status("Reading PDML packets..."); emit target(100); // in percentage isOk = reader->read(&file, NULL, &stop_); if (stop_) goto _user_cancel; if (!isOk) { error.append(QString("Error processing PDML (%1, %2): %3\n") .arg(reader->lineNumber()) .arg(reader->columnNumber()) .arg(reader->errorString())); goto _exit; } goto _exit; _open_fail: isOk = false; _user_cancel: _exit: delete reader; return isOk; } bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) { bool isOk = false; QTemporaryFile pcapFile; AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType("PCAP"); QProcess tshark; Q_ASSERT(fmt); if (!pcapFile.open()) { error.append("Unable to open temporary file to create PCAP\n"); goto _fail; } qDebug("intermediate PCAP %s", pcapFile.fileName().toAscii().constData()); connect(fmt, SIGNAL(target(int)), this, SIGNAL(target(int))); connect(fmt, SIGNAL(progress(int)), this, SIGNAL(progress(int))); emit status("Writing intermediate PCAP file..."); isOk = fmt->saveStreams(streams, pcapFile.fileName(), error); qDebug("generating PDML %s", fileName.toAscii().constData()); emit status("Converting PCAP to PDML..."); emit target(0); tshark.setStandardOutputFile(fileName); tshark.start(OstProtoLib::tsharkPath(), QStringList() << QString("-r%1").arg(pcapFile.fileName()) << "-Tpdml"); if (!tshark.waitForStarted(-1)) { error.append(QString("Unable to start tshark. Check path in preferences.\n")); goto _fail; } if (!tshark.waitForFinished(-1)) { error.append(QString("Error running tshark\n")); goto _fail; } isOk = true; _fail: return isOk; } bool PdmlFileFormat::isMyFileFormat(const QString fileName) { bool ret = false; QFile file(fileName); QByteArray buf; QXmlStreamReader xml; if (!file.open(QIODevice::ReadOnly)) goto _exit; xml.setDevice(&file); xml.readNext(); if (xml.hasError() || !xml.isStartDocument()) goto _close_exit; xml.readNext(); if (!xml.hasError() && xml.isStartElement() && (xml.name() == "pdml")) ret = true; else ret = false; _close_exit: xml.clear(); file.close(); _exit: return ret; } bool PdmlFileFormat::isMyFileType(const QString fileType) { if (fileType.startsWith("PDML")) return true; else return false; } ostinato-0.5.1/common/pdmlfileformat.h0000700000175300010010000000235512005505614017343 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PDML_FILE_FORMAT_H #define _PDML_FILE_FORMAT_H #include "abstractfileformat.h" class PdmlFileFormat : public AbstractFileFormat { public: PdmlFileFormat(); ~PdmlFileFormat(); virtual bool openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error); virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error); bool isMyFileFormat(const QString fileName); bool isMyFileType(const QString fileType); }; extern PdmlFileFormat pdmlFileFormat; #endif ostinato-0.5.1/common/pdmlprotocol.cpp0000700000175300010010000001067012005505614017406 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pdmlprotocol.h" const int kBaseHex = 16; PdmlProtocol::PdmlProtocol() { ostProtoId_ = -1; } PdmlProtocol::~PdmlProtocol() { } PdmlProtocol* PdmlProtocol::createInstance() { return new PdmlProtocol(); } int PdmlProtocol::ostProtoId() const { return ostProtoId_; } bool PdmlProtocol::hasField(QString name) const { return fieldMap_.contains(name); } int PdmlProtocol::fieldId(QString name) const { return fieldMap_.value(name); } void PdmlProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } void PdmlProtocol::prematureEndHandler(int /*pos*/, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } void PdmlProtocol::postProtocolHandler(OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } void PdmlProtocol::fieldHandler(QString name, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream) { if (hasField(name)) { QString valueHexStr = attributes.value("value").toString(); qDebug("\t(KNOWN) fieldName:%s, value:%s", name.toAscii().constData(), valueHexStr.toAscii().constData()); knownFieldHandler(name, valueHexStr, pbProto); } else { int pos = -1; int size = -1; if (!attributes.value("pos").isEmpty()) pos = attributes.value("pos").toString().toInt(); if (!attributes.value("size").isEmpty()) size = attributes.value("size").toString().toInt(); qDebug("\t(UNKNOWN) fieldName:%s, pos:%d, size:%d", name.toAscii().constData(), pos, size); unknownFieldHandler(name, pos, size, attributes, pbProto, stream); } } void PdmlProtocol::knownFieldHandler(QString name, QString valueHexStr, OstProto::Protocol *pbProto) { const google::protobuf::Reflection *protoRefl = pbProto->GetReflection(); const google::protobuf::FieldDescriptor *extDesc = protoRefl->FindKnownExtensionByNumber(ostProtoId()); google::protobuf::Message *msg = protoRefl->MutableMessage(pbProto,extDesc); const google::protobuf::Reflection *msgRefl = msg->GetReflection(); const google::protobuf::FieldDescriptor *fieldDesc = msg->GetDescriptor()->FindFieldByNumber(fieldId(name)); bool isOk; Q_ASSERT(fieldDesc != NULL); switch(fieldDesc->cpp_type()) { case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: msgRefl->SetBool(msg, fieldDesc, bool(valueHexStr.toUInt(&isOk))); break; case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: // TODO case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: msgRefl->SetUInt32(msg, fieldDesc, valueHexStr.toUInt(&isOk, kBaseHex)); break; case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: msgRefl->SetUInt64(msg, fieldDesc, valueHexStr.toULongLong(&isOk, kBaseHex)); break; case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { QByteArray hexVal = QByteArray::fromHex(valueHexStr.toUtf8()); std::string str(hexVal.constData(), hexVal.size()); msgRefl->SetString(msg, fieldDesc, str); break; } default: qDebug("%s: unhandled cpptype = %d", __FUNCTION__, fieldDesc->cpp_type()); } } void PdmlProtocol::unknownFieldHandler(QString /*name*/, int /*pos*/, int /*size*/, const QXmlStreamAttributes& /*attributes*/, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } ostinato-0.5.1/common/pdmlprotocol.h0000700000175300010010000000374112005505614017054 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PDML_PROTOCOL_H #define _PDML_PROTOCOL_H #include "protocol.pb.h" #include #include #include #include class PdmlProtocol { public: virtual ~PdmlProtocol(); static PdmlProtocol* createInstance(); int ostProtoId() const; bool hasField(QString name) const; int fieldId(QString name) const; virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void prematureEndHandler(int pos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); void fieldHandler(QString name, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); void knownFieldHandler(QString name, QString valueHexStr, OstProto::Protocol *pbProto); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlProtocol(); int ostProtoId_; QMap fieldMap_; }; #endif ostinato-0.5.1/common/pdmlprotocols.cpp0000700000175300010010000013051112005505614017566 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pdmlprotocols.h" #include "arp.pb.h" #include "eth2.pb.h" #include "dot3.pb.h" #include "gmp.pb.h" #include "hexdump.pb.h" #include "llc.pb.h" #include "mac.pb.h" #include "icmp.pb.h" #include "igmp.pb.h" #include "ip4.pb.h" #include "ip6.pb.h" #include "mld.pb.h" #include "sample.pb.h" #include "snap.pb.h" #include "svlan.pb.h" #include "tcp.pb.h" #include "textproto.pb.h" #include "udp.pb.h" #include "vlan.pb.h" #include #include const int kBaseHex = 16; // ---------------------------------------------------------- // // PdmlUnknownProtocol // // ---------------------------------------------------------- // PdmlUnknownProtocol::PdmlUnknownProtocol() { ostProtoId_ = OstProto::Protocol::kHexDumpFieldNumber; endPos_ = expPos_ = -1; } PdmlProtocol* PdmlUnknownProtocol::createInstance() { return new PdmlUnknownProtocol(); } void PdmlUnknownProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream) { bool isOk; int size; int pos = attributes.value("pos").toString().toUInt(&isOk); if (!isOk) { if (expectedPos >= 0) expPos_ = pos = expectedPos; else goto _skip_pos_size_proc; } size = attributes.value("size").toString().toUInt(&isOk); if (!isOk) goto _skip_pos_size_proc; // If pos+size goes beyond the frame length, this is a "reassembled" // protocol and should be skipped if ((pos + size) > int(stream->core().frame_len())) goto _skip_pos_size_proc; expPos_ = pos; endPos_ = expPos_ + size; _skip_pos_size_proc: OstProto::HexDump *hexDump = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::hexDump); hexDump->set_pad_until_end(false); } void PdmlUnknownProtocol::prematureEndHandler(int pos, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { endPos_ = pos; } void PdmlUnknownProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::HexDump *hexDump = pbProto->MutableExtension(OstProto::hexDump); // Skipped field(s) at end? Pad with zero! if (endPos_ > expPos_) { QByteArray hexVal(endPos_ - expPos_, char(0)); hexDump->mutable_content()->append(hexVal.constData(), hexVal.size()); expPos_ += hexVal.size(); } qDebug(" hexdump: expPos_ = %d, endPos_ = %d\n", expPos_, endPos_); // If empty for some reason, remove the protocol if (hexDump->content().size() == 0) stream->mutable_protocol()->RemoveLast(); endPos_ = expPos_ = -1; } void PdmlUnknownProtocol::unknownFieldHandler(QString name, int pos, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::HexDump *hexDump = pbProto->MutableExtension(OstProto::hexDump); qDebug(" hexdump: %s, pos = %d, expPos_ = %d, endPos_ = %d\n", name.toAscii().constData(), pos, expPos_, endPos_); // Skipped field? Pad with zero! if ((pos > expPos_) && (expPos_ < endPos_)) { QByteArray hexVal(pos - expPos_, char(0)); hexDump->mutable_content()->append(hexVal.constData(), hexVal.size()); expPos_ += hexVal.size(); } if (pos == expPos_) { QByteArray hexVal = attributes.value("unmaskedvalue").isEmpty() ? QByteArray::fromHex(attributes.value("value").toString().toUtf8()) : QByteArray::fromHex(attributes.value("unmaskedvalue").toString().toUtf8()); hexDump->mutable_content()->append(hexVal.constData(), hexVal.size()); expPos_ += hexVal.size(); } } // ---------------------------------------------------------- // // PdmlGenInfoProtocol // // ---------------------------------------------------------- // PdmlGenInfoProtocol::PdmlGenInfoProtocol() { } PdmlProtocol* PdmlGenInfoProtocol::createInstance() { return new PdmlGenInfoProtocol(); } // ---------------------------------------------------------- // // PdmlFrameProtocol // // ---------------------------------------------------------- // PdmlFrameProtocol::PdmlFrameProtocol() { } PdmlProtocol* PdmlFrameProtocol::createInstance() { return new PdmlFrameProtocol(); } void PdmlFrameProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream) { if (name == "frame.len") { int len = -1; if (!attributes.value("show").isEmpty()) len = attributes.value("show").toString().toInt(); stream->mutable_core()->set_frame_len(len+4); // TODO:check FCS } else if (name == "frame.time_delta") { if (!attributes.value("show").isEmpty()) { QString delta = attributes.value("show").toString(); int decimal = delta.indexOf('.'); if (decimal >= 0) { const uint kNsecsInSec = 1000000000; uint sec = delta.left(decimal).toUInt(); uint nsec = delta.mid(decimal+1).toUInt(); uint ipg = sec*kNsecsInSec + nsec; if (ipg) { stream->mutable_control()->set_packets_per_sec( kNsecsInSec/ipg); } qDebug("sec.nsec = %u.%u, ipg = %u", sec, nsec, ipg); } } } } // ---------------------------------------------------------- // // PdmlSvlanProtocol // // ---------------------------------------------------------- // PdmlSvlanProtocol::PdmlSvlanProtocol() { ostProtoId_ = OstProto::Protocol::kSvlanFieldNumber; } PdmlProtocol* PdmlSvlanProtocol::createInstance() { return new PdmlSvlanProtocol(); } void PdmlSvlanProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::Vlan *svlan = pbProto->MutableExtension(OstProto::svlan); svlan->set_tpid(0x88a8); svlan->set_is_override_tpid(true); // If a eth2 protocol precedes svlan, we remove the eth2 protocol // 'coz the eth2.etherType is actually the svlan.tpid // // We assume that the current protocol is the last in the stream int index = stream->protocol_size() - 1; if ((index > 1) && (stream->protocol(index).protocol_id().id() == OstProto::Protocol::kSvlanFieldNumber) && (stream->protocol(index - 1).protocol_id().id() == OstProto::Protocol::kEth2FieldNumber)) { stream->mutable_protocol()->SwapElements(index, index - 1); Q_ASSERT(stream->protocol(index).protocol_id().id() == OstProto::Protocol::kEth2FieldNumber); stream->mutable_protocol()->RemoveLast(); } } void PdmlSvlanProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream) { if ((name == "ieee8021ad.id") || (name == "ieee8021ad.svid")) { bool isOk; OstProto::Vlan *svlan = pbProto->MutableExtension(OstProto::svlan); uint tag = attributes.value("unmaskedvalue").isEmpty() ? attributes.value("value").toString().toUInt(&isOk, kBaseHex) : attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex); svlan->set_vlan_tag(tag); } else if (name == "ieee8021ad.cvid") { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kSvlanFieldNumber); OstProto::Vlan *svlan = proto->MutableExtension(OstProto::svlan); svlan->set_tpid(0x88a8); svlan->set_is_override_tpid(true); bool isOk; uint tag = attributes.value("unmaskedvalue").isEmpty() ? attributes.value("value").toString().toUInt(&isOk, kBaseHex) : attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex); svlan->set_vlan_tag(tag); } else if (name == "ieee8021ah.etype") // yes 'ah' not 'ad' - not a typo! { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kEth2FieldNumber); bool isOk; OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2); eth2->set_type(attributes.value("value") .toString().toUInt(&isOk, kBaseHex)); eth2->set_is_override_type(true); } } // ---------------------------------------------------------- // // PdmlVlanProtocol // // ---------------------------------------------------------- // PdmlVlanProtocol::PdmlVlanProtocol() { ostProtoId_ = OstProto::Protocol::kVlanFieldNumber; } PdmlProtocol* PdmlVlanProtocol::createInstance() { return new PdmlVlanProtocol(); } void PdmlVlanProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::Vlan *vlan = pbProto->MutableExtension(OstProto::vlan); vlan->set_tpid(0x8100); vlan->set_is_override_tpid(true); // If a eth2 protocol precedes vlan, we remove the eth2 protocol // 'coz the eth2.etherType is actually the vlan.tpid // // We assume that the current protocol is the last in the stream int index = stream->protocol_size() - 1; if ((index > 1) && (stream->protocol(index).protocol_id().id() == OstProto::Protocol::kVlanFieldNumber) && (stream->protocol(index - 1).protocol_id().id() == OstProto::Protocol::kEth2FieldNumber)) { stream->mutable_protocol()->SwapElements(index, index - 1); Q_ASSERT(stream->protocol(index).protocol_id().id() == OstProto::Protocol::kEth2FieldNumber); stream->mutable_protocol()->RemoveLast(); } } void PdmlVlanProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream) { if (name == "vlan.id") { bool isOk; OstProto::Vlan *vlan = pbProto->MutableExtension(OstProto::vlan); uint tag = attributes.value("unmaskedvalue").isEmpty() ? attributes.value("value").toString().toUInt(&isOk, kBaseHex) : attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex); vlan->set_vlan_tag(tag); } else if (name == "vlan.etype") { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kEth2FieldNumber); bool isOk; OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2); eth2->set_type(attributes.value("value") .toString().toUInt(&isOk, kBaseHex)); eth2->set_is_override_type(true); } } // ---------------------------------------------------------- // // PdmlEthProtocol // // ---------------------------------------------------------- // PdmlEthProtocol::PdmlEthProtocol() { ostProtoId_ = OstProto::Protocol::kMacFieldNumber; fieldMap_.insert("eth.dst", OstProto::Mac::kDstMacFieldNumber); fieldMap_.insert("eth.src", OstProto::Mac::kSrcMacFieldNumber); } PdmlProtocol* PdmlEthProtocol::createInstance() { return new PdmlEthProtocol(); } void PdmlEthProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream) { if (name == "eth.vlan.tpid") { bool isOk; uint tpid = attributes.value("value").toString() .toUInt(&isOk, kBaseHex); OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kVlanFieldNumber); OstProto::Vlan *vlan = proto->MutableExtension(OstProto::vlan); vlan->set_tpid(tpid); vlan->set_is_override_tpid(true); } else if (name == "eth.vlan.id") { bool isOk; uint tag = attributes.value("unmaskedvalue").isEmpty() ? attributes.value("value").toString().toUInt(&isOk, kBaseHex) : attributes.value("unmaskedvalue").toString().toUInt(&isOk,kBaseHex); OstProto::Vlan *vlan = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::vlan); vlan->set_vlan_tag(tag); } else if (name == "eth.type") { bool isOk; uint type = attributes.value("value").toString() .toUInt(&isOk, kBaseHex); OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kEth2FieldNumber); OstProto::Eth2 *eth2 = proto->MutableExtension(OstProto::eth2); eth2->set_type(type); eth2->set_is_override_type(true); } else if (name == "eth.len") { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kDot3FieldNumber); OstProto::Dot3 *dot3 = proto->MutableExtension(OstProto::dot3); bool isOk; dot3->set_length(attributes.value("value").toString().toUInt(&isOk, kBaseHex)); dot3->set_is_override_length(true); } #if 0 else if (name == "eth.trailer") { QByteArray trailer = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); stream->mutable_core()->mutable_name()->append(trailer.constData(), trailer.size()); } else if ((name == "eth.fcs") || attributes.value("show").toString().startsWith("Frame check sequence")) { QByteArray trailer = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); stream->mutable_core()->mutable_name()->append(trailer.constData(), trailer.size()); } #endif } // ---------------------------------------------------------- // // PdmlLlcProtocol // // ---------------------------------------------------------- // PdmlLlcProtocol::PdmlLlcProtocol() { ostProtoId_ = OstProto::Protocol::kLlcFieldNumber; fieldMap_.insert("llc.dsap", OstProto::Llc::kDsapFieldNumber); fieldMap_.insert("llc.ssap", OstProto::Llc::kSsapFieldNumber); fieldMap_.insert("llc.control", OstProto::Llc::kCtlFieldNumber); } PdmlProtocol* PdmlLlcProtocol::createInstance() { return new PdmlLlcProtocol(); } void PdmlLlcProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream) { if (name == "llc.oui") { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kSnapFieldNumber); OstProto::Snap *snap = proto->MutableExtension(OstProto::snap); bool isOk; snap->set_oui(attributes.value("value").toString() .toUInt(&isOk, kBaseHex)); snap->set_is_override_oui(true); } else if ((name == "llc.type") || (name.contains(QRegExp("llc\\..*pid")))) { OstProto::Snap *snap = stream->mutable_protocol( stream->protocol_size()-1)->MutableExtension(OstProto::snap); bool isOk; snap->set_type(attributes.value("value").toString() .toUInt(&isOk, kBaseHex)); snap->set_is_override_type(true); } } void PdmlLlcProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::Llc *llc = pbProto->MutableExtension(OstProto::llc); llc->set_is_override_dsap(true); llc->set_is_override_ssap(true); llc->set_is_override_ctl(true); } // ---------------------------------------------------------- // // PdmlArpProtocol // // ---------------------------------------------------------- // PdmlArpProtocol::PdmlArpProtocol() { ostProtoId_ = OstProto::Protocol::kArpFieldNumber; fieldMap_.insert("arp.opcode", OstProto::Arp::kOpCodeFieldNumber); fieldMap_.insert("arp.src.hw_mac", OstProto::Arp::kSenderHwAddrFieldNumber); fieldMap_.insert("arp.src.proto_ipv4", OstProto::Arp::kSenderProtoAddrFieldNumber); fieldMap_.insert("arp.dst.hw_mac", OstProto::Arp::kTargetHwAddrFieldNumber); fieldMap_.insert("arp.dst.proto_ipv4", OstProto::Arp::kTargetProtoAddrFieldNumber); } PdmlProtocol* PdmlArpProtocol::createInstance() { return new PdmlArpProtocol(); } // ---------------------------------------------------------- // // PdmlIp4Protocol // // ---------------------------------------------------------- // PdmlIp4Protocol::PdmlIp4Protocol() { ostProtoId_ = OstProto::Protocol::kIp4FieldNumber; fieldMap_.insert("ip.version", OstProto::Ip4::kVerHdrlenFieldNumber); fieldMap_.insert("ip.dsfield", OstProto::Ip4::kTosFieldNumber); fieldMap_.insert("ip.len", OstProto::Ip4::kTotlenFieldNumber); fieldMap_.insert("ip.id", OstProto::Ip4::kIdFieldNumber); //fieldMap_.insert("ip.flags", OstProto::Ip4::kFlagsFieldNumber); fieldMap_.insert("ip.frag_offset", OstProto::Ip4::kFragOfsFieldNumber); fieldMap_.insert("ip.ttl", OstProto::Ip4::kTtlFieldNumber); fieldMap_.insert("ip.proto", OstProto::Ip4::kProtoFieldNumber); fieldMap_.insert("ip.checksum", OstProto::Ip4::kCksumFieldNumber); fieldMap_.insert("ip.src", OstProto::Ip4::kSrcIpFieldNumber); fieldMap_.insert("ip.dst", OstProto::Ip4::kDstIpFieldNumber); } PdmlProtocol* PdmlIp4Protocol::createInstance() { return new PdmlIp4Protocol(); } void PdmlIp4Protocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; if ((name == "ip.options") || attributes.value("show").toString().startsWith("Options")) { options_ = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); } else if (name == "ip.flags") { OstProto::Ip4 *ip4 = pbProto->MutableExtension(OstProto::ip4); ip4->set_flags(attributes.value("value").toString().toUInt(&isOk, kBaseHex) >> 5); } } void PdmlIp4Protocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::Ip4 *ip4 = pbProto->MutableExtension(OstProto::ip4); ip4->set_is_override_ver(true); ip4->set_is_override_hdrlen(true); ip4->set_is_override_totlen(true); ip4->set_is_override_proto(true); ip4->set_is_override_cksum(true); if (options_.size()) { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kHexDumpFieldNumber); OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); hexDump->mutable_content()->append(options_.constData(), options_.size()); hexDump->set_pad_until_end(false); options_.resize(0); } } // ---------------------------------------------------------- // // PdmlIp6Protocol // // ---------------------------------------------------------- // PdmlIp6Protocol::PdmlIp6Protocol() { ostProtoId_ = OstProto::Protocol::kIp6FieldNumber; fieldMap_.insert("ipv6.version", OstProto::Ip6::kVersionFieldNumber); fieldMap_.insert("ipv6.class", OstProto::Ip6::kTrafficClassFieldNumber); fieldMap_.insert("ipv6.flow", OstProto::Ip6::kFlowLabelFieldNumber); fieldMap_.insert("ipv6.plen", OstProto::Ip6::kPayloadLengthFieldNumber); fieldMap_.insert("ipv6.nxt", OstProto::Ip6::kNextHeaderFieldNumber); fieldMap_.insert("ipv6.hlim", OstProto::Ip6::kHopLimitFieldNumber); // ipv6.src and ipv6.dst handled as unknown fields } PdmlProtocol* PdmlIp6Protocol::createInstance() { return new PdmlIp6Protocol(); } void PdmlIp6Protocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; if (name == "ipv6.src") { OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6); QString addrHexStr = attributes.value("value").toString(); ip6->set_src_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip6->set_src_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex)); } else if (name == "ipv6.dst") { OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6); QString addrHexStr = attributes.value("value").toString(); ip6->set_dst_addr_hi(addrHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip6->set_dst_addr_lo(addrHexStr.right(16).toULongLong(&isOk, kBaseHex)); } } void PdmlIp6Protocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::Ip6 *ip6 = pbProto->MutableExtension(OstProto::ip6); ip6->set_is_override_version(true); ip6->set_is_override_payload_length(true); ip6->set_is_override_next_header(true); } // ---------------------------------------------------------- // // PdmlIcmpProtocol // // ---------------------------------------------------------- // PdmlIcmpProtocol::PdmlIcmpProtocol() { ostProtoId_ = OstProto::Protocol::kIcmpFieldNumber; fieldMap_.insert("icmp.type", OstProto::Icmp::kTypeFieldNumber); fieldMap_.insert("icmp.code", OstProto::Icmp::kCodeFieldNumber); fieldMap_.insert("icmp.checksum", OstProto::Icmp::kChecksumFieldNumber); fieldMap_.insert("icmp.ident", OstProto::Icmp::kIdentifierFieldNumber); fieldMap_.insert("icmp.seq", OstProto::Icmp::kSequenceFieldNumber); fieldMap_.insert("icmpv6.type", OstProto::Icmp::kTypeFieldNumber); fieldMap_.insert("icmpv6.code", OstProto::Icmp::kCodeFieldNumber); fieldMap_.insert("icmpv6.checksum", OstProto::Icmp::kChecksumFieldNumber); fieldMap_.insert("icmpv6.echo.identifier", OstProto::Icmp::kIdentifierFieldNumber); fieldMap_.insert("icmpv6.echo.sequence_number", OstProto::Icmp::kSequenceFieldNumber); } PdmlProtocol* PdmlIcmpProtocol::createInstance() { return new PdmlIcmpProtocol(); } void PdmlIcmpProtocol::preProtocolHandler(QString name, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp); if (name == "icmp") icmp->set_icmp_version(OstProto::Icmp::kIcmp4); else if (name == "icmpv6") icmp->set_icmp_version(OstProto::Icmp::kIcmp6); icmp->set_is_override_checksum(true); icmp->set_type(kIcmpInvalidType); } void PdmlIcmpProtocol::unknownFieldHandler(QString /*name*/, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp); if ((icmp->icmp_version() == OstProto::Icmp::kIcmp6) && (icmp->type() >= kIcmp6EchoRequest) && (icmp->type() <= kIcmp6EchoReply)) { QString addrHexStr = attributes.value("value").toString(); // Wireshark 1.4.x does not have these as filterable fields if (attributes.value("show").toString().startsWith("ID")) icmp->set_identifier(addrHexStr.toUInt(&isOk, kBaseHex)); else if (attributes.value("show").toString().startsWith("Sequence")) icmp->set_sequence(addrHexStr.toUInt(&isOk, kBaseHex)); } } void PdmlIcmpProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::Icmp *icmp = pbProto->MutableExtension(OstProto::icmp); if (icmp->type() == kIcmpInvalidType) stream->mutable_protocol()->RemoveLast(); } // ---------------------------------------------------------- // // PdmlIcmp6Protocol // // ---------------------------------------------------------- // PdmlIcmp6Protocol::PdmlIcmp6Protocol() { ostProtoId_ = OstProto::Protocol::kSampleFieldNumber; proto_ = NULL; } PdmlProtocol* PdmlIcmp6Protocol::createInstance() { return new PdmlIcmp6Protocol(); } void PdmlIcmp6Protocol::preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream) { proto_ = NULL; ostProtoId_ = OstProto::Protocol::kSampleFieldNumber; icmp_.preProtocolHandler(name, attributes, expectedPos, pbProto, stream); mld_.preProtocolHandler(name, attributes, expectedPos, pbProto, stream); } void PdmlIcmp6Protocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { if (proto_) proto_->postProtocolHandler(pbProto, stream); else stream->mutable_protocol()->RemoveLast(); proto_ = NULL; ostProtoId_ = OstProto::Protocol::kSampleFieldNumber; } void PdmlIcmp6Protocol::unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream) { if (proto_) { proto_->unknownFieldHandler(name, pos, size, attributes, pbProto, stream); } else if (name == "icmpv6.type") { bool isOk; uint type = attributes.value("value").toString().toUInt( &isOk, kBaseHex); if (((type >= 130) && (type <= 132)) || (type == 143)) { // MLD proto_ = &mld_; fieldMap_ = mld_.fieldMap_; ostProtoId_ = OstProto::Protocol::kMldFieldNumber; } else { // ICMP proto_ = &icmp_; fieldMap_ = icmp_.fieldMap_; ostProtoId_ = OstProto::Protocol::kIcmpFieldNumber; } pbProto->mutable_protocol_id()->set_id(ostProtoId_); pbProto->MutableExtension(OstProto::sample)->Clear(); fieldHandler(name, attributes, pbProto, stream); } else { qDebug("unexpected field %s", name.toAscii().constData()); } } // ---------------------------------------------------------- // // PdmlIgmpProtocol // // ---------------------------------------------------------- // PdmlIgmpProtocol::PdmlIgmpProtocol() { ostProtoId_ = OstProto::Protocol::kIgmpFieldNumber; fieldMap_.insert("igmp.max_resp", OstProto::Gmp::kMaxResponseTimeFieldNumber); // FIXME fieldMap_.insert("igmp.checksum", OstProto::Gmp::kChecksumFieldNumber); fieldMap_.insert("igmp.s", OstProto::Gmp::kSFlagFieldNumber); fieldMap_.insert("igmp.qrv", OstProto::Gmp::kQrvFieldNumber); fieldMap_.insert("igmp.qqic", OstProto::Gmp::kQqiFieldNumber); // FIXME fieldMap_.insert("igmp.num_grp_recs", OstProto::Gmp::kGroupRecordCountFieldNumber); } PdmlProtocol* PdmlIgmpProtocol::createInstance() { return new PdmlIgmpProtocol(); } void PdmlIgmpProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::Gmp *igmp = pbProto->MutableExtension(OstProto::igmp); igmp->set_is_override_rsvd_code(true); igmp->set_is_override_checksum(true); igmp->set_is_override_source_count(true); igmp->set_is_override_group_record_count(true); version_ = 0; } void PdmlIgmpProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; OstProto::Gmp *igmp = pbProto->MutableExtension(OstProto::igmp); QString valueHexStr = attributes.value("value").toString(); if (name == "igmp.version") { version_ = attributes.value("show").toString().toUInt(&isOk); } else if (name == "igmp.type") { uint type = valueHexStr.toUInt(&isOk, kBaseHex); if (type == kIgmpQuery) { switch(version_) { case 1: type = kIgmpV1Query; break; case 2: type = kIgmpV2Query; break; case 3: type = kIgmpV3Query; break; } } igmp->set_type(type); } else if (name == "igmp.record_type") { OstProto::Gmp::GroupRecord *rec = igmp->add_group_records(); rec->set_type(OstProto::Gmp::GroupRecord::RecordType( valueHexStr.toUInt(&isOk, kBaseHex))); rec->set_is_override_source_count(true); rec->set_is_override_aux_data_length(true); } else if (name == "igmp.aux_data_len") { igmp->mutable_group_records(igmp->group_records_size() - 1)-> set_aux_data_length(valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "igmp.num_src") { if (igmp->group_record_count()) igmp->mutable_group_records(igmp->group_records_size() - 1)-> set_source_count(valueHexStr.toUInt(&isOk, kBaseHex)); else igmp->set_source_count(valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "igmp.maddr") { if (igmp->group_record_count()) igmp->mutable_group_records(igmp->group_records_size() - 1)-> mutable_group_address()->set_v4( valueHexStr.toUInt(&isOk, kBaseHex)); else igmp->mutable_group_address()->set_v4( valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "igmp.saddr") { if (igmp->group_record_count()) igmp->mutable_group_records(igmp->group_records_size() - 1)-> add_sources()->set_v4(valueHexStr.toUInt(&isOk, kBaseHex)); else igmp->add_sources()->set_v4(valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "igmp.aux_data") { QByteArray ba = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); igmp->mutable_group_records(igmp->group_records_size() - 1)-> set_aux_data(ba.constData(), ba.size()); } } void PdmlIgmpProtocol::postProtocolHandler(OstProto::Protocol* /*pbProto*/, OstProto::Stream *stream) { // version is 0 for IGMP like protocols such as RGMP which we don't // support currently if (version_ == 0) stream->mutable_protocol()->RemoveLast(); } // ---------------------------------------------------------- // // PdmlMldProtocol // // ---------------------------------------------------------- // PdmlMldProtocol::PdmlMldProtocol() { ostProtoId_ = OstProto::Protocol::kMldFieldNumber; fieldMap_.insert("icmpv6.code", OstProto::Gmp::kRsvdCodeFieldNumber); fieldMap_.insert("icmpv6.checksum", OstProto::Gmp::kChecksumFieldNumber); fieldMap_.insert("icmpv6.mld.maximum_response_delay", OstProto::Gmp::kMaxResponseTimeFieldNumber); // FIXME fieldMap_.insert("icmpv6.mld.flag.s", OstProto::Gmp::kSFlagFieldNumber); fieldMap_.insert("icmpv6.mld.flag.qrv", OstProto::Gmp::kQrvFieldNumber); fieldMap_.insert("icmpv6.mld.qqi", OstProto::Gmp::kQqiFieldNumber); // FIXME fieldMap_.insert("icmpv6.mld.nb_sources", OstProto::Gmp::kSourceCountFieldNumber); fieldMap_.insert("icmpv6.mldr.nb_mcast_records", OstProto::Gmp::kGroupRecordCountFieldNumber); } PdmlProtocol* PdmlMldProtocol::createInstance() { return new PdmlMldProtocol(); } void PdmlMldProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes &attributes, int /*expectedPos*/, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; OstProto::Gmp *mld = pbProto->MutableExtension(OstProto::mld); mld->set_is_override_rsvd_code(true); mld->set_is_override_checksum(true); mld->set_is_override_source_count(true); mld->set_is_override_group_record_count(true); protoSize_ = attributes.value("size").toString().toUInt(&isOk); } void PdmlMldProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { bool isOk; OstProto::Gmp *mld = pbProto->MutableExtension(OstProto::mld); QString valueHexStr = attributes.value("value").toString(); if (name == "icmpv6.type") { uint type = valueHexStr.toUInt(&isOk, kBaseHex); if ((type == kMldQuery) && (protoSize_ >= 28)) type = kMldV2Query; mld->set_type(type); } else if (name == "icmpv6.mld.multicast_address") { mld->mutable_group_address()->set_v6_hi( valueHexStr.left(16).toULongLong(&isOk, kBaseHex)); mld->mutable_group_address()->set_v6_lo( valueHexStr.right(16).toULongLong(&isOk, kBaseHex)); } else if (name == "icmpv6.mld.source_address") { OstProto::Gmp::IpAddress *ip = mld->add_sources(); ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex)); } else if (name == "icmpv6.mldr.mar.record_type") { OstProto::Gmp::GroupRecord *rec = mld->add_group_records(); rec->set_type(OstProto::Gmp::GroupRecord::RecordType( valueHexStr.toUInt(&isOk, kBaseHex))); rec->set_is_override_source_count(true); rec->set_is_override_aux_data_length(true); } else if (name == "icmpv6.mldr.mar.aux_data_len") { mld->mutable_group_records(mld->group_records_size() - 1)-> set_aux_data_length(valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "icmpv6.mldr.mar.nb_sources") { mld->mutable_group_records(mld->group_records_size() - 1)-> set_source_count(valueHexStr.toUInt(&isOk, kBaseHex)); } else if (name == "icmpv6.mldr.mar.multicast_address") { OstProto::Gmp::IpAddress *ip = mld->mutable_group_records( mld->group_records_size() - 1)->mutable_group_address(); ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex)); } else if (name == "icmpv6.mldr.mar.source_address") { OstProto::Gmp::IpAddress *ip = mld->mutable_group_records( mld->group_records_size() - 1)->add_sources(); ip->set_v6_hi(valueHexStr.left(16).toULongLong(&isOk, kBaseHex)); ip->set_v6_lo(valueHexStr.right(16).toULongLong(&isOk, kBaseHex)); } else if (name == "icmpv6.mldr.mar.auxiliary_data") { QByteArray ba = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); mld->mutable_group_records(mld->group_records_size() - 1)-> set_aux_data(ba.constData(), ba.size()); } } // ---------------------------------------------------------- // // PdmlTcpProtocol // // ---------------------------------------------------------- // PdmlTcpProtocol::PdmlTcpProtocol() { ostProtoId_ = OstProto::Protocol::kTcpFieldNumber; fieldMap_.insert("tcp.srcport", OstProto::Tcp::kSrcPortFieldNumber); fieldMap_.insert("tcp.dstport", OstProto::Tcp::kDstPortFieldNumber); fieldMap_.insert("tcp.seq", OstProto::Tcp::kSeqNumFieldNumber); fieldMap_.insert("tcp.ack", OstProto::Tcp::kAckNumFieldNumber); fieldMap_.insert("tcp.hdr_len", OstProto::Tcp::kHdrlenRsvdFieldNumber); fieldMap_.insert("tcp.flags", OstProto::Tcp::kFlagsFieldNumber); fieldMap_.insert("tcp.window_size", OstProto::Tcp::kWindowFieldNumber); fieldMap_.insert("tcp.checksum", OstProto::Tcp::kCksumFieldNumber); fieldMap_.insert("tcp.urgent_pointer", OstProto::Tcp::kUrgPtrFieldNumber); } PdmlProtocol* PdmlTcpProtocol::createInstance() { return new PdmlTcpProtocol(); } void PdmlTcpProtocol::unknownFieldHandler(QString name, int /*pos*/, int /*size*/, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { if (name == "tcp.options") options_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8()); else if (name == "") { if (attributes.value("show").toString().startsWith("Acknowledgement number")) { bool isOk; OstProto::Tcp *tcp = pbProto->MutableExtension(OstProto::tcp); tcp->set_ack_num(attributes.value("value").toString().toUInt(&isOk, kBaseHex)); } #if 0 else if (attributes.value("show").toString().startsWith("TCP segment data")) { segmentData_ = QByteArray::fromHex(attributes.value("value").toString().toUtf8()); stream->mutable_core()->mutable_name()->insert(0, segmentData_.constData(), segmentData_.size()); } #endif } } void PdmlTcpProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::Tcp *tcp = pbProto->MutableExtension(OstProto::tcp); qDebug("Tcp: post\n"); tcp->set_is_override_src_port(true); tcp->set_is_override_dst_port(true); tcp->set_is_override_hdrlen(true); tcp->set_is_override_cksum(true); if (options_.size()) { OstProto::Protocol *proto = stream->add_protocol(); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kHexDumpFieldNumber); OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); hexDump->mutable_content()->append(options_.constData(), options_.size()); hexDump->set_pad_until_end(false); options_.resize(0); } } // ---------------------------------------------------------- // // PdmlUdpProtocol // // ---------------------------------------------------------- // PdmlUdpProtocol::PdmlUdpProtocol() { ostProtoId_ = OstProto::Protocol::kUdpFieldNumber; fieldMap_.insert("udp.srcport", OstProto::Udp::kSrcPortFieldNumber); fieldMap_.insert("udp.dstport", OstProto::Udp::kDstPortFieldNumber); fieldMap_.insert("udp.length", OstProto::Udp::kTotlenFieldNumber); fieldMap_.insert("udp.checksum_coverage", OstProto::Udp::kTotlenFieldNumber); fieldMap_.insert("udp.checksum", OstProto::Udp::kCksumFieldNumber); } PdmlProtocol* PdmlUdpProtocol::createInstance() { return new PdmlUdpProtocol(); } void PdmlUdpProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { OstProto::Udp *udp = pbProto->MutableExtension(OstProto::udp); qDebug("Udp: post\n"); udp->set_is_override_src_port(true); udp->set_is_override_dst_port(true); udp->set_is_override_totlen(true); udp->set_is_override_cksum(true); } // ---------------------------------------------------------- // // PdmlTextProtocol // // ---------------------------------------------------------- // PdmlTextProtocol::PdmlTextProtocol() { ostProtoId_ = OstProto::Protocol::kTextProtocolFieldNumber; } PdmlProtocol* PdmlTextProtocol::createInstance() { return new PdmlTextProtocol(); } void PdmlTextProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream) { bool isOk; int size; int pos = attributes.value("pos").toString().toUInt(&isOk); if (!isOk) { if (expectedPos >= 0) expPos_ = pos = expectedPos; else goto _skip_pos_size_proc; } size = attributes.value("size").toString().toUInt(&isOk); if (!isOk) goto _skip_pos_size_proc; // If pos+size goes beyond the frame length, this is a "reassembled" // protocol and should be skipped if ((pos + size) > int(stream->core().frame_len())) goto _skip_pos_size_proc; expPos_ = pos; endPos_ = expPos_ + size; _skip_pos_size_proc: qDebug("expPos_ = %d, endPos_ = %d", expPos_, endPos_); OstProto::TextProtocol *text = pbProto->MutableExtension( OstProto::textProtocol); text->set_port_num(0); text->set_eol(OstProto::TextProtocol::kCrLf); // by default we assume CRLF detectEol_ = true; contentType_ = kUnknownContent; } void PdmlTextProtocol::unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream* /*stream*/) { _retry: switch(contentType_) { case kUnknownContent: if (name == "data") contentType_ = kOtherContent; else contentType_ = kTextContent; goto _retry; break; case kTextContent: { OstProto::TextProtocol *text = pbProto->MutableExtension( OstProto::textProtocol); if ((name == "data") || (attributes.value("show") == "HTTP chunked response")) { contentType_ = kOtherContent; goto _retry; } if (pos < expPos_) break; if ((pos + size) > endPos_) break; if (pos > expPos_) { int gap = pos - expPos_; QByteArray filler(gap, '\n'); if (text->eol() == OstProto::TextProtocol::kCrLf) { if (gap & 0x01) // Odd { filler.resize(gap/2 + 1); filler[0]=int(' '); } else // Even filler.resize(gap/2); } text->mutable_text()->append(filler.constData(), filler.size()); expPos_ += gap; } QByteArray line = QByteArray::fromHex( attributes.value("value").toString().toUtf8()); if (detectEol_) { if (line.right(2) == "\r\n") text->set_eol(OstProto::TextProtocol::kCrLf); else if (line.right(1) == "\r") text->set_eol(OstProto::TextProtocol::kCr); else if (line.right(1) == "\n") text->set_eol(OstProto::TextProtocol::kLf); detectEol_ = false; } // Convert line endings to LF only - Qt reqmt that TextProto honours line.replace("\r\n", "\n"); line.replace('\r', '\n'); text->mutable_text()->append(line.constData(), line.size()); expPos_ += size; break; } case kOtherContent: // Do nothing! break; default: Q_ASSERT(false); } } void PdmlTextProtocol::postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream) { OstProto::TextProtocol *text = pbProto->MutableExtension( OstProto::textProtocol); // Empty Text Content - remove ourselves if (text->text().length() == 0) stream->mutable_protocol()->RemoveLast(); expPos_ = endPos_ = -1; detectEol_ = true; contentType_ = kUnknownContent; } ostinato-0.5.1/common/pdmlprotocols.h0000700000175300010010000002242412005505614017236 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PDML_PROTOCOLS_H #define _PDML_PROTOCOLS_H #include "pdmlprotocol.h" class PdmlUnknownProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void prematureEndHandler(int pos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlUnknownProtocol(); private: int endPos_; int expPos_; }; class PdmlGenInfoProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); protected: PdmlGenInfoProtocol(); }; class PdmlFrameProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlFrameProtocol(); }; class PdmlEthProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlEthProtocol(); }; class PdmlSvlanProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlSvlanProtocol(); }; class PdmlVlanProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlVlanProtocol(); }; class PdmlLlcProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlLlcProtocol(); }; class PdmlArpProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); protected: PdmlArpProtocol(); }; class PdmlIp4Protocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlIp4Protocol(); private: QByteArray options_; }; class PdmlIp6Protocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlIp6Protocol(); }; class PdmlIcmpProtocol : public PdmlProtocol { friend class PdmlIcmp6Protocol; public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlIcmpProtocol(); private: static const uint kIcmpInvalidType = 0xFFFFFFFF; static const uint kIcmp6EchoRequest = 128; static const uint kIcmp6EchoReply = 129; }; class PdmlMldProtocol : public PdmlProtocol { friend class PdmlIcmp6Protocol; public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlMldProtocol(); private: static const uint kMldQuery = 0x82; static const uint kMldV1Query = 0x82; static const uint kMldV2Query = 0xFF82; uint protoSize_; }; class PdmlIcmp6Protocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlIcmp6Protocol(); private: PdmlIcmpProtocol icmp_; PdmlMldProtocol mld_; PdmlProtocol *proto_; }; class PdmlIgmpProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlIgmpProtocol(); private: static const uint kIgmpQuery = 0x11; static const uint kIgmpV1Query = 0x11; static const uint kIgmpV2Query = 0xFF11; static const uint kIgmpV3Query = 0xFE11; uint version_; }; class PdmlTcpProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlTcpProtocol(); private: QByteArray options_; QByteArray segmentData_; }; class PdmlUdpProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlUdpProtocol(); }; class PdmlTextProtocol : public PdmlProtocol { public: static PdmlProtocol* createInstance(); virtual void preProtocolHandler(QString name, const QXmlStreamAttributes &attributes, int expectedPos, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void unknownFieldHandler(QString name, int pos, int size, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream); virtual void postProtocolHandler(OstProto::Protocol *pbProto, OstProto::Stream *stream); protected: PdmlTextProtocol(); private: enum ContentType { kUnknownContent, kTextContent, kOtherContent }; bool detectEol_; ContentType contentType_; int expPos_; int endPos_; }; #endif ostinato-0.5.1/common/pdmlreader.cpp0000700000175300010010000003653712005505614017021 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pdmlreader.h" #include "abstractprotocol.h" #include "hexdump.pb.h" #include "pcapfileformat.h" #include "streambase.h" #include "pdmlprotocols.h" PdmlReader::PdmlReader(OstProto::StreamConfigList *streams) { //gPdmlReader = this; pcap_ = NULL; streams_ = streams; currentStream_ = NULL; prevStream_ = NULL; stop_ = NULL; factory_.insert("hexdump", PdmlUnknownProtocol::createInstance); factory_.insert("geninfo", PdmlGenInfoProtocol::createInstance); factory_.insert("frame", PdmlFrameProtocol::createInstance); factory_.insert("arp", PdmlArpProtocol::createInstance); factory_.insert("eth", PdmlEthProtocol::createInstance); factory_.insert("http", PdmlTextProtocol::createInstance); factory_.insert("icmp", PdmlIcmpProtocol::createInstance); factory_.insert("icmpv6", PdmlIcmp6Protocol::createInstance); factory_.insert("igmp", PdmlIgmpProtocol::createInstance); factory_.insert("ieee8021ad", PdmlSvlanProtocol::createInstance); factory_.insert("imap", PdmlTextProtocol::createInstance); factory_.insert("ip", PdmlIp4Protocol::createInstance); factory_.insert("ipv6", PdmlIp6Protocol::createInstance); factory_.insert("llc", PdmlLlcProtocol::createInstance); factory_.insert("nntp", PdmlTextProtocol::createInstance); factory_.insert("pop", PdmlTextProtocol::createInstance); factory_.insert("rtsp", PdmlTextProtocol::createInstance); factory_.insert("sdp", PdmlTextProtocol::createInstance); factory_.insert("sip", PdmlTextProtocol::createInstance); factory_.insert("smtp", PdmlTextProtocol::createInstance); factory_.insert("tcp", PdmlTcpProtocol::createInstance); factory_.insert("udp", PdmlUdpProtocol::createInstance); factory_.insert("udplite", PdmlUdpProtocol::createInstance); factory_.insert("vlan", PdmlVlanProtocol::createInstance); } PdmlReader::~PdmlReader() { } bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap, bool *stop) { setDevice(device); pcap_ = pcap; stop_ = stop; while (!atEnd()) { readNext(); if (isStartElement()) { if (name() == "pdml") readPdml(); else raiseError("Not a pdml file!"); } } if (error() && (errorString() != "USER-CANCEL")) { qDebug("Line %lld", lineNumber()); qDebug("Col %lld", columnNumber()); qDebug("%s", errorString().toAscii().constData()); return false; } return true; } // TODO: use a temp pool to avoid a lot of new/delete PdmlProtocol* PdmlReader::allocPdmlProtocol(QString protoName) { // If protoName is not known, we use a hexdump if (!factory_.contains(protoName)) protoName = "hexdump"; // If MLD is not supported by the creator of the PDML, we interpret // ICMPv6 as ICMP since our implementation of the ICMPv6 PDML protocol // exists just to distinguish between MLD and ICMP. Non MLD ICMPv6 is // also handled by ICMP only if (!isMldSupport_ && (protoName == "icmpv6")) protoName = "icmp"; return (*(factory_.value(protoName)))(); } void PdmlReader::freePdmlProtocol(PdmlProtocol *proto) { delete proto; } bool PdmlReader::isDontCareProto() { Q_ASSERT(isStartElement() && name() == "proto"); QStringRef protoName = attributes().value("name"); if (protoName.isEmpty() || (protoName == "expert")) return true; return false; } void PdmlReader::skipElement() { Q_ASSERT(isStartElement()); qDebug("skipping element - <%s>", name().toString().toAscii().constData()); while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) skipElement(); } } void PdmlReader::readPdml() { QStringList creator; Q_ASSERT(isStartElement() && name() == "pdml"); isMldSupport_ = true; creator = attributes().value("creator").toString().split('/'); if ((creator.size() >= 2) && (creator.at(0) == "wireshark")) { QList minMldVer; minMldVer << 1 << 5 << 0; QStringList version = creator.at(1).split('.'); for (int i = 0; i < qMin(version.size(), minMldVer.size()); i++) { if (version.at(i).toUInt() < minMldVer.at(i)) { isMldSupport_ = false; break; } } } packetCount_ = 1; while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "packet") readPacket(); else skipElement(); } } } void PdmlReader::readPacket() { PcapFileFormat::PcapPacketHeader pktHdr; Q_ASSERT(isStartElement() && name() == "packet"); qDebug("%s: packetNum = %d", __FUNCTION__, packetCount_); skipUntilEnd_ = false; // XXX: we play dumb and convert each packet to a stream, for now prevStream_ = currentStream_; currentStream_ = streams_->add_stream(); currentStream_->mutable_stream_id()->set_id(packetCount_); currentStream_->mutable_core()->set_is_enabled(true); // Set to a high number; will get reset to correct value during parse currentStream_->mutable_core()->set_frame_len(16384); // FIXME: Hard coding! expPos_ = 0; if (pcap_) pcap_->readPacket(pktHdr, pktBuf_); while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (skipUntilEnd_) skipElement(); else if (name() == "proto") readProto(); else if (name() == "field") readField(NULL, NULL); // TODO: top level field!!!! else skipElement(); } } currentStream_->mutable_core()->set_name(""); // FIXME // If trailing bytes are missing, add those from the pcap if ((expPos_ < pktBuf_.size()) && pcap_) { OstProto::Protocol *proto = currentStream_->add_protocol(); OstProto::HexDump *hexDump = proto->MutableExtension( OstProto::hexDump); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kHexDumpFieldNumber); qDebug("adding trailing %d bytes starting from %d", pktBuf_.size() - expPos_, expPos_); hexDump->set_content(pktBuf_.constData() + expPos_, pktBuf_.size() - expPos_); hexDump->set_pad_until_end(false); } packetCount_++; emit progress(int(characterOffset()*100/device()->size())); // in % if (prevStream_) prevStream_->mutable_control()->CopyFrom(currentStream_->control()); if (stop_ && *stop_) raiseError("USER-CANCEL"); } void PdmlReader::readProto() { PdmlProtocol *pdmlProto = NULL; OstProto::Protocol *pbProto = NULL; Q_ASSERT(isStartElement() && name() == "proto"); QString protoName; int pos = -1; int size = -1; if (!attributes().value("name").isEmpty()) protoName = attributes().value("name").toString(); if (!attributes().value("pos").isEmpty()) pos = attributes().value("pos").toString().toInt(); if (!attributes().value("size").isEmpty()) size = attributes().value("size").toString().toInt(); qDebug("proto: %s, pos = %d, expPos_ = %d, size = %d", protoName.toAscii().constData(), pos, expPos_, size); // This is a heuristic to skip protocols which are not part of // this frame, but of a reassembled segment spanning several frames // 1. Proto starting pos is 0, but we've already seen some protocols // 2. Protocol Size exceeds frame length if (((pos == 0) && (currentStream_->protocol_size() > 0)) || ((pos + size) > int(currentStream_->core().frame_len()))) { skipElement(); return; } if (isDontCareProto()) { skipElement(); return; } // if we detect a gap between subsequent protocols, we "fill-in" // with a "hexdump" from the pcap if (pos > expPos_ && pcap_) { appendHexDumpProto(expPos_, pos - expPos_); expPos_ = pos; } // for unknown protocol, read a hexdump from the pcap if (!factory_.contains(protoName) && pcap_) { int size = -1; if (!attributes().value("size").isEmpty()) size = attributes().value("size").toString().toInt(); // Check if this proto is a subset of previous proto - if so, do nothing if ((pos >= 0) && (size > 0) && ((pos + size) <= expPos_)) { qDebug("subset proto"); skipElement(); return; } if (pos >= 0 && size > 0 && ((pos + size) <= pktBuf_.size())) { appendHexDumpProto(pos, size); expPos_ += size; skipElement(); return; } } pdmlProto = appendPdmlProto(protoName, &pbProto); qDebug("%s: preProtocolHandler(expPos = %d)", protoName.toAscii().constData(), expPos_); pdmlProto->preProtocolHandler(protoName, attributes(), expPos_, pbProto, currentStream_); while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "proto") { // an embedded proto qDebug("embedded proto: %s\n", attributes().value("name") .toString().toAscii().constData()); if (isDontCareProto()) { skipElement(); continue; } // if we are in the midst of processing a protocol, we // end it prematurely before we start processing the // embedded protocol // // XXX: pdmlProto may be NULL for a sequence of embedded protos if (pdmlProto) { int endPos = -1; if (!attributes().value("pos").isEmpty()) endPos = attributes().value("pos").toString().toInt(); pdmlProto->prematureEndHandler(endPos, pbProto, currentStream_); pdmlProto->postProtocolHandler(pbProto, currentStream_); StreamBase s; s.protoDataCopyFrom(*currentStream_); expPos_ = s.frameProtocolLength(0); } readProto(); pdmlProto = NULL; pbProto = NULL; } else if (name() == "field") { if ((protoName == "fake-field-wrapper") && (attributes().value("name") == "tcp.segments")) { skipElement(); qDebug("[skipping reassembled tcp segments]"); skipUntilEnd_ = true; continue; } if (pdmlProto == NULL) { pdmlProto = appendPdmlProto(protoName, &pbProto); qDebug("%s: preProtocolHandler(expPos = %d)", protoName.toAscii().constData(), expPos_); pdmlProto->preProtocolHandler(protoName, attributes(), expPos_, pbProto, currentStream_); } readField(pdmlProto, pbProto); } else skipElement(); } } // Close-off current protocol if (pdmlProto) { pdmlProto->postProtocolHandler(pbProto, currentStream_); freePdmlProtocol(pdmlProto); StreamBase s; s.protoDataCopyFrom(*currentStream_); expPos_ = s.frameProtocolLength(0); } } void PdmlReader::readField(PdmlProtocol *pdmlProto, OstProto::Protocol *pbProto) { Q_ASSERT(isStartElement() && name() == "field"); // fields with "hide='yes'" are informational and should be skipped if (attributes().value("hide") == "yes") { skipElement(); return; } QString fieldName = attributes().value("name").toString(); qDebug(" fieldName:%s", fieldName.toAscii().constData()); pdmlProto->fieldHandler(fieldName, attributes(), pbProto, currentStream_); while (!atEnd()) { readNext(); if (isEndElement()) break; if (isStartElement()) { if (name() == "proto") { // Since we are in the midst of processing a protocol, we // end it prematurely before we start processing the // embedded protocol // int endPos = -1; if (!attributes().value("pos").isEmpty()) endPos = attributes().value("pos").toString().toInt(); pdmlProto->prematureEndHandler(endPos, pbProto, currentStream_); pdmlProto->postProtocolHandler(pbProto, currentStream_); StreamBase s; s.protoDataCopyFrom(*currentStream_); expPos_ = s.frameProtocolLength(0); readProto(); } else if (name() == "field") readField(pdmlProto, pbProto); else skipElement(); } } } void PdmlReader::appendHexDumpProto(int offset, int size) { OstProto::Protocol *proto = currentStream_->add_protocol(); OstProto::HexDump *hexDump = proto->MutableExtension(OstProto::hexDump); proto->mutable_protocol_id()->set_id( OstProto::Protocol::kHexDumpFieldNumber); qDebug("filling in gap of %d bytes starting from %d", size, offset); hexDump->set_content(pktBuf_.constData() + offset, size); hexDump->set_pad_until_end(false); } PdmlProtocol* PdmlReader::appendPdmlProto(const QString &protoName, OstProto::Protocol **pbProto) { PdmlProtocol* pdmlProto = allocPdmlProtocol(protoName); Q_ASSERT(pdmlProto != NULL); int protoId = pdmlProto->ostProtoId(); if (protoId > 0) // Non-Base Class { OstProto::Protocol *proto = currentStream_->add_protocol(); proto->mutable_protocol_id()->set_id(protoId); const google::protobuf::Reflection *msgRefl = proto->GetReflection(); const google::protobuf::FieldDescriptor *fieldDesc = msgRefl->FindKnownExtensionByNumber(protoId); // TODO: if !fDesc // init default values of all fields in protocol msgRefl->MutableMessage(proto, fieldDesc); *pbProto = proto; qDebug("%s: name = %s", __FUNCTION__, protoName.toAscii().constData()); } else *pbProto = NULL; return pdmlProto; } ostinato-0.5.1/common/pdmlreader.h0000700000175300010010000000365012005505614016454 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PDML_READER_H #define _PDML_READER_H #include "pdmlprotocol.h" #include #include class PcapFileFormat; class PdmlReader : public QObject, public QXmlStreamReader { Q_OBJECT public: PdmlReader(OstProto::StreamConfigList *streams); ~PdmlReader(); bool read(QIODevice *device, PcapFileFormat *pcap = NULL, bool *stop = NULL); signals: void progress(int value); private: PdmlProtocol* allocPdmlProtocol(QString protoName); void freePdmlProtocol(PdmlProtocol *proto); bool isDontCareProto(); void skipElement(); void readPdml(); void readPacket(); void readProto(); void readField(PdmlProtocol *pdmlProto, OstProto::Protocol *pbProto); void appendHexDumpProto(int offset, int size); PdmlProtocol* appendPdmlProto(const QString &protoName, OstProto::Protocol **pbProto); typedef PdmlProtocol* (*FactoryMethod)(); QMap factory_; bool *stop_; OstProto::StreamConfigList *streams_; PcapFileFormat *pcap_; QByteArray pktBuf_; bool isMldSupport_; int packetCount_; int expPos_; bool skipUntilEnd_; OstProto::Stream *prevStream_; OstProto::Stream *currentStream_; }; #endif ostinato-0.5.1/common/protocol.proto0000700000175300010010000001432412005505614017112 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ package OstProto; option cc_generic_services = true; message StreamId { required uint32 id = 1; } message StreamCore { enum FrameLengthMode { e_fl_fixed = 0; e_fl_inc = 1; e_fl_dec = 2; e_fl_random = 3; } // Basics optional string name = 1; optional bool is_enabled = 2; optional uint32 ordinal = 3; // Frame Length (includes CRC) optional FrameLengthMode len_mode = 14 [default = e_fl_fixed]; optional uint32 frame_len = 15 [default = 64]; optional uint32 frame_len_min = 16 [default = 64]; optional uint32 frame_len_max = 17 [default = 1518]; } message StreamControl { enum SendUnit { e_su_packets = 0; e_su_bursts = 1; } enum SendMode { e_sm_fixed = 0; e_sm_continuous = 1; } enum NextWhat { e_nw_stop = 0; e_nw_goto_next = 1; e_nw_goto_id = 2; } optional SendUnit unit = 1 [default = e_su_packets]; optional SendMode mode = 2 [default = e_sm_fixed]; optional uint32 num_packets = 3 [default = 1]; optional uint32 num_bursts = 4 [default = 1]; optional uint32 packets_per_burst = 5 [default = 10]; optional NextWhat next = 6 [default = e_nw_goto_next]; optional uint32 OBSOLETE_packets_per_sec = 7 [default = 1, deprecated=true]; optional uint32 OBSOLETE_bursts_per_sec = 8 [default = 1, deprecated=true]; optional double packets_per_sec = 9 [default = 1]; optional double bursts_per_sec = 10 [default = 1]; } message ProtocolId { required uint32 id = 1; } message Protocol { required ProtocolId protocol_id = 1; extensions 100 to 199; // Reserved for Ostinato Use extensions 200 to 500; // Available for use by protocols enum k { kMacFieldNumber = 100; kPayloadFieldNumber = 101; kSampleFieldNumber = 102; kUserScriptFieldNumber = 103; kHexDumpFieldNumber = 104; kEth2FieldNumber = 200; kDot3FieldNumber = 201; kLlcFieldNumber = 202; kSnapFieldNumber = 203; kSvlanFieldNumber = 204; kVlanFieldNumber = 205; kDot2LlcFieldNumber = 206; kDot2SnapFieldNumber = 207; kVlanStackFieldNumber = 208; kArpFieldNumber = 300; kIp4FieldNumber = 301; kIp6FieldNumber = 302; kIp6over4FieldNumber = 303; kIp4over6FieldNumber = 304; kIp4over4FieldNumber = 305; kIp6over6FieldNumber = 306; kTcpFieldNumber = 400; kUdpFieldNumber = 401; kIcmpFieldNumber = 402; kIgmpFieldNumber = 403; kMldFieldNumber = 404; kTextProtocolFieldNumber = 500; } } message Stream { required StreamId stream_id = 1; optional StreamCore core = 2; optional StreamControl control = 3; repeated Protocol protocol = 4; } message Void { // nothing! } message Ack { //! \todo (LOW) do we need any fields in 'Ack' } message PortId { required uint32 id = 1; } message PortIdList { repeated PortId port_id = 1; } message StreamIdList { required PortId port_id = 1; repeated StreamId stream_id = 2; } enum TransmitMode { kSequentialTransmit = 0; kInterleavedTransmit = 1; } message Port { required PortId port_id = 1; optional string name = 2; optional string description = 3; optional string notes = 4; optional bool is_enabled = 5; optional bool is_exclusive_control = 6; optional TransmitMode transmit_mode = 7 [default = kSequentialTransmit]; } message PortConfigList { repeated Port port = 1; } message StreamConfigList { required PortId port_id = 1; repeated Stream stream = 2; } message CaptureBuffer { //! \todo (HIGH) define CaptureBuffer } message CaptureBufferList { repeated CaptureBuffer list = 1; } enum LinkState { LinkStateUnknown = 0; LinkStateDown = 1; LinkStateUp = 2; } message PortState { optional LinkState link_state = 1 [default = LinkStateUnknown]; optional bool is_transmit_on = 2 [default = false]; optional bool is_capture_on = 3 [default = false]; } message PortStats { required PortId port_id = 1; optional PortState state = 2; optional uint64 rx_pkts = 11; optional uint64 rx_bytes = 12; optional uint64 rx_pkts_nic = 13; optional uint64 rx_bytes_nic = 14; optional uint64 rx_pps = 15; optional uint64 rx_bps = 16; optional uint64 tx_pkts = 21; optional uint64 tx_bytes = 22; optional uint64 tx_pkts_nic = 23; optional uint64 tx_bytes_nic = 24; optional uint64 tx_pps = 25; optional uint64 tx_bps = 26; optional uint64 rx_drops = 100; optional uint64 rx_errors = 101; optional uint64 rx_fifo_errors = 102; optional uint64 rx_frame_errors = 103; } message PortStatsList { repeated PortStats port_stats = 1; } service OstService { rpc getPortIdList(Void) returns (PortIdList); rpc getPortConfig(PortIdList) returns (PortConfigList); rpc modifyPort(PortConfigList) returns (Ack); rpc getStreamIdList(PortId) returns (StreamIdList); rpc getStreamConfig(StreamIdList) returns (StreamConfigList); rpc addStream(StreamIdList) returns (Ack); rpc deleteStream(StreamIdList) returns (Ack); rpc modifyStream(StreamConfigList) returns (Ack); rpc startTx(PortIdList) returns (Ack); rpc stopTx(PortIdList) returns (Ack); rpc startCapture(PortIdList) returns (Ack); rpc stopCapture(PortIdList) returns (Ack); rpc getCaptureBuffer(PortId) returns (CaptureBuffer); rpc getStats(PortIdList) returns (PortStatsList); rpc clearStats(PortIdList) returns (Ack); } ostinato-0.5.1/common/protocollist.cpp0000700000175300010010000000146112005505614017423 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "protocollist.h" #include "abstractprotocol.h" void ProtocolList::destroy() { while (!isEmpty()) delete takeFirst(); } ostinato-0.5.1/common/protocollist.h0000700000175300010010000000145712005505614017075 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include class AbstractProtocol; class ProtocolList : public QLinkedList { public: void destroy(); }; ostinato-0.5.1/common/protocollistiterator.cpp0000700000175300010010000000604412005505614021177 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "protocollistiterator.h" #include "protocollist.h" #include "abstractprotocol.h" ProtocolListIterator::ProtocolListIterator(ProtocolList &list) { _iter = new QMutableLinkedListIterator(list); } ProtocolListIterator::~ProtocolListIterator() { delete _iter; } bool ProtocolListIterator::findNext(const AbstractProtocol* value) const { return _iter->findNext(const_cast(value)); } bool ProtocolListIterator::findPrevious(const AbstractProtocol* value) { return _iter->findPrevious(const_cast(value)); } bool ProtocolListIterator::hasNext() const { return _iter->hasNext(); } bool ProtocolListIterator::hasPrevious() const { return _iter->hasPrevious(); } void ProtocolListIterator::insert(AbstractProtocol* value) { if (_iter->hasPrevious()) { value->prev = _iter->peekPrevious(); value->prev->next = value; } else value->prev = NULL; if (_iter->hasNext()) { value->next = _iter->peekNext(); value->next->prev = value; } else value->next = NULL; _iter->insert(const_cast(value)); } AbstractProtocol* ProtocolListIterator::next() { return _iter->next(); } AbstractProtocol* ProtocolListIterator::peekNext() const { return _iter->peekNext(); } AbstractProtocol* ProtocolListIterator::peekPrevious() const { return _iter->peekPrevious(); } AbstractProtocol* ProtocolListIterator::previous() { return _iter->previous(); } void ProtocolListIterator::remove() { if (_iter->value()->prev) _iter->value()->prev->next = _iter->value()->next; if (_iter->value()->next) _iter->value()->next->prev = _iter->value()->prev; _iter->remove(); } void ProtocolListIterator::setValue(AbstractProtocol* value) const { if (_iter->value()->prev) _iter->value()->prev->next = value; if (_iter->value()->next) _iter->value()->next->prev = value; value->prev = _iter->value()->prev; value->next = _iter->value()->next; _iter->setValue(const_cast(value)); } void ProtocolListIterator::toBack() { _iter->toBack(); } void ProtocolListIterator::toFront() { _iter->toFront(); } const AbstractProtocol* ProtocolListIterator::value() const { return _iter->value(); } AbstractProtocol* ProtocolListIterator::value() { return _iter->value(); } ostinato-0.5.1/common/protocollistiterator.h0000700000175300010010000000271012005505614020640 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include class AbstractProtocol; class ProtocolList; class ProtocolListIterator { private: QMutableLinkedListIterator *_iter; public: ProtocolListIterator(ProtocolList &list); ~ProtocolListIterator(); bool findNext(const AbstractProtocol* value) const; bool findPrevious(const AbstractProtocol* value); bool hasNext() const; bool hasPrevious() const; void insert(AbstractProtocol* value); AbstractProtocol* next(); AbstractProtocol* peekNext() const; AbstractProtocol* peekPrevious() const; AbstractProtocol* previous(); void remove(); void setValue(AbstractProtocol* value) const; void toBack(); void toFront(); const AbstractProtocol* value() const; AbstractProtocol* value(); }; ostinato-0.5.1/common/protocolmanager.cpp0000700000175300010010000001554012005505614020065 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "protocolmanager.h" #include "abstractprotocol.h" #include "protocol.pb.h" #include "mac.h" #include "payload.h" #include "eth2.h" #include "dot3.h" #include "llc.h" #include "snap.h" #include "dot2llc.h" #include "dot2snap.h" #include "vlan.h" #include "vlanstack.h" #include "arp.h" #include "ip4.h" #include "ip6.h" #include "ip6over4.h" #include "ip4over6.h" #include "ip4over4.h" #include "ip6over6.h" #include "icmp.h" #include "igmp.h" #include "mld.h" #include "tcp.h" #include "udp.h" #include "textproto.h" #include "userscript.h" #include "hexdump.h" #include "sample.h" ProtocolManager *OstProtocolManager; ProtocolManager::ProtocolManager() { /*! \todo (LOW) calls to registerProtocol() should be done by the protocols themselves (once this is done remove the #includes for all the protocols) */ registerProtocol(OstProto::Protocol::kMacFieldNumber, (void*) MacProtocol::createInstance); registerProtocol(OstProto::Protocol::kEth2FieldNumber, (void*) Eth2Protocol::createInstance); registerProtocol(OstProto::Protocol::kDot3FieldNumber, (void*) Dot3Protocol::createInstance); registerProtocol(OstProto::Protocol::kLlcFieldNumber, (void*) LlcProtocol::createInstance); registerProtocol(OstProto::Protocol::kSnapFieldNumber, (void*) SnapProtocol::createInstance); registerProtocol(OstProto::Protocol::kDot2LlcFieldNumber, (void*) Dot2LlcProtocol::createInstance); registerProtocol(OstProto::Protocol::kDot2SnapFieldNumber, (void*) Dot2SnapProtocol::createInstance); registerProtocol(OstProto::Protocol::kSvlanFieldNumber, (void*) SVlanProtocol::createInstance); registerProtocol(OstProto::Protocol::kVlanFieldNumber, (void*) VlanProtocol::createInstance); registerProtocol(OstProto::Protocol::kVlanStackFieldNumber, (void*) VlanStackProtocol::createInstance); registerProtocol(OstProto::Protocol::kArpFieldNumber, (void*) ArpProtocol::createInstance); registerProtocol(OstProto::Protocol::kIp4FieldNumber, (void*) Ip4Protocol::createInstance); registerProtocol(OstProto::Protocol::kIp6FieldNumber, (void*) Ip6Protocol::createInstance); registerProtocol(OstProto::Protocol::kIp6over4FieldNumber, (void*) Ip6over4Protocol::createInstance); registerProtocol(OstProto::Protocol::kIp4over6FieldNumber, (void*) Ip4over6Protocol::createInstance); registerProtocol(OstProto::Protocol::kIp4over4FieldNumber, (void*) Ip4over4Protocol::createInstance); registerProtocol(OstProto::Protocol::kIp6over6FieldNumber, (void*) Ip6over6Protocol::createInstance); registerProtocol(OstProto::Protocol::kIcmpFieldNumber, (void*) IcmpProtocol::createInstance); registerProtocol(OstProto::Protocol::kIgmpFieldNumber, (void*) IgmpProtocol::createInstance); registerProtocol(OstProto::Protocol::kMldFieldNumber, (void*) MldProtocol::createInstance); registerProtocol(OstProto::Protocol::kTcpFieldNumber, (void*) TcpProtocol::createInstance); registerProtocol(OstProto::Protocol::kUdpFieldNumber, (void*) UdpProtocol::createInstance); registerProtocol(OstProto::Protocol::kTextProtocolFieldNumber, (void*) TextProtocol::createInstance); registerProtocol(OstProto::Protocol::kHexDumpFieldNumber, (void*) HexDumpProtocol::createInstance); registerProtocol(OstProto::Protocol::kPayloadFieldNumber, (void*) PayloadProtocol::createInstance); registerProtocol(OstProto::Protocol::kUserScriptFieldNumber, (void*) UserScriptProtocol::createInstance); registerProtocol(OstProto::Protocol::kSampleFieldNumber, (void*) SampleProtocol::createInstance); populateNeighbourProtocols(); } ProtocolManager::~ProtocolManager() { numberToNameMap.clear(); nameToNumberMap.clear(); neighbourProtocols.clear(); factory.clear(); QList pl = protocolList.values(); while (!pl.isEmpty()) delete pl.takeFirst(); } void ProtocolManager::registerProtocol(int protoNumber, void *protoInstanceCreator) { AbstractProtocol *p; Q_ASSERT(!factory.contains(protoNumber)); factory.insert(protoNumber, protoInstanceCreator); p = createProtocol(protoNumber, NULL); protocolList.insert(protoNumber, p); numberToNameMap.insert(protoNumber, p->shortName()); nameToNumberMap.insert(p->shortName(), protoNumber); } void ProtocolManager::populateNeighbourProtocols() { neighbourProtocols.clear(); foreach(AbstractProtocol *p, protocolList) { if (p->protocolIdType() != AbstractProtocol::ProtocolIdNone) { foreach(AbstractProtocol *q, protocolList) { if (q->protocolId(p->protocolIdType())) neighbourProtocols.insert( p->protocolNumber(), q->protocolNumber()); } } } } bool ProtocolManager::isRegisteredProtocol(int protoNumber) { return factory.contains(protoNumber); } AbstractProtocol* ProtocolManager::createProtocol(int protoNumber, StreamBase *stream, AbstractProtocol *parent) { AbstractProtocol* (*pc)(StreamBase*, AbstractProtocol*); AbstractProtocol* p; pc = (AbstractProtocol* (*)(StreamBase*, AbstractProtocol*)) factory.value(protoNumber); Q_ASSERT(pc != NULL); p = (*pc)(stream, parent); return p; } AbstractProtocol* ProtocolManager::createProtocol(QString protoName, StreamBase *stream, AbstractProtocol *parent) { return createProtocol(nameToNumberMap.value(protoName), stream, parent); } bool ProtocolManager::isValidNeighbour(int protoPrefix, int protoSuffix) { if (neighbourProtocols.contains(protoPrefix, protoSuffix)) return true; else return false; } bool ProtocolManager::protocolHasPayload(int protoNumber) { Q_ASSERT(protocolList.contains(protoNumber)); return protocolList.value(protoNumber)->protocolHasPayload(); } QStringList ProtocolManager::protocolDatabase() { return numberToNameMap.values(); } ostinato-0.5.1/common/protocolmanager.h0000700000175300010010000000316512005505614017532 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PROTOCOL_MANAGER_H #define _PROTOCOL_MANAGER_H #include #include class AbstractProtocol; class StreamBase; class ProtocolManager { QMap numberToNameMap; QMap nameToNumberMap; QMultiMap neighbourProtocols; QMap factory; QMap protocolList; void populateNeighbourProtocols(); public: ProtocolManager(); ~ProtocolManager(); void registerProtocol(int protoNumber, void *protoInstanceCreator); bool isRegisteredProtocol(int protoNumber); AbstractProtocol* createProtocol(int protoNumber, StreamBase *stream, AbstractProtocol *parent = 0); AbstractProtocol* createProtocol(QString protoName, StreamBase *stream, AbstractProtocol *parent = 0); bool isValidNeighbour(int protoPrefix, int protoSuffix); bool protocolHasPayload(int protoNumber); QStringList protocolDatabase(); }; #endif ostinato-0.5.1/common/sample.cpp0000700000175300010010000003545512005505614016161 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "sample.h" SampleConfigForm::SampleConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } SampleProtocol::SampleProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { /* The configWidget is created lazily */ configForm = NULL; } SampleProtocol::~SampleProtocol() { delete configForm; } AbstractProtocol* SampleProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new SampleProtocol(stream, parent); } quint32 SampleProtocol::protocolNumber() const { return OstProto::Protocol::kSampleFieldNumber; } void SampleProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::sample)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void SampleProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::sample)) data.MergeFrom(protocol.GetExtension(OstProto::sample)); } QString SampleProtocol::name() const { return QString("Sample Protocol"); } QString SampleProtocol::shortName() const { return QString("SAMPLE"); } /*! TODO Return the ProtocolIdType for your protocol \n If your protocol doesn't have a protocolId field, you don't need to reimplement this method - the base class implementation will do the right thing */ AbstractProtocol::ProtocolIdType SampleProtocol::protocolIdType() const { return ProtocolIdIp; } /*! TODO Return the protocolId for your protoocol based on the 'type' requested \n If not all types are valid for your protocol, handle the valid type(s) and for the remaining fallback to the base class implementation; if your protocol doesn't have a protocolId at all, you don't need to reimplement this method - the base class will do the right thing */ quint32 SampleProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: return 1234; default:break; } return AbstractProtocol::protocolId(type); } int SampleProtocol::fieldCount() const { return sample_fieldCount; } /*! TODO Return the number of frame fields for your protocol. A frame field is a field which has the FrameField flag set \n If your protocol has different sets of fields based on a OpCode/Type field (e.g. icmp), you MUST re-implement this function; however, if your protocol has a fixed set of frame fields always, you don't need to reimplement this method - the base class implementation will do the right thing */ int SampleProtocol::frameFieldCount() const { return 0; } /*! TODO Edit this function to return the appropriate flags for each field \n See AbstractProtocol::FieldFlags for more info */ AbstractProtocol::FieldFlags SampleProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case sample_a: case sample_b: case sample_payloadLength: break; case sample_checksum: flags |= CksumField; break; case sample_x: case sample_y: break; case sample_is_override_checksum: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } /*! TODO: Edit this function to return the data for each field See AbstractProtocol::fieldData() for more info */ QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case sample_a: { int a = data.ab() >> 13; switch(attrib) { case FieldName: return QString("A"); case FieldValue: return a; case FieldTextValue: return QString("%1").arg(a); case FieldFrameValue: return QByteArray(1, (char) a); case FieldBitSize: return 3; default: break; } break; } case sample_b: { int b = data.ab() & 0x1FFF; switch(attrib) { case FieldName: return QString("B"); case FieldValue: return b; case FieldTextValue: return QString("%1").arg(b, 4, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) b, (uchar*) fv.data()); return fv; } case FieldBitSize: return 13; default: break; } break; } case sample_payloadLength: { switch(attrib) { case FieldName: return QString("Payload Length"); case FieldValue: return protocolFramePayloadSize(streamIndex); case FieldFrameValue: { QByteArray fv; int totlen; totlen = protocolFramePayloadSize(streamIndex); fv.resize(2); qToBigEndian((quint16) totlen, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("%1").arg( protocolFramePayloadSize(streamIndex)); case FieldBitSize: return 16; default: break; } break; } case sample_checksum: { quint16 cksum; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_checksum()) cksum = data.checksum(); else cksum = protocolFrameCksum(streamIndex, CksumIp); break; default: cksum = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Checksum"); case FieldValue: return cksum; case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(cksum, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("0x%1").arg( cksum, 4, BASE_HEX, QChar('0'));; case FieldBitSize: return 16; default: break; } break; } case sample_x: { switch(attrib) { case FieldName: return QString("X"); case FieldValue: return data.x(); case FieldTextValue: // Use the following line for display in decimal return QString("%1").arg(data.x()); // Use the following line for display in hexa-decimal //return QString("%1").arg(data.x(), 8, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) data.x(), (uchar*) fv.data()); return fv; } default: break; } break; } case sample_y: { switch(attrib) { case FieldName: return QString("Y"); case FieldValue: return data.y(); case FieldTextValue: // Use the following line for display in decimal //return QString("%1").arg(data.y()); // Use the following line for display in hexa-decimal return QString("%1").arg(data.y(), 4, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.y(), (uchar*) fv.data()); return fv; } default: break; } break; } // Meta fields case sample_is_override_checksum: { switch(attrib) { case FieldValue: return data.is_override_checksum(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } /*! TODO: Edit this function to set the data for each field See AbstractProtocol::setFieldData() for more info */ bool SampleProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case sample_a: { uint a = value.toUInt(&isOk); if (isOk) data.set_ab((data.ab() & 0xe000) | (a << 13)); break; } case sample_b: { uint b = value.toUInt(&isOk); if (isOk) data.set_ab((data.ab() & 0x1FFF) | b); break; } case sample_payloadLength: { uint len = value.toUInt(&isOk); if (isOk) data.set_payload_length(len); break; } case sample_checksum: { uint csum = value.toUInt(&isOk); if (isOk) data.set_checksum(csum); break; } case sample_x: { uint x = value.toUInt(&isOk); if (isOk) data.set_x(x); break; } case sample_y: { uint y = value.toUInt(&isOk); if (isOk) data.set_y(y); break; } case sample_is_override_checksum: { bool ovr = value.toBool(); data.set_is_override_checksum(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } /*! TODO: Return the protocol frame size in bytes\n If your protocol has a fixed size - you don't need to reimplement this; the base class implementation is good enough */ int SampleProtocol::protocolFrameSize(int streamIndex) const { return AbstractProtocol::protocolFrameSize(streamIndex); } /*! TODO: If your protocol has any variable fields, return true \n Otherwise you don't need to reimplement this method - the base class always returns false */ bool SampleProtocol::isProtocolFrameValueVariable() const { return false; } /*! TODO: If your protocol frame size can vary across pkts of the same stream, return true \n Otherwise you don't need to reimplement this method - the base class always returns false */ bool SampleProtocol::isProtocolFrameSizeVariable() const { return false; } /*! TODO: If your protocol frame has any variable fields or has a variable size, return the minimum number of frames required to vary the fields \n Otherwise you don't need to reimplement this method - the base class always returns 1 */ int SampleProtocol::protocolFrameVariableCount() const { return 1; } QWidget* SampleProtocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new SampleConfigForm; loadConfigWidget(); } return configForm; } /*! TODO: Edit this function to load each field's data into the config Widget See AbstractProtocol::loadConfigWidget() for more info */ void SampleProtocol::loadConfigWidget() { configWidget(); configForm->sampleA->setText(fieldData(sample_a, FieldValue).toString()); configForm->sampleB->setText(fieldData(sample_b, FieldValue).toString()); configForm->samplePayloadLength->setText( fieldData(sample_payloadLength, FieldValue).toString()); configForm->isChecksumOverride->setChecked( fieldData(sample_is_override_checksum, FieldValue).toBool()); configForm->sampleChecksum->setText(uintToHexStr( fieldData(sample_checksum, FieldValue).toUInt(), 2)); configForm->sampleX->setText(fieldData(sample_x, FieldValue).toString()); configForm->sampleY->setText(fieldData(sample_y, FieldValue).toString()); } /*! TODO: Edit this function to store each field's data from the config Widget See AbstractProtocol::storeConfigWidget() for more info */ void SampleProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(sample_a, configForm->sampleA->text()); setFieldData(sample_b, configForm->sampleB->text()); setFieldData(sample_payloadLength, configForm->samplePayloadLength->text()); setFieldData(sample_is_override_checksum, configForm->isChecksumOverride->isChecked()); setFieldData(sample_checksum, configForm->sampleChecksum->text().toUInt(&isOk, BASE_HEX)); setFieldData(sample_x, configForm->sampleX->text()); setFieldData(sample_y, configForm->sampleY->text()); } ostinato-0.5.1/common/sample.h0000700000175300010010000000554212005505614015620 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SAMPLE_H #define _SAMPLE_H #include "sample.pb.h" #include "ui_sample.h" #include "abstractprotocol.h" /* Sample Protocol Frame Format - +-----+------+------+------+------+------+ | A | B | LEN | CSUM | X | Y | | (3) | (13) | (16) | (16) | (32) | (32) | +-----+------+------+------+------+------+ Figures in brackets represent field width in bits */ class SampleConfigForm : public QWidget, public Ui::Sample { Q_OBJECT public: SampleConfigForm(QWidget *parent = 0); private slots: }; class SampleProtocol : public AbstractProtocol { private: OstProto::Sample data; SampleConfigForm *configForm; enum samplefield { // Frame Fields sample_a = 0, sample_b, sample_payloadLength, sample_checksum, sample_x, sample_y, // Meta Fields sample_is_override_checksum, sample_fieldCount }; public: SampleProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~SampleProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual int frameFieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual int protocolFrameSize(int streamIndex = 0) const; virtual bool isProtocolFrameValueVariable() const; virtual bool isProtocolFrameSizeVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/sample.proto0000700000175300010010000000203212005505614016523 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Sample Protocol message Sample { optional bool is_override_checksum = 1; optional uint32 ab = 2; optional uint32 payload_length = 3; optional uint32 checksum = 4; optional uint32 x = 5 [default = 1234]; optional uint32 y = 6; } extend Protocol { optional Sample sample = 102; } ostinato-0.5.1/common/sample.ui0000700000175300010010000001136612005505614016007 0ustar srivatspNone Sample 0 0 263 116 Form Field A Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sampleA >HH; Checksum false >HH HH; Field B Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sampleB >HH HH; Field X Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sampleX Qt::Horizontal 40 20 Length Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter samplePayloadLength false Field Y Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter sampleY Qt::Vertical 20 40 sampleA sampleB samplePayloadLength isChecksumOverride sampleChecksum sampleX sampleY isChecksumOverride toggled(bool) sampleChecksum setEnabled(bool) 345 122 406 122 ostinato-0.5.1/common/snap.cpp0000700000175300010010000001742612005505614015637 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "snap.h" quint32 kStdOui = 0x000000; SnapConfigForm::SnapConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } SnapProtocol::SnapProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } SnapProtocol::~SnapProtocol() { delete configForm; } AbstractProtocol* SnapProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new SnapProtocol(stream, parent); } quint32 SnapProtocol::protocolNumber() const { return OstProto::Protocol::kSnapFieldNumber; } void SnapProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::snap)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void SnapProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::snap)) data.MergeFrom(protocol.GetExtension(OstProto::snap)); } QString SnapProtocol::name() const { return QString("SubNetwork Access Protocol"); } QString SnapProtocol::shortName() const { return QString("SNAP"); } AbstractProtocol::ProtocolIdType SnapProtocol::protocolIdType() const { return ProtocolIdEth; } quint32 SnapProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdLlc: return 0xAAAA03; default: break; } return AbstractProtocol::protocolId(type); } int SnapProtocol::fieldCount() const { return snap_fieldCount; } AbstractProtocol::FieldFlags SnapProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case snap_oui: case snap_type: break; case snap_is_override_oui: case snap_is_override_type: flags &= ~FrameField; flags |= MetaField; break; default: break; } return flags; } QVariant SnapProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case snap_oui: switch(attrib) { case FieldName: return QString("OUI"); case FieldValue: { quint32 oui = data.is_override_oui() ? data.oui() : kStdOui; return oui; } case FieldTextValue: { quint32 oui = data.is_override_oui() ? data.oui() : kStdOui; return QString("%1").arg(oui, 6, BASE_HEX, QChar('0')); } case FieldFrameValue: { quint32 oui = data.is_override_oui() ? data.oui() : kStdOui; QByteArray fv; fv.resize(4); qToBigEndian(oui, (uchar*) fv.data()); fv.remove(0, 1); return fv; } default: break; } break; case snap_type: { quint16 type; switch(attrib) { case FieldName: return QString("Type"); case FieldValue: type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); return type; case FieldTextValue: type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); return QString("%1").arg(type, 4, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(2); type = data.is_override_type() ? data.type() : payloadProtocolId(ProtocolIdEth); qToBigEndian(type, (uchar*) fv.data()); return fv; } default: break; } break; } // Meta fields case snap_is_override_oui: { switch(attrib) { case FieldValue: return data.is_override_oui(); default: break; } break; } case snap_is_override_type: { switch(attrib) { case FieldValue: return data.is_override_type(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool SnapProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) return false; switch (index) { case snap_oui: { uint oui = value.toUInt(&isOk); if (isOk) data.set_oui(oui); break; } case snap_type: { uint type = value.toUInt(&isOk); if (isOk) data.set_type(type); break; } case snap_is_override_oui: { bool ovr = value.toBool(); data.set_is_override_oui(ovr); isOk = true; break; } case snap_is_override_type: { bool ovr = value.toBool(); data.set_is_override_type(ovr); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return isOk; } QWidget* SnapProtocol::configWidget() { if (configForm == NULL) { configForm = new SnapConfigForm; loadConfigWidget(); } return configForm; } void SnapProtocol::loadConfigWidget() { configWidget(); configForm->cbOverrideOui->setChecked( fieldData(snap_is_override_oui, FieldValue).toBool()); configForm->leOui->setText(uintToHexStr( fieldData(snap_oui, FieldValue).toUInt(), 3)); configForm->cbOverrideType->setChecked( fieldData(snap_is_override_type, FieldValue).toBool()); configForm->leType->setText(uintToHexStr( fieldData(snap_type, FieldValue).toUInt(), 2)); } void SnapProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(snap_is_override_oui, configForm->cbOverrideOui->isChecked()); setFieldData(snap_oui, configForm->leOui->text().remove(QChar(' ')) .toUInt(&isOk, BASE_HEX)); setFieldData(snap_is_override_type, configForm->cbOverrideType->isChecked()); setFieldData(snap_type, configForm->leType->text().remove(QChar(' ')) .toUInt(&isOk, BASE_HEX)); } ostinato-0.5.1/common/snap.h0000700000175300010010000000427612005505614015303 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SNAP_H #define _SNAP_H #include "abstractprotocol.h" #include "snap.pb.h" #include "ui_snap.h" class SnapConfigForm : public QWidget, public Ui::snap { Q_OBJECT public: SnapConfigForm(QWidget *parent = 0); }; class SnapProtocol : public AbstractProtocol { private: OstProto::Snap data; SnapConfigForm *configForm; enum snapfield { snap_oui = 0, snap_type, // Meta fields snap_is_override_oui, snap_is_override_type, snap_fieldCount }; public: SnapProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~SnapProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/snap.proto0000700000175300010010000000163612005505614016214 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; message Snap { optional bool is_override_oui = 3; optional bool is_override_type = 4; optional uint32 oui = 1; optional uint32 type = 2; } extend Protocol { optional Snap snap = 203; } ostinato-0.5.1/common/snap.ui0000700000175300010010000000532212005505614015462 0ustar srivatspNone snap 0 0 268 98 Form SNAP OUI false >HH HH HH; Type false >HH HH; Qt::Horizontal 40 20 Qt::Vertical 20 40 cbOverrideOui toggled(bool) leOui setEnabled(bool) 49 42 68 43 cbOverrideType toggled(bool) leType setEnabled(bool) 161 34 183 33 ostinato-0.5.1/common/streambase.cpp0000700000175300010010000003152612005505614017021 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "streambase.h" #include "abstractprotocol.h" #include "protocollist.h" #include "protocollistiterator.h" #include "protocolmanager.h" extern ProtocolManager *OstProtocolManager; StreamBase::StreamBase() : mStreamId(new OstProto::StreamId), mCore(new OstProto::StreamCore), mControl(new OstProto::StreamControl) { AbstractProtocol *proto; ProtocolListIterator *iter; mStreamId->set_id(0xFFFFFFFF); currentFrameProtocols = new ProtocolList; iter = createProtocolListIterator(); // By default newly created streams have the mac and payload protocols proto = OstProtocolManager->createProtocol( OstProto::Protocol::kMacFieldNumber, this); iter->insert(proto); qDebug("stream: mac = %p", proto); proto = OstProtocolManager->createProtocol( OstProto::Protocol::kPayloadFieldNumber, this); iter->insert(proto); qDebug("stream: payload = %p", proto); { iter->toFront(); while (iter->hasNext()) { qDebug("{{%p}}", iter->next()); // qDebug("{{%p}: %d}", iter->peekNext(), iter->next()->protocolNumber()); } iter->toFront(); while (iter->hasNext()) { qDebug("{[%d]}", iter->next()->protocolNumber()); // qDebug("{{%p}: %d}", iter->peekNext(), iter->next()->protocolNumber()); } } delete iter; } StreamBase::~StreamBase() { currentFrameProtocols->destroy(); delete currentFrameProtocols; delete mControl; delete mCore; delete mStreamId; } void StreamBase::protoDataCopyFrom(const OstProto::Stream &stream) { AbstractProtocol *proto; ProtocolListIterator *iter; mStreamId->CopyFrom(stream.stream_id()); mCore->CopyFrom(stream.core()); mControl->CopyFrom(stream.control()); currentFrameProtocols->destroy(); iter = createProtocolListIterator(); for (int i=0; i < stream.protocol_size(); i++) { int protoId = stream.protocol(i).protocol_id().id(); if (!OstProtocolManager->isRegisteredProtocol(protoId)) { qWarning("Skipping unregistered protocol %d", protoId); continue; } proto = OstProtocolManager->createProtocol(protoId, this); proto->protoDataCopyFrom(stream.protocol(i)); iter->insert(proto); } delete iter; } void StreamBase::protoDataCopyInto(OstProto::Stream &stream) const { stream.mutable_stream_id()->CopyFrom(*mStreamId); stream.mutable_core()->CopyFrom(*mCore); stream.mutable_control()->CopyFrom(*mControl); stream.clear_protocol(); foreach (const AbstractProtocol* proto, *currentFrameProtocols) { OstProto::Protocol *p; p = stream.add_protocol(); proto->protoDataCopyInto(*p); } } #if 0 ProtocolList StreamBase::frameProtocol() { return currentFrameProtocols; } void StreamBase::setFrameProtocol(ProtocolList protocolList) { //currentFrameProtocols.destroy(); currentFrameProtocols = protocolList; } #endif ProtocolListIterator* StreamBase::createProtocolListIterator() const { return new ProtocolListIterator(*currentFrameProtocols); } quint32 StreamBase::id() { return mStreamId->id(); } bool StreamBase::setId(quint32 id) { mStreamId->set_id(id); return true; } quint32 StreamBase::ordinal() { return mCore->ordinal(); } bool StreamBase::setOrdinal(quint32 ordinal) { mCore->set_ordinal(ordinal); return true; } bool StreamBase::isEnabled() const { return mCore->is_enabled(); } bool StreamBase::setEnabled(bool flag) { mCore->set_is_enabled(flag); return true; } const QString StreamBase::name() const { return QString().fromStdString(mCore->name()); } bool StreamBase::setName(QString name) { mCore->set_name(name.toStdString()); return true; } StreamBase::FrameLengthMode StreamBase::lenMode() const { return (StreamBase::FrameLengthMode) mCore->len_mode(); } bool StreamBase::setLenMode(FrameLengthMode lenMode) { mCore->set_len_mode((OstProto::StreamCore::FrameLengthMode) lenMode); return true; } quint16 StreamBase::frameLen(int streamIndex) const { int pktLen; // Decide a frame length based on length mode switch(lenMode()) { case OstProto::StreamCore::e_fl_fixed: pktLen = mCore->frame_len(); break; case OstProto::StreamCore::e_fl_inc: pktLen = frameLenMin() + (streamIndex % (frameLenMax() - frameLenMin() + 1)); break; case OstProto::StreamCore::e_fl_dec: pktLen = frameLenMax() - (streamIndex % (frameLenMax() - frameLenMin() + 1)); break; case OstProto::StreamCore::e_fl_random: //! \todo (MED) This 'random' sequence is same across iterations pktLen = 64; // to avoid the 'maybe used uninitialized' warning qsrand(reinterpret_cast(this)); for (int i = 0; i <= streamIndex; i++) pktLen = qrand(); pktLen = frameLenMin() + (pktLen % (frameLenMax() - frameLenMin() + 1)); break; default: qWarning("Unhandled len mode %d. Using default 64", lenMode()); pktLen = 64; break; } return pktLen; } bool StreamBase::setFrameLen(quint16 frameLen) { mCore->set_frame_len(frameLen); return true; } quint16 StreamBase::frameLenMin() const { return mCore->frame_len_min(); } bool StreamBase::setFrameLenMin(quint16 frameLenMin) { mCore->set_frame_len_min(frameLenMin); return true; } quint16 StreamBase::frameLenMax() const { return mCore->frame_len_max(); } bool StreamBase::setFrameLenMax(quint16 frameLenMax) { mCore->set_frame_len_max(frameLenMax); return true; } /*! Convenience Function */ quint16 StreamBase::frameLenAvg() const { quint16 avgFrameLen; if (lenMode() == e_fl_fixed) avgFrameLen = frameLen(); else avgFrameLen = (frameLenMin() + frameLenMax())/2; return avgFrameLen; } StreamBase::SendUnit StreamBase::sendUnit() const { return (StreamBase::SendUnit) mControl->unit(); } bool StreamBase::setSendUnit(SendUnit sendUnit) { mControl->set_unit((OstProto::StreamControl::SendUnit) sendUnit); return true; } StreamBase::SendMode StreamBase::sendMode() const { return (StreamBase::SendMode) mControl->mode(); } bool StreamBase::setSendMode(SendMode sendMode) { mControl->set_mode( (OstProto::StreamControl::SendMode) sendMode); return true; } StreamBase::NextWhat StreamBase::nextWhat() const { return (StreamBase::NextWhat) mControl->next(); } bool StreamBase::setNextWhat(NextWhat nextWhat) { mControl->set_next((OstProto::StreamControl::NextWhat) nextWhat); return true; } quint32 StreamBase::numPackets() const { return (quint32) mControl->num_packets(); } bool StreamBase::setNumPackets(quint32 numPackets) { mControl->set_num_packets(numPackets); return true; } quint32 StreamBase::numBursts() const { return (quint32) mControl->num_bursts(); } bool StreamBase::setNumBursts(quint32 numBursts) { mControl->set_num_bursts(numBursts); return true; } quint32 StreamBase::burstSize() const { return (quint32) mControl->packets_per_burst(); } bool StreamBase::setBurstSize(quint32 packetsPerBurst) { mControl->set_packets_per_burst(packetsPerBurst); return true; } double StreamBase::packetRate() const { return (double) mControl->packets_per_sec(); } bool StreamBase::setPacketRate(double packetsPerSec) { mControl->set_packets_per_sec(packetsPerSec); return true; } double StreamBase::burstRate() const { return (double) mControl->bursts_per_sec(); } bool StreamBase::setBurstRate(double burstsPerSec) { mControl->set_bursts_per_sec(burstsPerSec); return true; } /*! Convenience Function */ double StreamBase::averagePacketRate() const { double avgPacketRate; switch (sendUnit()) { case e_su_bursts: avgPacketRate = burstRate() * burstSize(); break; case e_su_packets: avgPacketRate = packetRate(); break; default: Q_ASSERT(false); // Unreachable!! } return avgPacketRate; } /*! Convenience Function */ bool StreamBase::setAveragePacketRate(double packetsPerSec) { switch (sendUnit()) { case e_su_bursts: setBurstRate(packetsPerSec/double(burstSize())); break; case e_su_packets: setPacketRate(packetsPerSec); break; default: Q_ASSERT(false); // Unreachable!! } return true; } bool StreamBase::isFrameVariable() const { ProtocolListIterator *iter; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol *proto; proto = iter->next(); if (proto->isProtocolFrameValueVariable()) goto _exit; } delete iter; return false; _exit: delete iter; return true; } bool StreamBase::isFrameSizeVariable() const { ProtocolListIterator *iter; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol *proto; proto = iter->next(); if (proto->isProtocolFrameSizeVariable()) goto _exit; } delete iter; return false; _exit: delete iter; return true; } int StreamBase::frameVariableCount() const { ProtocolListIterator *iter; quint64 frameCount = 1; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol *proto; int count; proto = iter->next(); count = proto->protocolFrameVariableCount(); // correct count for mis-behaving protocols if (count <= 0) count = 1; frameCount = AbstractProtocol::lcm(frameCount, count); } delete iter; return frameCount; } // frameProtocolLength() returns the sum of all the individual protocol sizes // which may be different from frameLen() int StreamBase::frameProtocolLength(int frameIndex) const { int len = 0; ProtocolListIterator *iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol *proto = iter->next(); len += proto->protocolFrameSize(frameIndex); } delete iter; return len; } int StreamBase::frameCount() const { int count = 0; switch (sendUnit()) { case e_su_packets: count = numPackets(); break; case e_su_bursts: count = numBursts() * burstSize(); break; default: Q_ASSERT(false); // unreachable } return count; } int StreamBase::frameValue(uchar *buf, int bufMaxSize, int frameIndex) const { int pktLen, len = 0; pktLen = frameLen(frameIndex); // pktLen is adjusted for CRC/FCS which will be added by the NIC pktLen -= kFcsSize; if ((pktLen < 0) || (pktLen > bufMaxSize)) return 0; ProtocolListIterator *iter; iter = createProtocolListIterator(); while (iter->hasNext()) { AbstractProtocol *proto; QByteArray ba; proto = iter->next(); ba = proto->protocolFrameValue(frameIndex); if (len + ba.size() < bufMaxSize) memcpy(buf+len, ba.constData(), ba.size()); len += ba.size(); } delete iter; // Pad with zero, if required if (len < pktLen) memset(buf+len, 0, pktLen-len); return pktLen; } bool StreamBase::preflightCheck(QString &result) const { bool pass = true; int count = isFrameSizeVariable() ? frameCount() : 1; for (int i = 0; i < count; i++) { if (frameLen(i) < (frameProtocolLength(i) + kFcsSize)) { result += QString("One or more frames may be truncated - " "frame length should be at least %1.\n") .arg(frameProtocolLength(i) + kFcsSize); pass = false; } if (frameLen(i) > 1522) { result += QString("Jumbo frames may be truncated or dropped " "if not supported by the hardware\n"); pass = false; } } return pass; } bool StreamBase::StreamLessThan(StreamBase* stream1, StreamBase* stream2) { return stream1->ordinal() < stream2->ordinal() ? true : false; } ostinato-0.5.1/common/streambase.h0000700000175300010010000000711212005505614016460 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _STREAM_BASE_H #define _STREAM_BASE_H #include #include #include "protocol.pb.h" const int kFcsSize = 4; class AbstractProtocol; class ProtocolList; class ProtocolListIterator; class StreamBase { private: OstProto::StreamId *mStreamId; OstProto::StreamCore *mCore; OstProto::StreamControl *mControl; ProtocolList *currentFrameProtocols; public: StreamBase(); ~StreamBase(); void protoDataCopyFrom(const OstProto::Stream &stream); void protoDataCopyInto(OstProto::Stream &stream) const; ProtocolListIterator* createProtocolListIterator() const; //! \todo (LOW) should we have a copy constructor?? public: enum FrameLengthMode { e_fl_fixed, e_fl_inc, e_fl_dec, e_fl_random }; enum SendUnit { e_su_packets, e_su_bursts }; enum SendMode { e_sm_fixed, e_sm_continuous }; enum NextWhat { e_nw_stop, e_nw_goto_next, e_nw_goto_id }; quint32 id(); bool setId(quint32 id); #if 0 // FIXME(HI): needed? quint32 portId() { return mCore->port_id();} bool setPortId(quint32 id) { mCore->set_port_id(id); return true;} #endif quint32 ordinal(); bool setOrdinal(quint32 ordinal); bool isEnabled() const; bool setEnabled(bool flag); const QString name() const ; bool setName(QString name) ; // Frame Length (includes FCS); FrameLengthMode lenMode() const; bool setLenMode(FrameLengthMode lenMode); quint16 frameLen(int streamIndex = 0) const; bool setFrameLen(quint16 frameLen); quint16 frameLenMin() const; bool setFrameLenMin(quint16 frameLenMin); quint16 frameLenMax() const; bool setFrameLenMax(quint16 frameLenMax); quint16 frameLenAvg() const; SendUnit sendUnit() const; bool setSendUnit(SendUnit sendUnit); SendMode sendMode() const; bool setSendMode(SendMode sendMode); NextWhat nextWhat() const; bool setNextWhat(NextWhat nextWhat); quint32 numPackets() const; bool setNumPackets(quint32 numPackets); quint32 numBursts() const; bool setNumBursts(quint32 numBursts); quint32 burstSize() const; bool setBurstSize(quint32 packetsPerBurst); double packetRate() const; bool setPacketRate(double packetsPerSec); double burstRate() const; bool setBurstRate(double burstsPerSec); double averagePacketRate() const; bool setAveragePacketRate(double packetsPerSec); bool isFrameVariable() const; bool isFrameSizeVariable() const; int frameVariableCount() const; int frameProtocolLength(int frameIndex) const; int frameCount() const; int frameValue(uchar *buf, int bufMaxSize, int frameIndex) const; bool preflightCheck(QString &result) const; static bool StreamLessThan(StreamBase* stream1, StreamBase* stream2); }; #endif ostinato-0.5.1/common/svlan.cpp0000700000175300010010000000341712005505614016014 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "svlan.h" #include "svlan.pb.h" SVlanProtocol::SVlanProtocol(StreamBase *stream, AbstractProtocol *parent) : VlanProtocol(stream, parent) { data.set_tpid(0x88a8); data.set_is_override_tpid(true); } SVlanProtocol::~SVlanProtocol() { } AbstractProtocol* SVlanProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new SVlanProtocol(stream, parent); } quint32 SVlanProtocol::protocolNumber() const { return OstProto::Protocol::kSvlanFieldNumber; } void SVlanProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::svlan)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void SVlanProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::svlan)) data.MergeFrom(protocol.GetExtension(OstProto::svlan)); } QString SVlanProtocol::name() const { return QString("SVlan"); } QString SVlanProtocol::shortName() const { return QString("SVlan"); } ostinato-0.5.1/common/svlan.h0000700000175300010010000000235112005505615015456 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SVLAN_H #define _SVLAN_H #include "vlan.h" class SVlanProtocol : public VlanProtocol { public: SVlanProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~SVlanProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; }; #endif ostinato-0.5.1/common/svlan.proto0000700000175300010010000000142712005505615016375 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; import "vlan.proto"; package OstProto; extend Protocol { optional Vlan svlan = 204; } ostinato-0.5.1/common/tcp.cpp0000700000175300010010000005075612005505615015470 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "tcp.h" TcpConfigForm::TcpConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } TcpProtocol::TcpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } TcpProtocol::~TcpProtocol() { delete configForm; } AbstractProtocol* TcpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new TcpProtocol(stream, parent); } quint32 TcpProtocol::protocolNumber() const { return OstProto::Protocol::kTcpFieldNumber; } void TcpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::tcp)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void TcpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::tcp)) data.MergeFrom(protocol.GetExtension(OstProto::tcp)); } QString TcpProtocol::name() const { return QString("Transmission Control Protocol"); } QString TcpProtocol::shortName() const { return QString("TCP"); } AbstractProtocol::ProtocolIdType TcpProtocol::protocolIdType() const { return ProtocolIdTcpUdp; } quint32 TcpProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: return 0x06; default: break; } return AbstractProtocol::protocolId(type); } int TcpProtocol::fieldCount() const { return tcp_fieldCount; } AbstractProtocol::FieldFlags TcpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case tcp_src_port: case tcp_dst_port: case tcp_seq_num: case tcp_ack_num: case tcp_hdrlen: case tcp_rsvd: case tcp_flags: case tcp_window: break; case tcp_cksum: flags |= CksumField; break; case tcp_urg_ptr: break; case tcp_is_override_src_port: case tcp_is_override_dst_port: case tcp_is_override_hdrlen: case tcp_is_override_cksum: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant TcpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case tcp_src_port: { quint16 srcPort; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_src_port()) srcPort = data.src_port(); else srcPort = payloadProtocolId(ProtocolIdTcpUdp); break; default: srcPort = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Source Port"); case FieldValue: return srcPort; case FieldTextValue: return QString("%1").arg(srcPort); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(srcPort, (uchar*) fv.data()); return fv; } default: break; } break; } case tcp_dst_port: { quint16 dstPort; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_dst_port()) dstPort = data.dst_port(); else dstPort = payloadProtocolId(ProtocolIdTcpUdp); break; default: dstPort = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Destination Port"); case FieldValue: return dstPort; case FieldTextValue: return QString("%1").arg(dstPort); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(dstPort, (uchar*) fv.data()); return fv; } default: break; } break; } case tcp_seq_num: switch(attrib) { case FieldName: return QString("Sequence Number"); case FieldValue: return data.seq_num(); case FieldTextValue: return QString("%1").arg(data.seq_num()); case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) data.seq_num(), (uchar*) fv.data()); return fv; } default: break; } break; case tcp_ack_num: switch(attrib) { case FieldName: return QString("Acknowledgement Number"); case FieldValue: return data.ack_num(); case FieldTextValue: return QString("%1").arg(data.ack_num()); case FieldFrameValue: { QByteArray fv; fv.resize(4); qToBigEndian((quint32) data.ack_num(), (uchar*) fv.data()); return fv; } default: break; } break; case tcp_hdrlen: switch(attrib) { case FieldName: return QString("Header Length"); case FieldValue: if (data.is_override_hdrlen()) return ((data.hdrlen_rsvd() >> 4) & 0x0F); else return 5; case FieldTextValue: if (data.is_override_hdrlen()) return QString("%1 bytes").arg( 4 * ((data.hdrlen_rsvd() >> 4) & 0x0F)); else return QString("20 bytes"); case FieldFrameValue: if (data.is_override_hdrlen()) return QByteArray(1, (char)((data.hdrlen_rsvd() >> 4) & 0x0F)); else return QByteArray(1, (char) 0x05); case FieldBitSize: return 4; default: break; } break; case tcp_rsvd: switch(attrib) { case FieldName: return QString("Reserved"); case FieldValue: return (data.hdrlen_rsvd() & 0x0F); case FieldTextValue: return QString("%1").arg(data.hdrlen_rsvd() & 0x0F); case FieldFrameValue: return QByteArray(1, (char)(data.hdrlen_rsvd() & 0x0F)); case FieldBitSize: return 4; default: break; } break; case tcp_flags: switch(attrib) { case FieldName: return QString("Flags"); case FieldValue: return (data.flags()); case FieldTextValue: { QString s; s.append("URG: "); s.append(data.flags() & TCP_FLAG_URG ? "1" : "0"); s.append(" ACK: "); s.append(data.flags() & TCP_FLAG_ACK ? "1" : "0"); s.append(" PSH: "); s.append(data.flags() & TCP_FLAG_PSH ? "1" : "0"); s.append(" RST: "); s.append(data.flags() & TCP_FLAG_RST ? "1" : "0"); s.append(" SYN: "); s.append(data.flags() & TCP_FLAG_SYN ? "1" : "0"); s.append(" FIN: "); s.append(data.flags() & TCP_FLAG_FIN ? "1" : "0"); return s; } case FieldFrameValue: return QByteArray(1, (char)(data.flags() & 0x3F)); default: break; } break; case tcp_window: switch(attrib) { case FieldName: return QString("Window Size"); case FieldValue: return data.window(); case FieldTextValue: return QString("%1").arg(data.window()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.window(), (uchar*) fv.data()); return fv; } default: break; } break; case tcp_cksum: switch(attrib) { case FieldName: return QString("Checksum"); case FieldValue: { quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumTcpUdp); return cksum; } case FieldTextValue: { quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumTcpUdp); return QString("0x%1").arg(cksum, 4, BASE_HEX, QChar('0')); } case FieldFrameValue: { quint16 cksum; if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumTcpUdp); QByteArray fv; fv.resize(2); qToBigEndian(cksum, (uchar*) fv.data()); return fv; } case FieldBitSize: return 16; default: break; } break; case tcp_urg_ptr: switch(attrib) { case FieldName: return QString("Urgent Pointer"); case FieldValue: return data.urg_ptr(); case FieldTextValue: return QString("%1").arg(data.urg_ptr()); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) data.urg_ptr(), (uchar*) fv.data()); return fv; } default: break; } break; // Meta fields case tcp_is_override_src_port: { switch(attrib) { case FieldValue: return data.is_override_src_port(); default: break; } break; } case tcp_is_override_dst_port: { switch(attrib) { case FieldValue: return data.is_override_dst_port(); default: break; } break; } case tcp_is_override_hdrlen: { switch(attrib) { case FieldValue: return data.is_override_hdrlen(); default: break; } break; } case tcp_is_override_cksum: { switch(attrib) { case FieldValue: return data.is_override_cksum(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool TcpProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case tcp_src_port: { uint srcPort = value.toUInt(&isOk); if (isOk) data.set_src_port(srcPort); break; } case tcp_dst_port: { uint dstPort = value.toUInt(&isOk); if (isOk) data.set_dst_port(dstPort); break; } case tcp_seq_num: { uint seqNum = value.toUInt(&isOk); if (isOk) data.set_seq_num(seqNum); break; } case tcp_ack_num: { uint ackNum = value.toUInt(&isOk); if (isOk) data.set_ack_num(ackNum); break; } case tcp_hdrlen: { uint hdrLen = value.toUInt(&isOk); if (isOk) data.set_hdrlen_rsvd( (data.hdrlen_rsvd() & 0x0F) | (hdrLen << 4)); break; } case tcp_rsvd: { uint rsvd = value.toUInt(&isOk); if (isOk) data.set_hdrlen_rsvd( (data.hdrlen_rsvd() & 0xF0) | (rsvd & 0x0F)); break; } case tcp_flags: { uint flags = value.toUInt(&isOk); if (isOk) data.set_flags(flags); break; } case tcp_window: { uint window = value.toUInt(&isOk); if (isOk) data.set_window(window); break; } case tcp_cksum: { uint cksum = value.toUInt(&isOk); if (isOk) data.set_cksum(cksum); break; } case tcp_urg_ptr: { uint urgPtr = value.toUInt(&isOk); if (isOk) data.set_urg_ptr(urgPtr); break; } case tcp_is_override_src_port: { data.set_is_override_src_port(value.toBool()); isOk = true; break; } case tcp_is_override_dst_port: { data.set_is_override_dst_port(value.toBool()); isOk = true; break; } case tcp_is_override_hdrlen: { data.set_is_override_hdrlen(value.toBool()); isOk = true; break; } case tcp_is_override_cksum: { data.set_is_override_cksum(value.toBool()); isOk = true; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } bool TcpProtocol::isProtocolFrameValueVariable() const { if (data.is_override_cksum()) return false; else return isProtocolFramePayloadValueVariable(); } int TcpProtocol::protocolFrameVariableCount() const { if (data.is_override_cksum()) return 1; return protocolFramePayloadVariableCount(); } QWidget* TcpProtocol::configWidget() { if (configForm == NULL) { configForm = new TcpConfigForm; loadConfigWidget(); } return configForm; } void TcpProtocol::loadConfigWidget() { configWidget(); configForm->leTcpSrcPort->setText( fieldData(tcp_src_port, FieldValue).toString()); configForm->cbTcpSrcPortOverride->setChecked( fieldData(tcp_is_override_src_port, FieldValue).toBool()); configForm->leTcpDstPort->setText( fieldData(tcp_dst_port, FieldValue).toString()); configForm->cbTcpDstPortOverride->setChecked( fieldData(tcp_is_override_dst_port, FieldValue).toBool()); configForm->leTcpSeqNum->setText( fieldData(tcp_seq_num, FieldValue).toString()); configForm->leTcpAckNum->setText( fieldData(tcp_ack_num, FieldValue).toString()); configForm->leTcpHdrLen->setText( fieldData(tcp_hdrlen, FieldValue).toString()); configForm->cbTcpHdrLenOverride->setChecked( fieldData(tcp_is_override_hdrlen, FieldValue).toBool()); configForm->leTcpWindow->setText( fieldData(tcp_window, FieldValue).toString()); configForm->leTcpCksum->setText(QString("%1").arg( fieldData(tcp_cksum, FieldValue).toUInt(), 4, BASE_HEX, QChar('0'))); configForm->cbTcpCksumOverride->setChecked( fieldData(tcp_is_override_cksum, FieldValue).toBool()); configForm->leTcpUrgentPointer->setText( fieldData(tcp_urg_ptr, FieldValue).toString()); uint flags = fieldData(tcp_flags, FieldValue).toUInt(); configForm->cbTcpFlagsUrg->setChecked((flags & TCP_FLAG_URG) > 0); configForm->cbTcpFlagsAck->setChecked((flags & TCP_FLAG_ACK) > 0); configForm->cbTcpFlagsPsh->setChecked((flags & TCP_FLAG_PSH) > 0); configForm->cbTcpFlagsRst->setChecked((flags & TCP_FLAG_RST) > 0); configForm->cbTcpFlagsSyn->setChecked((flags & TCP_FLAG_SYN) > 0); configForm->cbTcpFlagsFin->setChecked((flags & TCP_FLAG_FIN) > 0); } void TcpProtocol::storeConfigWidget() { bool isOk; int ff = 0; configWidget(); setFieldData(tcp_src_port, configForm->leTcpSrcPort->text()); setFieldData(tcp_is_override_src_port, configForm->cbTcpSrcPortOverride->isChecked()); setFieldData(tcp_dst_port, configForm->leTcpDstPort->text()); setFieldData(tcp_is_override_dst_port, configForm->cbTcpDstPortOverride->isChecked()); setFieldData(tcp_seq_num, configForm->leTcpSeqNum->text()); setFieldData(tcp_ack_num, configForm->leTcpAckNum->text()); setFieldData(tcp_hdrlen, configForm->leTcpHdrLen->text()); setFieldData(tcp_is_override_hdrlen, configForm->cbTcpHdrLenOverride->isChecked()); setFieldData(tcp_window, configForm->leTcpWindow->text()); setFieldData(tcp_cksum, configForm->leTcpCksum->text().remove(QChar(' ')) .toUInt(&isOk, BASE_HEX)); setFieldData(tcp_is_override_cksum, configForm->cbTcpCksumOverride->isChecked()); setFieldData(tcp_urg_ptr, configForm->leTcpUrgentPointer->text()); if (configForm->cbTcpFlagsUrg->isChecked()) ff |= TCP_FLAG_URG; if (configForm->cbTcpFlagsAck->isChecked()) ff |= TCP_FLAG_ACK; if (configForm->cbTcpFlagsPsh->isChecked()) ff |= TCP_FLAG_PSH; if (configForm->cbTcpFlagsRst->isChecked()) ff |= TCP_FLAG_RST; if (configForm->cbTcpFlagsSyn->isChecked()) ff |= TCP_FLAG_SYN; if (configForm->cbTcpFlagsFin->isChecked()) ff |= TCP_FLAG_FIN; setFieldData(tcp_flags, ff); } ostinato-0.5.1/common/tcp.h0000700000175300010010000000524012005505615015121 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _TCP_H #define _TCP_H #include "abstractprotocol.h" #include "tcp.pb.h" #include "ui_tcp.h" #define TCP_FLAG_URG 0x20 #define TCP_FLAG_ACK 0x10 #define TCP_FLAG_PSH 0x08 #define TCP_FLAG_RST 0x04 #define TCP_FLAG_SYN 0x02 #define TCP_FLAG_FIN 0x01 class TcpConfigForm : public QWidget, public Ui::tcp { Q_OBJECT public: TcpConfigForm(QWidget *parent = 0); }; class TcpProtocol : public AbstractProtocol { private: OstProto::Tcp data; TcpConfigForm *configForm; enum tcpfield { tcp_src_port = 0, tcp_dst_port, tcp_seq_num, tcp_ack_num, tcp_hdrlen, tcp_rsvd, tcp_flags, tcp_window, tcp_cksum, tcp_urg_ptr, tcp_is_override_src_port, tcp_is_override_dst_port, tcp_is_override_hdrlen, tcp_is_override_cksum, tcp_fieldCount }; public: TcpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~TcpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/tcp.proto0000700000175300010010000000252512005505615016040 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Tcp message Tcp { optional bool is_override_src_port = 1; optional bool is_override_dst_port = 2; optional bool is_override_hdrlen = 3; optional bool is_override_cksum = 4; optional uint32 src_port = 5 [default = 49152]; optional uint32 dst_port = 6 [default = 49153]; optional uint32 seq_num = 7 [default = 129018]; optional uint32 ack_num = 8; optional uint32 hdrlen_rsvd = 9 [default = 0x50]; optional uint32 flags = 10; optional uint32 window = 11 [default = 1024]; optional uint32 cksum = 12; optional uint32 urg_ptr = 13; } extend Protocol { optional Tcp tcp = 400; } ostinato-0.5.1/common/tcp.ui0000700000175300010010000001521412005505615015311 0ustar srivatspNone tcp 0 0 447 194 Form Override Source Port false Qt::Vertical Override Checksum false >HH HH; Override Destination Port false Urgent Pointer Sequence Number Flags URG ACK PSH RST SYN FIN Qt::Horizontal 21 20 Acknowledgement Number Override Header Length (x4) false Window Qt::Vertical 20 40 cbTcpHdrLenOverride toggled(bool) leTcpHdrLen setEnabled(bool) 141 123 187 123 cbTcpCksumOverride toggled(bool) leTcpCksum setEnabled(bool) 316 14 384 17 cbTcpSrcPortOverride toggled(bool) leTcpSrcPort setEnabled(bool) 159 16 178 18 cbTcpDstPortOverride toggled(bool) leTcpDstPort setEnabled(bool) 147 45 180 44 ostinato-0.5.1/common/textproto.cpp0000700000175300010010000001674412005505615016751 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "textproto.h" TextProtocolConfigForm::TextProtocolConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); portNumCombo->setValidator(new QIntValidator(0, 0xFFFF, this)); portNumCombo->addItem(0, "Reserved"); portNumCombo->addItem(80, "HTTP"); portNumCombo->addItem(554, "RTSP"); portNumCombo->addItem(5060, "SIP"); } TextProtocol::TextProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { /* The configWidget is created lazily */ configForm = NULL; } TextProtocol::~TextProtocol() { delete configForm; } AbstractProtocol* TextProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new TextProtocol(stream, parent); } quint32 TextProtocol::protocolNumber() const { return OstProto::Protocol::kTextProtocolFieldNumber; } void TextProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::textProtocol)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void TextProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::textProtocol)) data.MergeFrom(protocol.GetExtension(OstProto::textProtocol)); } QString TextProtocol::name() const { return QString("Text Protocol"); } QString TextProtocol::shortName() const { return QString("TEXT"); } quint32 TextProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdTcpUdp: return data.port_num(); default:break; } return AbstractProtocol::protocolId(type); } int TextProtocol::fieldCount() const { return textProto_fieldCount; } AbstractProtocol::FieldFlags TextProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case textProto_text: break; case textProto_portNum: case textProto_eol: case textProto_encoding: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant TextProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case textProto_text: { switch(attrib) { case FieldName: return QString("Text"); case FieldValue: case FieldTextValue: return QString().fromStdString(data.text()); case FieldFrameValue: { QString text; Q_ASSERT(data.encoding() == OstProto::TextProtocol::kUtf8); text = QString().fromStdString(data.text()); if (data.eol() == OstProto::TextProtocol::kCrLf) text.replace('\n', "\r\n"); else if (data.eol() == OstProto::TextProtocol::kCr) text.replace('\n', '\r'); return text.toUtf8(); } default: break; } break; } // Meta fields case textProto_portNum: { switch(attrib) { case FieldValue: return data.port_num(); default: break; } break; } case textProto_eol: { switch(attrib) { case FieldValue: return data.eol(); default: break; } break; } case textProto_encoding: { switch(attrib) { case FieldValue: return data.encoding(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool TextProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case textProto_text: { data.set_text(value.toString().toUtf8()); isOk = true; break; } case textProto_portNum: { uint portNum = value.toUInt(&isOk); if (isOk) data.set_port_num(portNum); break; } case textProto_eol: { uint eol = value.toUInt(&isOk); if (isOk && data.EndOfLine_IsValid(eol)) data.set_eol((OstProto::TextProtocol::EndOfLine) eol); else isOk = false; break; } case textProto_encoding: { uint enc = value.toUInt(&isOk); if (isOk && data.TextEncoding_IsValid(enc)) data.set_encoding((OstProto::TextProtocol::TextEncoding) enc); else isOk = false; break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } int TextProtocol::protocolFrameSize(int streamIndex) const { return fieldData(textProto_text, FieldFrameValue, streamIndex) .toByteArray().size() ; } QWidget* TextProtocol::configWidget() { /* Lazy creation of the configWidget */ if (configForm == NULL) { configForm = new TextProtocolConfigForm; loadConfigWidget(); } return configForm; } void TextProtocol::loadConfigWidget() { configWidget(); configForm->portNumCombo->setValue( fieldData(textProto_portNum, FieldValue).toUInt()); configForm->eolCombo->setCurrentIndex( fieldData(textProto_eol, FieldValue).toUInt()); configForm->encodingCombo->setCurrentIndex( fieldData(textProto_encoding, FieldValue).toUInt()); configForm->protoText->setText( fieldData(textProto_text, FieldValue).toString()); } void TextProtocol::storeConfigWidget() { configWidget(); setFieldData(textProto_portNum, configForm->portNumCombo->currentValue()); setFieldData(textProto_eol, configForm->eolCombo->currentIndex()); setFieldData(textProto_encoding, configForm->encodingCombo->currentIndex()); setFieldData(textProto_text, configForm->protoText->toPlainText()); } ostinato-0.5.1/common/textproto.h0000700000175300010010000000472012005505615016405 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _TEXT_PROTOCOL_H #define _TEXT_PROTOCOL_H #include "textproto.pb.h" #include "ui_textproto.h" #include "abstractprotocol.h" /* TextProtocol Protocol Frame Format - specified text with the specified line ending and encoded with the specified encoding */ class TextProtocolConfigForm : public QWidget, public Ui::TextProtocol { Q_OBJECT public: TextProtocolConfigForm(QWidget *parent = 0); private slots: }; class TextProtocol : public AbstractProtocol { private: OstProto::TextProtocol data; TextProtocolConfigForm *configForm; enum textProtocolField { // Frame Fields textProto_text = 0, // Meta Fields textProto_portNum, textProto_eol, textProto_encoding, textProto_fieldCount }; public: TextProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~TextProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual int protocolFrameSize(int streamIndex = 0) const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/textproto.proto0000700000175300010010000000220712005505615017317 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Any Text based protocol message TextProtocol { enum TextEncoding { kUtf8 = 0; } enum EndOfLine { kCr = 0; kLf = 1; kCrLf = 2; } optional uint32 port_num = 1 [default = 80]; optional TextEncoding encoding = 2 [default = kUtf8]; optional string text = 3; optional EndOfLine eol = 4 [default = kLf]; } extend Protocol { optional TextProtocol textProtocol = 500; } ostinato-0.5.1/common/textproto.ui0000700000175300010010000000520312005505615016570 0ustar srivatspNone TextProtocol 0 0 535 300 Form TCP/UDP Port Number (Protocol) portNumCombo 2 0 Line Ending 2 CR LF CRLF Encode as encodingCombo 1 0 UTF-8 false IntComboBox QComboBox
intcombobox.h
ostinato-0.5.1/common/udp.cpp0000700000175300010010000003250012005505615015455 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include #include "udp.h" UdpConfigForm::UdpConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } UdpProtocol::UdpProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } UdpProtocol::~UdpProtocol() { delete configForm; } AbstractProtocol* UdpProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new UdpProtocol(stream, parent); } quint32 UdpProtocol::protocolNumber() const { return OstProto::Protocol::kUdpFieldNumber; } void UdpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::udp)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void UdpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::udp)) data.MergeFrom(protocol.GetExtension(OstProto::udp)); } QString UdpProtocol::name() const { return QString("User Datagram Protocol"); } QString UdpProtocol::shortName() const { return QString("UDP"); } AbstractProtocol::ProtocolIdType UdpProtocol::protocolIdType() const { return ProtocolIdTcpUdp; } quint32 UdpProtocol::protocolId(ProtocolIdType type) const { switch(type) { case ProtocolIdIp: return 0x11; default: break; } return AbstractProtocol::protocolId(type); } int UdpProtocol::fieldCount() const { return udp_fieldCount; } AbstractProtocol::FieldFlags UdpProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case udp_srcPort: case udp_dstPort: case udp_totLen: break; case udp_cksum: flags |= CksumField; break; case udp_isOverrideSrcPort: case udp_isOverrideDstPort: case udp_isOverrideTotLen: case udp_isOverrideCksum: flags &= ~FrameField; flags |= MetaField; break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return flags; } QVariant UdpProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case udp_srcPort: { quint16 srcPort; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_src_port()) srcPort = data.src_port(); else srcPort = payloadProtocolId(ProtocolIdTcpUdp); break; default: srcPort = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Source Port"); case FieldValue: return srcPort; case FieldTextValue: return QString("%1").arg(srcPort); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(srcPort, (uchar*) fv.data()); return fv; } default: break; } break; } case udp_dstPort: { quint16 dstPort; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: if (data.is_override_dst_port()) dstPort = data.dst_port(); else dstPort = payloadProtocolId(ProtocolIdTcpUdp); break; default: dstPort = 0; // avoid the 'maybe used unitialized' warning break; } switch(attrib) { case FieldName: return QString("Destination Port"); case FieldValue: return dstPort; case FieldTextValue: return QString("%1").arg(dstPort); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(dstPort, (uchar*) fv.data()); return fv; } default: break; } break; } case udp_totLen: { switch(attrib) { case FieldName: return QString("Datagram Length"); case FieldValue: { int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 8); return totlen; } case FieldFrameValue: { QByteArray fv; int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 8); fv.resize(2); qToBigEndian((quint16) totlen, (uchar*) fv.data()); return fv; } case FieldTextValue: { int totlen; totlen = data.is_override_totlen() ? data.totlen() : (protocolFramePayloadSize(streamIndex) + 8); return QString("%1").arg(totlen); } case FieldBitSize: return 16; default: break; } break; } case udp_cksum: { quint16 cksum; switch(attrib) { case FieldValue: case FieldFrameValue: case FieldTextValue: { if (data.is_override_cksum()) cksum = data.cksum(); else cksum = protocolFrameCksum(streamIndex, CksumTcpUdp); qDebug("UDP cksum = %hu", cksum); break; } default: cksum = 0; break; } switch(attrib) { case FieldName: return QString("Checksum"); case FieldValue: return cksum; case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(cksum, (uchar*) fv.data()); return fv; } case FieldTextValue: return QString("0x%1"). arg(cksum, 4, BASE_HEX, QChar('0'));; case FieldBitSize: return 16; default: break; } break; } // Meta fields case udp_isOverrideSrcPort: { switch(attrib) { case FieldValue: return data.is_override_src_port(); default: break; } break; } case udp_isOverrideDstPort: { switch(attrib) { case FieldValue: return data.is_override_dst_port(); default: break; } break; } case udp_isOverrideTotLen: { switch(attrib) { case FieldValue: return data.is_override_totlen(); default: break; } break; } case udp_isOverrideCksum: { switch(attrib) { case FieldValue: return data.is_override_cksum(); default: break; } break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool UdpProtocol::setFieldData(int index, const QVariant& value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case udp_isOverrideSrcPort: { data.set_is_override_src_port(value.toBool()); isOk = true; break; } case udp_isOverrideDstPort: { data.set_is_override_dst_port(value.toBool()); isOk = true; break; } case udp_isOverrideTotLen: { data.set_is_override_totlen(value.toBool()); isOk = true; break; } case udp_isOverrideCksum: { data.set_is_override_cksum(value.toBool()); isOk = true; break; } case udp_srcPort: { uint srcPort = value.toUInt(&isOk); if (isOk) data.set_src_port(srcPort); break; } case udp_dstPort: { uint dstPort = value.toUInt(&isOk); if (isOk) data.set_dst_port(dstPort); break; } case udp_totLen: { uint totLen = value.toUInt(&isOk); if (isOk) data.set_totlen(totLen); break; } case udp_cksum: { uint cksum = value.toUInt(&isOk); if (isOk) data.set_cksum(cksum); break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } bool UdpProtocol::isProtocolFrameValueVariable() const { if (data.is_override_totlen() && data.is_override_cksum()) return false; else return isProtocolFramePayloadValueVariable(); } int UdpProtocol::protocolFrameVariableCount() const { if (data.is_override_totlen() && data.is_override_cksum()) return 1; return protocolFramePayloadVariableCount(); } QWidget* UdpProtocol::configWidget() { if (configForm == NULL) { configForm = new UdpConfigForm; loadConfigWidget(); } return configForm; } void UdpProtocol::loadConfigWidget() { configWidget(); configForm->leUdpSrcPort->setText( fieldData(udp_srcPort, FieldValue).toString()); configForm->cbUdpSrcPortOverride->setChecked( fieldData(udp_isOverrideSrcPort, FieldValue).toBool()); configForm->leUdpDstPort->setText( fieldData(udp_dstPort, FieldValue).toString()); configForm->cbUdpDstPortOverride->setChecked( fieldData(udp_isOverrideDstPort, FieldValue).toBool()); configForm->leUdpLength->setText( fieldData(udp_totLen, FieldValue).toString()); configForm->cbUdpLengthOverride->setChecked( fieldData(udp_isOverrideTotLen, FieldValue).toBool()); configForm->leUdpCksum->setText(QString("%1").arg( fieldData(udp_cksum, FieldValue).toUInt(), 4, BASE_HEX, QChar('0'))); configForm->cbUdpCksumOverride->setChecked( fieldData(udp_isOverrideCksum, FieldValue).toBool()); } void UdpProtocol::storeConfigWidget() { bool isOk; configWidget(); setFieldData(udp_srcPort, configForm->leUdpSrcPort->text()); setFieldData(udp_isOverrideSrcPort, configForm->cbUdpSrcPortOverride->isChecked()); setFieldData(udp_dstPort, configForm->leUdpDstPort->text()); setFieldData(udp_isOverrideDstPort, configForm->cbUdpDstPortOverride->isChecked()); setFieldData(udp_totLen, configForm->leUdpLength->text()); setFieldData(udp_isOverrideTotLen, configForm->cbUdpLengthOverride->isChecked()); setFieldData(udp_cksum, configForm->leUdpCksum->text().remove(QChar(' ')) .toUInt(&isOk, BASE_HEX)); setFieldData(udp_isOverrideCksum, configForm->cbUdpCksumOverride->isChecked()); } ostinato-0.5.1/common/udp.h0000700000175300010010000000455512005505615015133 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _UDP_H #define _UDP_H #include "abstractprotocol.h" #include "udp.pb.h" #include "ui_udp.h" class UdpConfigForm : public QWidget, public Ui::udp { Q_OBJECT public: UdpConfigForm(QWidget *parent = 0); }; class UdpProtocol : public AbstractProtocol { private: OstProto::Udp data; UdpConfigForm *configForm; enum udpfield { udp_srcPort = 0, udp_dstPort, udp_totLen, udp_cksum, udp_isOverrideSrcPort, udp_isOverrideDstPort, udp_isOverrideTotLen, udp_isOverrideCksum, udp_fieldCount }; public: UdpProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~UdpProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual ProtocolIdType protocolIdType() const; virtual quint32 protocolId(ProtocolIdType type) const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual bool isProtocolFrameValueVariable() const; virtual int protocolFrameVariableCount() const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/udp.proto0000700000175300010010000000215212005505615016036 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // UDP message Udp { optional bool is_override_src_port = 1; optional bool is_override_dst_port = 2; optional bool is_override_totlen = 3; optional bool is_override_cksum = 4; optional uint32 src_port = 5 [default = 49152]; optional uint32 dst_port = 6 [default = 49153]; optional uint32 totlen = 7; optional uint32 cksum = 8; } extend Protocol { optional Udp udp = 401; } ostinato-0.5.1/common/udp.ui0000700000175300010010000001013412005505615015307 0ustar srivatspNone udp 0 0 246 144 Form Override Source Port false Override Destination Port false Override Length false Override Checksum false >HH HH; Qt::Horizontal 40 20 Qt::Vertical 20 40 cbUdpLengthOverride toggled(bool) leUdpLength setEnabled(bool) 59 63 209 81 cbUdpCksumOverride toggled(bool) leUdpCksum setEnabled(bool) 55 106 209 107 cbUdpDstPortOverride toggled(bool) leUdpDstPort setEnabled(bool) 131 43 166 46 cbUdpSrcPortOverride toggled(bool) leUdpSrcPort setEnabled(bool) 125 21 167 20 ostinato-0.5.1/common/userscript.cpp0000700000175300010010000004011712005505615017073 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "userscript.h" #include // // -------------------- UserScriptConfigForm -------------------- // UserScriptConfigForm::UserScriptConfigForm(UserScriptProtocol *protocol, QWidget *parent) : QWidget(parent), protocol_(protocol) { setupUi(this); updateStatus(); } void UserScriptConfigForm::updateStatus() { if (protocol_->isScriptValid()) { statusLabel->setText(QString("Success")); compileButton->setDisabled(true); } else { statusLabel->setText( QString("Error: %1: %2").arg( protocol_->userScriptErrorLineNumber()).arg( protocol_->userScriptErrorText())); compileButton->setEnabled(true); } } void UserScriptConfigForm::on_programEdit_textChanged() { compileButton->setEnabled(true); } void UserScriptConfigForm::on_compileButton_clicked(bool /*checked*/) { protocol_->storeConfigWidget(); if (!protocol_->isScriptValid()) { QMessageBox::critical(this, "Error", QString("%1: %2").arg( protocol_->userScriptErrorLineNumber()).arg( protocol_->userScriptErrorText())); } updateStatus(); } // // -------------------- UserScriptProtocol -------------------- // UserScriptProtocol::UserScriptProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent), userProtocol_(this) { configForm = NULL; isScriptValid_ = false; errorLineNumber_ = 0; userProtocolScriptValue_ = engine_.newQObject(&userProtocol_); engine_.globalObject().setProperty("protocol", userProtocolScriptValue_); QScriptValue meta = engine_.newQMetaObject(userProtocol_.metaObject()); engine_.globalObject().setProperty("Protocol", meta); } UserScriptProtocol::~UserScriptProtocol() { delete configForm; } AbstractProtocol* UserScriptProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new UserScriptProtocol(stream, parent); } quint32 UserScriptProtocol::protocolNumber() const { return OstProto::Protocol::kUserScriptFieldNumber; } void UserScriptProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::userScript)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void UserScriptProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::userScript)) data.MergeFrom(protocol.GetExtension(OstProto::userScript)); evaluateUserScript(); } QString UserScriptProtocol::name() const { return QString("%1:{UserScript} [EXPERIMENTAL]").arg(userProtocol_.name()); } QString UserScriptProtocol::shortName() const { return QString("%1:{Script} [EXPERIMENTAL]").arg(userProtocol_.name()); } quint32 UserScriptProtocol::protocolId(ProtocolIdType type) const { QScriptValue userFunction; QScriptValue userValue; if (!isScriptValid_) goto _do_default; userFunction = userProtocolScriptValue_.property("protocolId"); if (!userFunction.isValid()) goto _do_default; Q_ASSERT(userFunction.isFunction()); userValue = userFunction.call(QScriptValue(), QScriptValueList() << QScriptValue(&engine_, type)); Q_ASSERT(userValue.isValid()); Q_ASSERT(userValue.isNumber()); return userValue.toUInt32(); _do_default: return AbstractProtocol::protocolId(type); } int UserScriptProtocol::fieldCount() const { return userScript_fieldCount; } QVariant UserScriptProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case userScript_program: switch(attrib) { case FieldName: return QString("UserProtocol"); case FieldValue: case FieldTextValue: return QString().fromStdString(data.program()); case FieldFrameValue: { if (!isScriptValid_) return QByteArray(); QScriptValue userFunction = userProtocolScriptValue_.property( "protocolFrameValue"); Q_ASSERT(userFunction.isValid()); Q_ASSERT(userFunction.isFunction()); QScriptValue userValue = userFunction.call(QScriptValue(), QScriptValueList() << QScriptValue(&engine_, streamIndex)); Q_ASSERT(userValue.isValid()); Q_ASSERT(userValue.isArray()); QByteArray fv; QList pktBuf; qScriptValueToSequence(userValue, pktBuf); fv.resize(pktBuf.size()); for (int i = 0; i < pktBuf.size(); i++) fv[i] = pktBuf.at(i) & 0xFF; return fv; } default: break; } break; default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool UserScriptProtocol::setFieldData(int index, const QVariant &value, FieldAttrib attrib) { bool isOk = false; if (attrib != FieldValue) goto _exit; switch (index) { case userScript_program: { data.set_program(value.toString().toStdString()); break; } default: qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__, index); break; } _exit: return isOk; } int UserScriptProtocol::protocolFrameSize(int streamIndex) const { if (!isScriptValid_) return 0; QScriptValue userFunction = userProtocolScriptValue_.property( "protocolFrameSize"); Q_ASSERT(userFunction.isValid()); Q_ASSERT(userFunction.isFunction()); QScriptValue userValue = userFunction.call(QScriptValue(), QScriptValueList() << QScriptValue(&engine_, streamIndex)); Q_ASSERT(userValue.isNumber()); return userValue.toInt32(); } bool UserScriptProtocol::isProtocolFrameValueVariable() const { return userProtocol_.isProtocolFrameValueVariable(); } bool UserScriptProtocol::isProtocolFrameSizeVariable() const { return userProtocol_.isProtocolFrameSizeVariable(); } int UserScriptProtocol::protocolFrameVariableCount() const { return userProtocol_.protocolFrameVariableCount(); } quint32 UserScriptProtocol::protocolFrameCksum(int streamIndex, CksumType cksumType) const { QScriptValue userFunction; QScriptValue userValue; if (!isScriptValid_) goto _do_default; userFunction = userProtocolScriptValue_.property("protocolFrameCksum"); qDebug("userscript protoFrameCksum(): isValid:%d/isFunc:%d", userFunction.isValid(), userFunction.isFunction()); if (!userFunction.isValid()) goto _do_default; Q_ASSERT(userFunction.isFunction()); userValue = userFunction.call(QScriptValue(), QScriptValueList() << QScriptValue(&engine_, streamIndex) << QScriptValue(&engine_, cksumType)); Q_ASSERT(userValue.isValid()); Q_ASSERT(userValue.isNumber()); return userValue.toUInt32(); _do_default: return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType); } QWidget* UserScriptProtocol::configWidget() { if (configForm == NULL) { configForm = new UserScriptConfigForm(this); loadConfigWidget(); } return configForm; } void UserScriptProtocol::loadConfigWidget() { configWidget(); configForm->programEdit->setPlainText( fieldData(userScript_program, FieldValue).toString()); } void UserScriptProtocol::storeConfigWidget() { configWidget(); setFieldData(userScript_program, configForm->programEdit->toPlainText()); evaluateUserScript(); } void UserScriptProtocol::evaluateUserScript() const { QScriptValue userFunction; QScriptValue userValue; QString property; isScriptValid_ = false; errorLineNumber_ = userScriptLineCount(); // Reset all properties including the dynamic ones userProtocol_.reset(); userProtocolScriptValue_.setProperty("protocolFrameValue", QScriptValue()); userProtocolScriptValue_.setProperty("protocolFrameSize", QScriptValue()); userProtocolScriptValue_.setProperty("protocolFrameCksum", QScriptValue()); userProtocolScriptValue_.setProperty("protocolId", QScriptValue()); engine_.evaluate(fieldData(userScript_program, FieldValue).toString()); if (engine_.hasUncaughtException()) goto _error_exception; // Validate protocolFrameValue() property = QString("protocolFrameValue"); userFunction = userProtocolScriptValue_.property(property); qDebug("userscript property %s: isValid:%d/isFunc:%d", property.toAscii().constData(), userFunction.isValid(), userFunction.isFunction()); if (!userFunction.isValid()) { errorText_ = property + QString(" not set"); goto _error_exit; } if (!userFunction.isFunction()) { errorText_ = property + QString(" is not a function"); goto _error_exit; } userValue = userFunction.call(); if (engine_.hasUncaughtException()) goto _error_exception; qDebug("userscript property %s return value: isValid:%d/isArray:%d", property.toAscii().constData(), userValue.isValid(), userValue.isArray()); if (!userValue.isArray()) { errorText_ = property + QString(" does not return an array"); goto _error_exit; } // Validate protocolFrameSize() property = QString("protocolFrameSize"); userFunction = userProtocolScriptValue_.property(property); qDebug("userscript property %s: isValid:%d/isFunc:%d", property.toAscii().constData(), userFunction.isValid(), userFunction.isFunction()); if (!userFunction.isValid()) { errorText_ = property + QString(" not set"); goto _error_exit; } if (!userFunction.isFunction()) { errorText_ = property + QString(" is not a function"); goto _error_exit; } userValue = userFunction.call(); if (engine_.hasUncaughtException()) goto _error_exception; qDebug("userscript property %s return value: isValid:%d/isNumber:%d", property.toAscii().constData(), userValue.isValid(), userValue.isNumber()); if (!userValue.isNumber()) { errorText_ = property + QString(" does not return a number"); goto _error_exit; } // Validate protocolFrameCksum() [optional] property = QString("protocolFrameCksum"); userFunction = userProtocolScriptValue_.property(property); qDebug("userscript property %s: isValid:%d/isFunc:%d", property.toAscii().constData(), userFunction.isValid(), userFunction.isFunction()); if (!userFunction.isValid()) goto _skip_cksum; if (!userFunction.isFunction()) { errorText_ = property + QString(" is not a function"); goto _error_exit; } userValue = userFunction.call(); if (engine_.hasUncaughtException()) goto _error_exception; qDebug("userscript property %s return value: isValid:%d/isNumber:%d", property.toAscii().constData(), userValue.isValid(), userValue.isNumber()); if (!userValue.isNumber()) { errorText_ = property + QString(" does not return a number"); goto _error_exit; } _skip_cksum: // Validate protocolId() [optional] property = QString("protocolId"); userFunction = userProtocolScriptValue_.property(property); qDebug("userscript property %s: isValid:%d/isFunc:%d", property.toAscii().constData(), userFunction.isValid(), userFunction.isFunction()); if (!userFunction.isValid()) goto _skip_protocol_id; if (!userFunction.isFunction()) { errorText_ = property + QString(" is not a function"); goto _error_exit; } userValue = userFunction.call(); if (engine_.hasUncaughtException()) goto _error_exception; qDebug("userscript property %s return value: isValid:%d/isNumber:%d", property.toAscii().constData(), userValue.isValid(), userValue.isNumber()); if (!userValue.isNumber()) { errorText_ = property + QString(" does not return a number"); goto _error_exit; } _skip_protocol_id: errorText_ = QString(""); isScriptValid_ = true; return; _error_exception: errorLineNumber_ = engine_.uncaughtExceptionLineNumber(); errorText_ = engine_.uncaughtException().toString(); _error_exit: userProtocol_.reset(); return; } bool UserScriptProtocol::isScriptValid() const { return isScriptValid_; } int UserScriptProtocol::userScriptErrorLineNumber() const { return errorLineNumber_; } QString UserScriptProtocol::userScriptErrorText() const { return errorText_; } int UserScriptProtocol::userScriptLineCount() const { return fieldData(userScript_program, FieldValue).toString().count( QChar('\n')) + 1; } // // -------------------- UserProtocol -------------------- // UserProtocol::UserProtocol(AbstractProtocol *parent) : parent_ (parent) { reset(); } void UserProtocol::reset() { name_ = QString(); protocolFrameValueVariable_ = false; protocolFrameSizeVariable_ = false; protocolFrameVariableCount_ = 1; } QString UserProtocol::name() const { return name_; } void UserProtocol::setName(QString &name) { name_ = name; } bool UserProtocol::isProtocolFrameValueVariable() const { return protocolFrameValueVariable_; } void UserProtocol::setProtocolFrameValueVariable(bool variable) { protocolFrameValueVariable_ = variable; } bool UserProtocol::isProtocolFrameSizeVariable() const { return protocolFrameSizeVariable_; } void UserProtocol::setProtocolFrameSizeVariable(bool variable) { protocolFrameSizeVariable_ = variable; } int UserProtocol::protocolFrameVariableCount() const { return protocolFrameVariableCount_; } void UserProtocol::setProtocolFrameVariableCount(int count) { protocolFrameVariableCount_ = count; } quint32 UserProtocol::payloadProtocolId(UserProtocol::ProtocolIdType type) const { return parent_->payloadProtocolId( static_cast(type)); } int UserProtocol::protocolFrameOffset(int streamIndex) const { return parent_->protocolFrameOffset(streamIndex); } int UserProtocol::protocolFramePayloadSize(int streamIndex) const { return parent_->protocolFramePayloadSize(streamIndex); } bool UserProtocol::isProtocolFramePayloadValueVariable() const { return parent_->isProtocolFramePayloadValueVariable(); } bool UserProtocol::isProtocolFramePayloadSizeVariable() const { return parent_->isProtocolFramePayloadSizeVariable(); } int UserProtocol::protocolFramePayloadVariableCount() const { return parent_->protocolFramePayloadVariableCount(); } quint32 UserProtocol::protocolFrameHeaderCksum(int streamIndex, AbstractProtocol::CksumType cksumType) const { return parent_->protocolFrameHeaderCksum(streamIndex, cksumType); } quint32 UserProtocol::protocolFramePayloadCksum(int streamIndex, AbstractProtocol::CksumType cksumType) const { quint32 cksum; cksum = parent_->protocolFramePayloadCksum(streamIndex, cksumType); qDebug("UserProto:%s = %d", __FUNCTION__, cksum); return cksum; } /* vim: set shiftwidth=4 tabstop=8 softtabstop=4 expandtab: */ ostinato-0.5.1/common/userscript.h0000700000175300010010000001272012005505615016537 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _USER_SCRIPT_H #define _USER_SCRIPT_H #include "abstractprotocol.h" #include "userscript.pb.h" #include "ui_userscript.h" #include #include class UserScriptProtocol; class UserProtocol : public QObject { Q_OBJECT; Q_ENUMS(ProtocolIdType); Q_ENUMS(CksumType); Q_PROPERTY(QString name READ name WRITE setName); Q_PROPERTY(bool protocolFrameValueVariable READ isProtocolFrameValueVariable WRITE setProtocolFrameValueVariable); Q_PROPERTY(bool protocolFrameSizeVariable READ isProtocolFrameSizeVariable WRITE setProtocolFrameSizeVariable); Q_PROPERTY(int protocolFrameVariableCount READ protocolFrameVariableCount WRITE setProtocolFrameVariableCount); public: enum ProtocolIdType { ProtocolIdLlc = AbstractProtocol::ProtocolIdLlc, ProtocolIdEth = AbstractProtocol::ProtocolIdEth, ProtocolIdIp = AbstractProtocol::ProtocolIdIp, ProtocolIdTcpUdp = AbstractProtocol::ProtocolIdTcpUdp }; enum CksumType { CksumIp = AbstractProtocol::CksumIp, CksumIpPseudo = AbstractProtocol::CksumIpPseudo, CksumTcpUdp = AbstractProtocol::CksumTcpUdp }; UserProtocol(AbstractProtocol *parent); public slots: void reset(); QString name() const; void setName(QString &name); bool isProtocolFrameValueVariable() const; void setProtocolFrameValueVariable(bool variable); bool isProtocolFrameSizeVariable() const; void setProtocolFrameSizeVariable(bool variable); int protocolFrameVariableCount() const; void setProtocolFrameVariableCount(int count); quint32 payloadProtocolId(UserProtocol::ProtocolIdType type) const; int protocolFrameOffset(int streamIndex = 0) const; int protocolFramePayloadSize(int streamIndex = 0) const; bool isProtocolFramePayloadValueVariable() const; bool isProtocolFramePayloadSizeVariable() const; int protocolFramePayloadVariableCount() const; quint32 protocolFrameHeaderCksum(int streamIndex = 0, AbstractProtocol::CksumType cksumType = AbstractProtocol::CksumIp) const; quint32 protocolFramePayloadCksum(int streamIndex = 0, AbstractProtocol::CksumType cksumType = AbstractProtocol::CksumIp) const; private: AbstractProtocol *parent_; QString name_; bool protocolFrameValueVariable_; bool protocolFrameSizeVariable_; int protocolFrameVariableCount_; }; class UserScriptConfigForm : public QWidget, public Ui::UserScript { Q_OBJECT public: UserScriptConfigForm(UserScriptProtocol *protocol, QWidget *parent = 0); private: void updateStatus(); UserScriptProtocol *protocol_; private slots: void on_programEdit_textChanged(); void on_compileButton_clicked(bool checked = false); }; class UserScriptProtocol : public AbstractProtocol { public: UserScriptProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~UserScriptProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual quint32 protocolId(ProtocolIdType type) const; virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual int protocolFrameSize(int streamIndex = 0) const; virtual bool isProtocolFrameValueVariable() const; virtual bool isProtocolFrameSizeVariable() const; virtual int protocolFrameVariableCount() const; virtual quint32 protocolFrameCksum(int streamIndex = 0, CksumType cksumType = CksumIp) const; virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); void evaluateUserScript() const; bool isScriptValid() const; int userScriptErrorLineNumber() const; QString userScriptErrorText() const; private: int userScriptLineCount() const; enum userScriptfield { // Frame Fields userScript_program = 0, userScript_fieldCount }; OstProto::UserScript data; UserScriptConfigForm *configForm; mutable QScriptEngine engine_; mutable UserProtocol userProtocol_; mutable QScriptValue userProtocolScriptValue_; mutable bool isScriptValid_; mutable int errorLineNumber_; mutable QString errorText_; }; #endif /* vim: set shiftwidth=4 tabstop=8 softtabstop=4 expandtab: */ ostinato-0.5.1/common/userscript.proto0000700000175300010010000000153612005505615017456 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Sample Protocol message UserScript { optional string program = 1; } extend Protocol { optional UserScript userScript = 103; } ostinato-0.5.1/common/userscript.ui0000700000175300010010000000337612005505615016734 0ustar srivatspNone UserScript 0 0 517 335 Form 10 0 QFrame::Panel QFrame::Sunken 4 4 4 4 4 Unknown Compile ostinato-0.5.1/common/vlan.cpp0000700000175300010010000001521712005505615015633 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include #include "vlan.h" VlanConfigForm::VlanConfigForm(QWidget *parent) : QWidget(parent) { setupUi(this); } VlanProtocol::VlanProtocol(StreamBase *stream, AbstractProtocol *parent) : AbstractProtocol(stream, parent) { configForm = NULL; } VlanProtocol::~VlanProtocol() { delete configForm; } AbstractProtocol* VlanProtocol::createInstance(StreamBase *stream, AbstractProtocol *parent) { return new VlanProtocol(stream, parent); } quint32 VlanProtocol::protocolNumber() const { return OstProto::Protocol::kVlanFieldNumber; } void VlanProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const { protocol.MutableExtension(OstProto::vlan)->CopyFrom(data); protocol.mutable_protocol_id()->set_id(protocolNumber()); } void VlanProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) { if (protocol.protocol_id().id() == protocolNumber() && protocol.HasExtension(OstProto::vlan)) data.MergeFrom(protocol.GetExtension(OstProto::vlan)); } QString VlanProtocol::name() const { return QString("Vlan"); } QString VlanProtocol::shortName() const { return QString("Vlan"); } int VlanProtocol::fieldCount() const { return vlan_fieldCount; } AbstractProtocol::FieldFlags VlanProtocol::fieldFlags(int index) const { AbstractProtocol::FieldFlags flags; flags = AbstractProtocol::fieldFlags(index); switch (index) { case vlan_tpid: case vlan_prio: case vlan_cfiDei: case vlan_vlanId: break; // meta-fields case vlan_isOverrideTpid: flags &= ~FrameField; flags |= MetaField; break; } return flags; } QVariant VlanProtocol::fieldData(int index, FieldAttrib attrib, int streamIndex) const { switch (index) { case vlan_tpid: { quint16 tpid; tpid = data.is_override_tpid() ? data.tpid() : 0x8100; switch(attrib) { case FieldName: return QString("Tag Protocol Id"); case FieldValue: return tpid; case FieldTextValue: return QString("0x%1").arg(tpid, 2, BASE_HEX, QChar('0')); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian(tpid, (uchar*) fv.data()); return fv; } default: break; } break; } case vlan_prio: { uint prio = ((data.vlan_tag() >> 13) & 0x07); switch(attrib) { case FieldName: return QString("Priority"); case FieldValue: return prio; case FieldTextValue: return QString("%1").arg(prio); case FieldFrameValue: return QByteArray(1, (char) prio); case FieldBitSize: return 3; default: break; } break; } case vlan_cfiDei: { uint cfiDei = ((data.vlan_tag() >> 12) & 0x01); switch(attrib) { case FieldName: return QString("CFI/DEI"); case FieldValue: return cfiDei; case FieldTextValue: return QString("%1").arg(cfiDei); case FieldFrameValue: return QByteArray(1, (char) cfiDei); case FieldBitSize: return 1; default: break; } break; } case vlan_vlanId: { quint16 vlanId = (data.vlan_tag() & 0x0FFF); switch(attrib) { case FieldName: return QString("VLAN Id"); case FieldValue: return vlanId; case FieldTextValue: return QString("%1").arg(vlanId); case FieldFrameValue: { QByteArray fv; fv.resize(2); qToBigEndian((quint16) vlanId, (uchar*) fv.data()); return fv; } case FieldBitSize: return 12; default: break; } break; } // Meta fields case vlan_isOverrideTpid: default: break; } return AbstractProtocol::fieldData(index, attrib, streamIndex); } bool VlanProtocol::setFieldData(int /*index*/, const QVariant &/*value*/, FieldAttrib /*attrib*/) { return false; } QWidget* VlanProtocol::configWidget() { if (configForm == NULL) { configForm = new VlanConfigForm; loadConfigWidget(); } return configForm; } void VlanProtocol::loadConfigWidget() { configWidget(); configForm->cbTpidOverride->setChecked(data.is_override_tpid()); configForm->leTpid->setText(uintToHexStr(fieldData(vlan_tpid, FieldValue).toUInt(), 2)); configForm->cmbPrio->setCurrentIndex(fieldData(vlan_prio, FieldValue).toUInt()); configForm->cmbCfiDei->setCurrentIndex(fieldData(vlan_cfiDei, FieldValue).toUInt()); configForm->leVlanId->setText(fieldData(vlan_vlanId, FieldValue).toString()); } void VlanProtocol::storeConfigWidget() { bool isOk; configWidget(); data.set_is_override_tpid(configForm->cbTpidOverride->isChecked()); data.set_tpid(configForm->leTpid->text().remove(QChar(' ')).toULong(&isOk, BASE_HEX)); data.set_vlan_tag( ((configForm->cmbPrio->currentIndex() & 0x07) << 13) | ((configForm->cmbCfiDei->currentIndex() & 0x01) << 12) | (configForm->leVlanId->text().toULong(&isOk) & 0x0FFF)); } ostinato-0.5.1/common/vlan.h0000700000175300010010000000414512005505615015276 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _Vlan_H #define _Vlan_H #include "abstractprotocol.h" #include "vlan.pb.h" #include "ui_vlan.h" class VlanConfigForm : public QWidget, public Ui::Vlan { Q_OBJECT public: VlanConfigForm(QWidget *parent = 0); }; class VlanProtocol : public AbstractProtocol { private: VlanConfigForm *configForm; enum Vlanfield { vlan_tpid, vlan_prio, vlan_cfiDei, vlan_vlanId, // meta-fields vlan_isOverrideTpid, vlan_fieldCount }; protected: OstProto::Vlan data; public: VlanProtocol(StreamBase *stream, AbstractProtocol *parent = 0); virtual ~VlanProtocol(); static AbstractProtocol* createInstance(StreamBase *stream, AbstractProtocol *parent = 0); virtual quint32 protocolNumber() const; virtual void protoDataCopyInto(OstProto::Protocol &protocol) const; virtual void protoDataCopyFrom(const OstProto::Protocol &protocol); virtual QString name() const; virtual QString shortName() const; virtual int fieldCount() const; virtual AbstractProtocol::FieldFlags fieldFlags(int index) const; virtual QVariant fieldData(int index, FieldAttrib attrib, int streamIndex = 0) const; virtual bool setFieldData(int index, const QVariant &value, FieldAttrib attrib = FieldValue); virtual QWidget* configWidget(); virtual void loadConfigWidget(); virtual void storeConfigWidget(); }; #endif ostinato-0.5.1/common/vlan.proto0000700000175300010010000000172212005505615016210 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; message Vlan { // VLAN presence/absence optional bool is_override_tpid = 1; // VLAN values optional uint32 tpid = 2; optional uint32 vlan_tag = 3; // includes prio, cfi and vlanid } extend Protocol { optional Vlan vlan = 205; } ostinato-0.5.1/common/vlan.ui0000700000175300010010000001041012005505615015454 0ustar srivatspNone Vlan 0 0 268 96 Form 6 9 9 9 9 VLAN true Override TPID Priority CFI/DEI VLAN false >HH HH; true 0 1 2 3 4 5 6 7 true 0 1 true 0 cbTpidOverride toggled(bool) leTpid setEnabled(bool) 59 41 59 57 ostinato-0.5.1/common/vlanstack.h0000700000175300010010000000161612005505615016324 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _VLAN_STACK_H #define _VLAN_STACK_H #include "comboprotocol.h" #include "svlan.h" #include "vlan.h" typedef ComboProtocol VlanStackProtocol; #endif ostinato-0.5.1/common/vlanstack.proto0000700000175300010010000000155112005505615017236 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ import "protocol.proto"; package OstProto; // Stacked VLAN (2 tags) message VlanStack { // Empty since this is a 'combo' protocol } extend Protocol { optional VlanStack vlanStack = 208; } ostinato-0.5.1/COPYING0000700000175300010010000010451312005505614013727 0ustar srivatspNone GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ostinato-0.5.1/extra/0000700000175300010010000000000012005505615014011 5ustar srivatspNoneostinato-0.5.1/extra/extra.pro0000700000175300010010000000005512005505615015661 0ustar srivatspNoneTEMPLATE = subdirs SUBDIRS = \ qhexedit2 ostinato-0.5.1/extra/qhexedit2/0000700000175300010010000000000012005505615015706 5ustar srivatspNoneostinato-0.5.1/extra/qhexedit2/qhexedit2.pro0000700000175300010010000000042312005505615020327 0ustar srivatspNoneTEMPLATE = lib CONFIG += qt staticlib warn_on HEADERS = src/commands.h\ src/qhexedit.h \ src/qhexedit_p.h \ src/xbytearray.h SOURCES = src/commands.cpp \ src/qhexedit.cpp \ src/qhexedit_p.cpp \ src/xbytearray.cpp ostinato-0.5.1/extra/qhexedit2/src/0000700000175300010010000000000012005505615016475 5ustar srivatspNoneostinato-0.5.1/extra/qhexedit2/src/commands.cpp0000700000175300010010000000545312005505615021014 0ustar srivatspNone#include "commands.h" CharCommand::CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar, QUndoCommand *parent) : QUndoCommand(parent) { _xData = xData; _charPos = charPos; _newChar = newChar; _cmd = cmd; } bool CharCommand::mergeWith(const QUndoCommand *command) { const CharCommand *nextCommand = static_cast(command); bool result = false; if (_cmd != remove) { if (nextCommand->_cmd == replace) if (nextCommand->_charPos == _charPos) { _newChar = nextCommand->_newChar; result = true; } } return result; } void CharCommand::undo() { switch (_cmd) { case insert: _xData->remove(_charPos, 1); break; case replace: _xData->replace(_charPos, _oldChar); _xData->setDataChanged(_charPos, _wasChanged); break; case remove: _xData->insert(_charPos, _oldChar); _xData->setDataChanged(_charPos, _wasChanged); break; } } void CharCommand::redo() { switch (_cmd) { case insert: _xData->insert(_charPos, _newChar); break; case replace: _oldChar = _xData->data()[_charPos]; _wasChanged = _xData->dataChanged(_charPos); _xData->replace(_charPos, _newChar); break; case remove: _oldChar = _xData->data()[_charPos]; _wasChanged = _xData->dataChanged(_charPos); _xData->remove(_charPos, 1); break; } } ArrayCommand::ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa, int len, QUndoCommand *parent) : QUndoCommand(parent) { _cmd = cmd; _xData = xData; _baPos = baPos; _newBa = newBa; _len = len; } void ArrayCommand::undo() { switch (_cmd) { case insert: _xData->remove(_baPos, _newBa.length()); break; case replace: _xData->replace(_baPos, _oldBa); _xData->setDataChanged(_baPos, _wasChanged); break; case remove: _xData->insert(_baPos, _oldBa); _xData->setDataChanged(_baPos, _wasChanged); break; } } void ArrayCommand::redo() { switch (_cmd) { case insert: _xData->insert(_baPos, _newBa); break; case replace: _oldBa = _xData->data().mid(_baPos, _len); _wasChanged = _xData->dataChanged(_baPos, _len); _xData->replace(_baPos, _newBa); break; case remove: _oldBa = _xData->data().mid(_baPos, _len); _wasChanged = _xData->dataChanged(_baPos, _len); _xData->remove(_baPos, _len); break; } } ostinato-0.5.1/extra/qhexedit2/src/commands.h0000700000175300010010000000357512005505615020464 0ustar srivatspNone#ifndef COMMANDS_H #define COMMANDS_H /** \cond docNever */ #include #include "xbytearray.h" /*! CharCommand is a class to prived undo/redo functionality in QHexEdit. A QUndoCommand represents a single editing action on a document. CharCommand is responsable for manipulations on single chars. It can insert. replace and remove characters. A manipulation stores allways to actions 1. redo (or do) action 2. undo action. CharCommand also supports command compression via mergeWidht(). This allows the user to execute a undo command contation e.g. 3 steps in a single command. If you for example insert a new byt "34" this means for the editor doing 3 steps: insert a "00", replace it with "03" and the replace it with "34". These 3 steps are combined into a single step, insert a "34". */ class CharCommand : public QUndoCommand { public: enum { Id = 1234 }; enum Cmd {insert, remove, replace}; CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar, QUndoCommand *parent=0); void undo(); void redo(); bool mergeWith(const QUndoCommand *command); int id() const { return Id; } private: XByteArray * _xData; int _charPos; bool _wasChanged; char _newChar; char _oldChar; Cmd _cmd; }; /*! ArrayCommand provides undo/redo functionality for handling binary strings. It can undo/redo insert, replace and remove binary strins (QByteArrays). */ class ArrayCommand : public QUndoCommand { public: enum Cmd {insert, remove, replace}; ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa=QByteArray(), int len=0, QUndoCommand *parent=0); void undo(); void redo(); private: Cmd _cmd; XByteArray * _xData; int _baPos; int _len; QByteArray _wasChanged; QByteArray _newBa; QByteArray _oldBa; }; /** \endcond docNever */ #endif // COMMANDS_H ostinato-0.5.1/extra/qhexedit2/src/license.txt0000700000175300010010000006364112005505615020675 0ustar srivatspNone GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!ostinato-0.5.1/extra/qhexedit2/src/qhexedit.cpp0000700000175300010010000000551112005505615021021 0ustar srivatspNone#include #include "qhexedit.h" QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent) { qHexEdit_p = new QHexEditPrivate(this); setWidget(qHexEdit_p); setWidgetResizable(true); connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int))); connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int))); connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged())); connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool))); setFocusPolicy(Qt::NoFocus); } void QHexEdit::insert(int i, const QByteArray & ba) { qHexEdit_p->insert(i, ba); } void QHexEdit::insert(int i, char ch) { qHexEdit_p->insert(i, ch); } void QHexEdit::remove(int pos, int len) { qHexEdit_p->remove(pos, len); } QString QHexEdit::toReadableString() { return qHexEdit_p->toRedableString(); } QString QHexEdit::selectionToReadableString() { return qHexEdit_p->selectionToReadableString(); } void QHexEdit::setAddressArea(bool addressArea) { qHexEdit_p->setAddressArea(addressArea); } void QHexEdit::redo() { qHexEdit_p->redo(); } void QHexEdit::undo() { qHexEdit_p->undo(); } void QHexEdit::setAddressWidth(int addressWidth) { qHexEdit_p->setAddressWidth(addressWidth); } void QHexEdit::setAsciiArea(bool asciiArea) { qHexEdit_p->setAsciiArea(asciiArea); } void QHexEdit::setHighlighting(bool mode) { qHexEdit_p->setHighlighting(mode); } void QHexEdit::setAddressOffset(int offset) { qHexEdit_p->setAddressOffset(offset); } int QHexEdit::addressOffset() { return qHexEdit_p->addressOffset(); } void QHexEdit::setData(const QByteArray &data) { qHexEdit_p->setData(data); } QByteArray QHexEdit::data() { return qHexEdit_p->data(); } void QHexEdit::setAddressAreaColor(const QColor &color) { qHexEdit_p->setAddressAreaColor(color); } QColor QHexEdit::addressAreaColor() { return qHexEdit_p->addressAreaColor(); } void QHexEdit::setHighlightingColor(const QColor &color) { qHexEdit_p->setHighlightingColor(color); } QColor QHexEdit::highlightingColor() { return qHexEdit_p->highlightingColor(); } void QHexEdit::setSelectionColor(const QColor &color) { qHexEdit_p->setSelectionColor(color); } QColor QHexEdit::selectionColor() { return qHexEdit_p->selectionColor(); } void QHexEdit::setOverwriteMode(bool overwriteMode) { qHexEdit_p->setOverwriteMode(overwriteMode); } bool QHexEdit::overwriteMode() { return qHexEdit_p->overwriteMode(); } void QHexEdit::setReadOnly(bool readOnly) { qHexEdit_p->setReadOnly(readOnly); } bool QHexEdit::isReadOnly() { return qHexEdit_p->isReadOnly(); } void QHexEdit::setFont(const QFont &font) { qHexEdit_p->setFont(font); } const QFont & QHexEdit::font() const { return qHexEdit_p->font(); } ostinato-0.5.1/extra/qhexedit2/src/qhexedit.h0000700000175300010010000001633112005505615020470 0ustar srivatspNone#ifndef QHEXEDIT_H #define QHEXEDIT_H #include #include "qhexedit_p.h" /** \mainpage QHexEdit is a binary editor widget for Qt. \version Version 0.6.1 \image html hexedit.png */ /*! QHexEdit is a hex editor widget written in C++ for the Qt (Qt4) framework. It is a simple editor for binary data, just like QPlainTextEdit is for text data. There are sip configuration files included, so it is easy to create bindings for PyQt and you can use this widget also in python. QHexEdit takes the data of a QByteArray (setData()) and shows it. You can use the mouse or the keyboard to navigate inside the widget. If you hit the keys (0..9, a..f) you will change the data. Changed data is highlighted and can be accessed via data(). Normaly QHexEdit works in the overwrite Mode. You can set overwriteMode(false) and insert data. In this case the size of data() increases. It is also possible to delete bytes (del or backspace), here the size of data decreases. You can select data with keyboard hits or mouse movements. The copy-key will copy the selected data into the clipboard. The cut-key copies also but delets it afterwards. In overwrite mode, the paste function overwrites the content of the (does not change the length) data. In insert mode, clipboard data will be inserted. The clipboard content is expected in ASCII Hex notation. Unknown characters will be ignored. QHexEdit comes with undo/redo functionality. All changes can be undone, by pressing the undo-key (usually ctr-z). They can also be redone afterwards. The undo/redo framework is cleared, when setData() sets up a new content for the editor. This widget can only handle small amounts of data. The size has to be below 10 megabytes, otherwise the scroll sliders ard not shown and you can't scroll any more. */ class QHexEdit : public QScrollArea { Q_OBJECT /*! Property data holds the content of QHexEdit. Call setData() to set the content of QHexEdit, data() returns the actual content. */ Q_PROPERTY(QByteArray data READ data WRITE setData) /*! Property addressOffset is added to the Numbers of the Address Area. A offset in the address area (left side) is sometimes usefull, whe you show only a segment of a complete memory picture. With setAddressOffset() you set this property - with addressOffset() you get the actual value. */ Q_PROPERTY(int addressOffset READ addressOffset WRITE setAddressOffset) /*! Property address area color sets (setAddressAreaColor()) the backgorund color of address areas. You can also read the color (addressaAreaColor()). */ Q_PROPERTY(QColor addressAreaColor READ addressAreaColor WRITE setAddressAreaColor) /*! Property highlighting color sets (setHighlightingColor()) the backgorund color of highlighted text areas. You can also read the color (highlightingColor()). */ Q_PROPERTY(QColor highlightingColor READ highlightingColor WRITE setHighlightingColor) /*! Property selection color sets (setSelectionColor()) the backgorund color of selected text areas. You can also read the color (selectionColor()). */ Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor) /*! Porperty overwrite mode sets (setOverwriteMode()) or gets (overwriteMode()) the mode in which the editor works. In overwrite mode the user will overwrite existing data. The size of data will be constant. In insert mode the size will grow, when inserting new data. */ Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode) /*! Porperty readOnly sets (setReadOnly()) or gets (isReadOnly) the mode in which the editor works. In readonly mode the the user can only navigate through the data and select data; modifying is not possible. This property's default is false. */ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) /*! Set the font of the widget. Please use fixed width fonts like Mono or Courier.*/ Q_PROPERTY(QFont font READ font WRITE setFont) public: /*! Creates an instance of QHexEdit. \param parent Parent widget of QHexEdit. */ QHexEdit(QWidget *parent = 0); /*! Inserts a byte array. \param i Index position, where to insert \param ba byte array, which is to insert In overwrite mode, the existing data will be overwritten, in insertmode ba will be insertet and size of data grows. */ void insert(int i, const QByteArray & ba); /*! Inserts a char. \param i Index position, where to insert \param ch Char, which is to insert In overwrite mode, the existing data will be overwritten, in insertmode ba will be insertet and size of data grows. */ void insert(int i, char ch); /*! Removes len bytes from the content. \param pos Index position, where to remove \param len Amount of bytes to remove In overwrite mode, the existing bytes will be overwriten with 0x00. */ void remove(int pos, int len=1); /*! Gives back a formatted image of the content of QHexEdit */ QString toReadableString(); /*! Gives back a formatted image of the selected content of QHexEdit */ QString selectionToReadableString(); /*! \cond docNever */ void setAddressOffset(int offset); int addressOffset(); void setData(QByteArray const &data); QByteArray data(); void setAddressAreaColor(QColor const &color); QColor addressAreaColor(); void setHighlightingColor(QColor const &color); QColor highlightingColor(); void setSelectionColor(QColor const &color); QColor selectionColor(); void setOverwriteMode(bool); bool overwriteMode(); void setReadOnly(bool); bool isReadOnly(); const QFont &font() const; void setFont(const QFont &); /*! \endcond docNever */ public slots: /*! Redoes the last operation. If there is no operation to redo, i.e. there is no redo step in the undo/redo history, nothing happens. */ void redo(); /*! Set the minimum width of the address area. \param addressWidth Width in characters. */ void setAddressWidth(int addressWidth); /*! Switch the address area on or off. \param addressArea true (show it), false (hide it). */ void setAddressArea(bool addressArea); /*! Switch the ascii area on or off. \param asciiArea true (show it), false (hide it). */ void setAsciiArea(bool asciiArea); /*! Switch the highlighting feature on or of. \param mode true (show it), false (hide it). */ void setHighlighting(bool mode); /*! Undoes the last operation. If there is no operation to undo, i.e. there is no undo step in the undo/redo history, nothing happens. */ void undo(); signals: /*! Contains the address, where the cursor is located. */ void currentAddressChanged(int address); /*! Contains the size of the data to edit. */ void currentSizeChanged(int size); /*! The signal is emited every time, the data is changed. */ void dataChanged(); /*! The signal is emited every time, the overwrite mode is changed. */ void overwriteModeChanged(bool state); private: /*! \cond docNever */ QHexEditPrivate *qHexEdit_p; QHBoxLayout *layout; QScrollArea *scrollArea; /*! \endcond docNever */ }; #endif ostinato-0.5.1/extra/qhexedit2/src/qhexedit_p.cpp0000700000175300010010000005400312005505615021340 0ustar srivatspNone#include #include "qhexedit_p.h" #include "commands.h" const int HEXCHARS_IN_LINE = 47; const int GAP_ADR_HEX = 10; const int GAP_HEX_ASCII = 16; const int BYTES_PER_LINE = 16; QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent) { _undoStack = new QUndoStack(this); _scrollArea = parent; setAddressWidth(4); setAddressOffset(0); setAddressArea(true); setAsciiArea(true); setHighlighting(true); setOverwriteMode(true); setReadOnly(false); setAddressAreaColor(QColor(0xd4, 0xd4, 0xd4, 0xff)); setHighlightingColor(QColor(0xff, 0xff, 0x99, 0xff)); setSelectionColor(QColor(0x6d, 0x9e, 0xff, 0xff)); setFont(QFont("Courier", 10)); _size = 0; resetSelection(0); setFocusPolicy(Qt::StrongFocus); connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor())); _cursorTimer.setInterval(500); _cursorTimer.start(); } void QHexEditPrivate::setAddressOffset(int offset) { _xData.setAddressOffset(offset); adjust(); } int QHexEditPrivate::addressOffset() { return _xData.addressOffset(); } void QHexEditPrivate::setData(const QByteArray &data) { _xData.setData(data); _undoStack->clear(); adjust(); setCursorPos(0); } QByteArray QHexEditPrivate::data() { return _xData.data(); } void QHexEditPrivate::setAddressAreaColor(const QColor &color) { _addressAreaColor = color; update(); } QColor QHexEditPrivate::addressAreaColor() { return _addressAreaColor; } void QHexEditPrivate::setHighlightingColor(const QColor &color) { _highlightingColor = color; update(); } QColor QHexEditPrivate::highlightingColor() { return _highlightingColor; } void QHexEditPrivate::setSelectionColor(const QColor &color) { _selectionColor = color; update(); } QColor QHexEditPrivate::selectionColor() { return _selectionColor; } void QHexEditPrivate::setReadOnly(bool readOnly) { _readOnly = readOnly; } bool QHexEditPrivate::isReadOnly() { return _readOnly; } XByteArray & QHexEditPrivate::xData() { return _xData; } void QHexEditPrivate::insert(int index, const QByteArray & ba) { if (ba.length() > 0) { if (_overwriteMode) { QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); _undoStack->push(arrayCommand); emit dataChanged(); } else { QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::insert, index, ba, ba.length()); _undoStack->push(arrayCommand); emit dataChanged(); } } } void QHexEditPrivate::insert(int index, char ch) { QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::insert, index, ch); _undoStack->push(charCommand); emit dataChanged(); } void QHexEditPrivate::remove(int index, int len) { if (len > 0) { if (len == 1) { if (_overwriteMode) { QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, char(0)); _undoStack->push(charCommand); emit dataChanged(); } else { QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::remove, index, char(0)); _undoStack->push(charCommand); emit dataChanged(); } } else { QByteArray ba = QByteArray(len, char(0)); if (_overwriteMode) { QUndoCommand *arrayCommand = new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); _undoStack->push(arrayCommand); emit dataChanged(); } else { QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::remove, index, ba, len); _undoStack->push(arrayCommand); emit dataChanged(); } } } } void QHexEditPrivate::replace(int index, char ch) { QUndoCommand *charCommand = new CharCommand(&_xData, CharCommand::replace, index, ch); _undoStack->push(charCommand); emit dataChanged(); } void QHexEditPrivate::replace(int index, const QByteArray & ba) { QUndoCommand *arrayCommand= new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()); _undoStack->push(arrayCommand); emit dataChanged(); } void QHexEditPrivate::setAddressArea(bool addressArea) { _addressArea = addressArea; adjust(); setCursorPos(_cursorPosition); } void QHexEditPrivate::setAddressWidth(int addressWidth) { _xData.setAddressWidth(addressWidth); setCursorPos(_cursorPosition); } void QHexEditPrivate::setAsciiArea(bool asciiArea) { _asciiArea = asciiArea; adjust(); } void QHexEditPrivate::setFont(const QFont &font) { QWidget::setFont(font); adjust(); } void QHexEditPrivate::setHighlighting(bool mode) { _highlighting = mode; update(); } void QHexEditPrivate::setOverwriteMode(bool overwriteMode) { _overwriteMode = overwriteMode; } bool QHexEditPrivate::overwriteMode() { return _overwriteMode; } void QHexEditPrivate::redo() { _undoStack->redo(); emit dataChanged(); setCursorPos(_cursorPosition); update(); } void QHexEditPrivate::undo() { _undoStack->undo(); emit dataChanged(); setCursorPos(_cursorPosition); update(); } QString QHexEditPrivate::toRedableString() { return _xData.toRedableString(); } QString QHexEditPrivate::selectionToReadableString() { return _xData.toRedableString(getSelectionBegin(), getSelectionEnd()); } void QHexEditPrivate::keyPressEvent(QKeyEvent *event) { int charX = (_cursorX - _xPosHex) / _charWidth; int posX = (charX / 3) * 2 + (charX % 3); int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2; /*****************************************************************************/ /* Cursor movements */ /*****************************************************************************/ if (event->matches(QKeySequence::MoveToNextChar)) { setCursorPos(_cursorPosition + 1); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToPreviousChar)) { setCursorPos(_cursorPosition - 1); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToEndOfLine)) { setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToStartOfLine)) { setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE))); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToPreviousLine)) { setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToNextLine)) { setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToNextPage)) { setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToPreviousPage)) { setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE)); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToEndOfDocument)) { setCursorPos(_xData.size() * 2); resetSelection(_cursorPosition); } if (event->matches(QKeySequence::MoveToStartOfDocument)) { setCursorPos(0); resetSelection(_cursorPosition); } /*****************************************************************************/ /* Select commands */ /*****************************************************************************/ if (event->matches(QKeySequence::SelectAll)) { resetSelection(0); setSelection(2*_xData.size() + 1); } if (event->matches(QKeySequence::SelectNextChar)) { int pos = _cursorPosition + 1; setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousChar)) { int pos = _cursorPosition - 1; setSelection(pos); setCursorPos(pos); } if (event->matches(QKeySequence::SelectEndOfLine)) { int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)) + (2 * BYTES_PER_LINE); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectStartOfLine)) { int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousLine)) { int pos = _cursorPosition - (2 * BYTES_PER_LINE); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectNextLine)) { int pos = _cursorPosition + (2 * BYTES_PER_LINE); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectNextPage)) { int pos = _cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectPreviousPage)) { int pos = _cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE); setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectEndOfDocument)) { int pos = _xData.size() * 2; setCursorPos(pos); setSelection(pos); } if (event->matches(QKeySequence::SelectStartOfDocument)) { int pos = 0; setCursorPos(pos); setSelection(pos); } /*****************************************************************************/ /* Edit Commands */ /*****************************************************************************/ if (!_readOnly) { /* Hex input */ int key = int(event->text()[0].toAscii()); if ((key>='0' && key<='9') || (key>='a' && key <= 'f')) { if (getSelectionBegin() != getSelectionEnd()) { posBa = getSelectionBegin(); remove(posBa, getSelectionEnd() - posBa); setCursorPos(2*posBa); resetSelection(2*posBa); } // If insert mode, then insert a byte if (_overwriteMode == false) if ((charX % 3) == 0) { insert(posBa, char(0)); } // Change content if (_xData.size() > 0) { QByteArray hexValue = _xData.data().mid(posBa, 1).toHex(); if ((charX % 3) == 0) hexValue[0] = key; else hexValue[1] = key; replace(posBa, QByteArray().fromHex(hexValue)[0]); setCursorPos(_cursorPosition + 1); resetSelection(_cursorPosition); } } /* Cut & Paste */ if (event->matches(QKeySequence::Cut)) { QString result = QString(); for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++) { result += _xData.data().mid(idx, 1).toHex() + " "; if ((idx % 16) == 15) result.append("\n"); } remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin()); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(result); setCursorPos(getSelectionBegin()); resetSelection(getSelectionBegin()); } if (event->matches(QKeySequence::Paste)) { QClipboard *clipboard = QApplication::clipboard(); QByteArray ba = QByteArray().fromHex(clipboard->text().toLatin1()); insert(_cursorPosition / 2, ba); setCursorPos(_cursorPosition + 2 * ba.length()); resetSelection(getSelectionBegin()); } /* Delete char */ if (event->matches(QKeySequence::Delete)) { if (getSelectionBegin() != getSelectionEnd()) { posBa = getSelectionBegin(); remove(posBa, getSelectionEnd() - posBa); setCursorPos(2*posBa); resetSelection(2*posBa); } else { if (_overwriteMode) replace(posBa, char(0)); else remove(posBa, 1); } } /* Backspace */ if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier)) { if (getSelectionBegin() != getSelectionEnd()) { posBa = getSelectionBegin(); remove(posBa, getSelectionEnd() - posBa); setCursorPos(2*posBa); resetSelection(2*posBa); } else { if (posBa > 0) { if (_overwriteMode) replace(posBa - 1, char(0)); else remove(posBa - 1, 1); setCursorPos(_cursorPosition - 2); } } } /* undo */ if (event->matches(QKeySequence::Undo)) { undo(); } /* redo */ if (event->matches(QKeySequence::Redo)) { redo(); } } if (event->matches(QKeySequence::Copy)) { QString result = QString(); for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++) { result += _xData.data().mid(idx, 1).toHex() + " "; if ((idx % 16) == 15) result.append('\n'); } QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(result); } // Switch between insert/overwrite mode if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier)) { _overwriteMode = !_overwriteMode; setCursorPos(_cursorPosition); overwriteModeChanged(_overwriteMode); } _scrollArea->ensureVisible(_cursorX, _cursorY + _charHeight/2, 3, _charHeight/2 + 2); update(); } void QHexEditPrivate::mouseMoveEvent(QMouseEvent * event) { _blink = false; update(); int actPos = cursorPos(event->pos()); setCursorPos(actPos); setSelection(actPos); } void QHexEditPrivate::mousePressEvent(QMouseEvent * event) { _blink = false; update(); int cPos = cursorPos(event->pos()); resetSelection(cPos); setCursorPos(cPos); } void QHexEditPrivate::paintEvent(QPaintEvent *event) { QPainter painter(this); // draw some patterns if needed painter.fillRect(event->rect(), this->palette().color(QPalette::Base)); if (_addressArea) painter.fillRect(QRect(_xPosAdr, event->rect().top(), _xPosHex - GAP_ADR_HEX + 2, height()), _addressAreaColor); if (_asciiArea) { int linePos = _xPosAscii - (GAP_HEX_ASCII / 2); painter.setPen(Qt::gray); painter.drawLine(linePos, event->rect().top(), linePos, height()); } painter.setPen(this->palette().color(QPalette::WindowText)); // calc position int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE; if (firstLineIdx < 0) firstLineIdx = 0; int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE; if (lastLineIdx > _xData.size()) lastLineIdx = _xData.size(); int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight; // paint address area if (_addressArea) { for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) { QString address = QString("%1") .arg(lineIdx + _xData.addressOffset(), _xData.realAddressNumbers(), 16, QChar('0')); painter.drawText(_xPosAdr, yPos, address); } } // paint hex area QByteArray hexBa(_xData.data().mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex()); QBrush highLighted = QBrush(_highlightingColor); QPen colHighlighted = QPen(this->palette().color(QPalette::WindowText)); QBrush selected = QBrush(_selectionColor); QPen colSelected = QPen(Qt::white); QPen colStandard = QPen(this->palette().color(QPalette::WindowText)); painter.setBackgroundMode(Qt::TransparentMode); for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) { QByteArray hex; int xPos = _xPosHex; for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() and (colIdx < BYTES_PER_LINE)); colIdx++) { int posBa = lineIdx + colIdx; if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa)) { painter.setBackground(selected); painter.setBackgroundMode(Qt::OpaqueMode); painter.setPen(colSelected); } else { if (_highlighting) { // hilight diff bytes painter.setBackground(highLighted); if (_xData.dataChanged(posBa)) { painter.setPen(colHighlighted); painter.setBackgroundMode(Qt::OpaqueMode); } else { painter.setPen(colStandard); painter.setBackgroundMode(Qt::TransparentMode); } } } // render hex value if (colIdx == 0) { hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2); painter.drawText(xPos, yPos, hex); xPos += 2 * _charWidth; } else { hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" "); painter.drawText(xPos, yPos, hex); xPos += 3 * _charWidth; } } } painter.setBackgroundMode(Qt::TransparentMode); painter.setPen(this->palette().color(QPalette::WindowText)); // paint ascii area if (_asciiArea) { for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight) { int xPosAscii = _xPosAscii; for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() and (colIdx < BYTES_PER_LINE)); colIdx++) { painter.drawText(xPosAscii, yPos, _xData.asciiChar(lineIdx + colIdx)); xPosAscii += _charWidth; } } } // paint cursor if (_blink) { if (_overwriteMode) painter.fillRect(_cursorX, _cursorY + _charHeight - 2, _charWidth, 2, this->palette().color(QPalette::WindowText)); else painter.fillRect(_cursorX, _cursorY, 2, _charHeight, this->palette().color(QPalette::WindowText)); } if (_size != _xData.size()) { _size = _xData.size(); emit currentSizeChanged(_size); } } void QHexEditPrivate::setCursorPos(int position) { // delete cursor _blink = false; update(); // cursor in range? if (_overwriteMode) { if (position > (_xData.size() * 2 - 1)) position = _xData.size() * 2 - 1; } else { if (position > (_xData.size() * 2)) position = _xData.size() * 2; } if (position < 0) position = 0; // calc position _cursorPosition = position; _cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4; int x = (position % (2 * BYTES_PER_LINE)); _cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex; // immiadately draw cursor _blink = true; update(); emit currentAddressChanged(_cursorPosition/2); } int QHexEditPrivate::cursorPos(QPoint pos) { int result = -1; // find char under cursor if ((pos.x() >= _xPosHex) and (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth))) { int x = (pos.x() - _xPosHex) / _charWidth; if ((x % 3) == 0) x = (x / 3) * 2; else x = ((x / 3) * 2) + 1; int y = ((pos.y() - 3) / _charHeight) * 2 * BYTES_PER_LINE; result = x + y; } return result; } int QHexEditPrivate::cursorPos() { return _cursorPosition; } void QHexEditPrivate::resetSelection(int pos) { if (pos < 0) pos = 0; pos = pos / 2; _selectionInit = pos; _selectionBegin = pos; _selectionEnd = pos; } void QHexEditPrivate::setSelection(int pos) { if (pos < 0) pos = 0; pos = pos / 2; if (pos >= _selectionInit) { _selectionEnd = pos; _selectionBegin = _selectionInit; } else { _selectionBegin = pos; _selectionEnd = _selectionInit; } } int QHexEditPrivate::getSelectionBegin() { return _selectionBegin; } int QHexEditPrivate::getSelectionEnd() { return _selectionEnd; } void QHexEditPrivate::updateCursor() { if (_blink) _blink = false; else _blink = true; update(_cursorX, _cursorY, _charWidth, _charHeight); } void QHexEditPrivate::adjust() { _charWidth = fontMetrics().width(QLatin1Char('9')); _charHeight = fontMetrics().height(); _xPosAdr = 0; if (_addressArea) _xPosHex = _xData.realAddressNumbers()*_charWidth + GAP_ADR_HEX; else _xPosHex = 0; _xPosAscii = _xPosHex + HEXCHARS_IN_LINE * _charWidth + GAP_HEX_ASCII; // tell QAbstractScollbar, how big we are setMinimumHeight(((_xData.size()/16 + 1) * _charHeight) + 5); setMinimumWidth(_xPosAscii + (BYTES_PER_LINE * _charWidth)); update(); } ostinato-0.5.1/extra/qhexedit2/src/qhexedit_p.h0000700000175300010010000000653712005505615021016 0ustar srivatspNone#ifndef QHEXEDIT_P_H #define QHEXEDIT_P_H /** \cond docNever */ #include #include "xbytearray.h" class QHexEditPrivate : public QWidget { Q_OBJECT public: QHexEditPrivate(QScrollArea *parent); void setAddressAreaColor(QColor const &color); QColor addressAreaColor(); void setAddressOffset(int offset); int addressOffset(); void setCursorPos(int position); int cursorPos(); void setData(QByteArray const &data); QByteArray data(); void setHighlightingColor(QColor const &color); QColor highlightingColor(); void setOverwriteMode(bool overwriteMode); bool overwriteMode(); void setReadOnly(bool readOnly); bool isReadOnly(); void setSelectionColor(QColor const &color); QColor selectionColor(); XByteArray & xData(); void insert(int index, const QByteArray & ba); void insert(int index, char ch); void remove(int index, int len=1); void replace(int index, char ch); void replace(int index, const QByteArray & ba); void setAddressArea(bool addressArea); void setAddressWidth(int addressWidth); void setAsciiArea(bool asciiArea); void setHighlighting(bool mode); virtual void setFont(const QFont &font); void undo(); void redo(); QString toRedableString(); QString selectionToReadableString(); signals: void currentAddressChanged(int address); void currentSizeChanged(int size); void dataChanged(); void overwriteModeChanged(bool state); protected: void keyPressEvent(QKeyEvent * event); void mouseMoveEvent(QMouseEvent * event); void mousePressEvent(QMouseEvent * event); void paintEvent(QPaintEvent *event); int cursorPos(QPoint pos); // calc cursorpos from graphics position. DOES NOT STORE POSITION void resetSelection(int pos); void setSelection(int pos); // set min (if below init) or max (if greater init) int getSelectionBegin(); int getSelectionEnd(); private slots: void updateCursor(); private: void adjust(); QColor _addressAreaColor; QColor _highlightingColor; QColor _selectionColor; QScrollArea *_scrollArea; QTimer _cursorTimer; QUndoStack *_undoStack; XByteArray _xData; // Hält den Inhalt des Hex Editors bool _blink; // true: then cursor blinks bool _renderingRequired; // Flag to store that rendering is necessary bool _addressArea; // left area of QHexEdit bool _asciiArea; // medium area bool _highlighting; // highlighting of changed bytes bool _overwriteMode; bool _readOnly; // true: the user can only look and navigate int _charWidth, _charHeight; // char dimensions (dpendend on font) int _cursorX, _cursorY; // graphics position of the cursor int _cursorPosition; // charakter positioin in stream (on byte ends in to steps) int _xPosAdr, _xPosHex, _xPosAscii; // graphics x-position of the areas int _selectionBegin; // First selected char int _selectionEnd; // Last selected char int _selectionInit; // That's, where we pressed the mouse button int _size; }; /** \endcond docNever */ #endif ostinato-0.5.1/extra/qhexedit2/src/xbytearray.cpp0000700000175300010010000000674112005505615021406 0ustar srivatspNone#include "xbytearray.h" XByteArray::XByteArray() { _oldSize = -99; _addressNumbers = 4; _addressOffset = 0; } int XByteArray::addressOffset() { return _addressOffset; } void XByteArray::setAddressOffset(int offset) { _addressOffset = offset; } int XByteArray::addressWidth() { return _addressNumbers; } void XByteArray::setAddressWidth(int width) { if ((width >= 0) and (width<=6)) { _addressNumbers = width; } } QByteArray & XByteArray::data() { return _data; } void XByteArray::setData(QByteArray data) { _data = data; _changedData = QByteArray(data.length(), char(0)); } bool XByteArray::dataChanged(int i) { return bool(_changedData[i]); } QByteArray XByteArray::dataChanged(int i, int len) { return _changedData.mid(i, len); } void XByteArray::setDataChanged(int i, bool state) { _changedData[i] = char(state); } void XByteArray::setDataChanged(int i, const QByteArray & state) { int length = state.length(); int len; if ((i + length) > _changedData.length()) len = _changedData.length() - i; else len = length; _changedData.replace(i, len, state); } int XByteArray::realAddressNumbers() { if (_oldSize != _data.size()) { // is addressNumbers wide enought? QString test = QString("%1") .arg(_data.size() + _addressOffset, _addressNumbers, 16, QChar('0')); _realAddressNumbers = test.size(); } return _realAddressNumbers; } int XByteArray::size() { return _data.size(); } QByteArray & XByteArray::insert(int i, char ch) { _data.insert(i, ch); _changedData.insert(i, char(1)); return _data; } QByteArray & XByteArray::insert(int i, const QByteArray & ba) { _data.insert(i, ba); _changedData.insert(i, QByteArray(ba.length(), char(1))); return _data; } QByteArray & XByteArray::remove(int i, int len) { _data.remove(i, len); _changedData.remove(i, len); return _data; } QByteArray & XByteArray::replace(int index, char ch) { _data[index] = ch; _changedData[index] = char(1); return _data; } QByteArray & XByteArray::replace(int index, const QByteArray & ba) { int len = ba.length(); return replace(index, len, ba); } QByteArray & XByteArray::replace(int index, int length, const QByteArray & ba) { int len; if ((index + length) > _data.length()) len = _data.length() - index; else len = length; _data.replace(index, len, ba.mid(0, len)); _changedData.replace(index, len, QByteArray(len, char(1))); return _data; } QChar XByteArray::asciiChar(int index) { char ch = _data[index]; if ((ch < 0x20) or (ch > 0x7e)) ch = '.'; return QChar(ch); } QString XByteArray::toRedableString(int start, int end) { int adrWidth = realAddressNumbers(); if (_addressNumbers > adrWidth) adrWidth = _addressNumbers; if (end < 0) end = _data.size(); QString result; for (int i=start; i < end; i += 16) { QString adrStr = QString("%1").arg(_addressOffset + i, adrWidth, 16, QChar('0')); QString hexStr; QString ascStr; for (int j=0; j<16; j++) { if ((i + j) < _data.size()) { hexStr.append(" ").append(_data.mid(i+j, 1).toHex()); ascStr.append(asciiChar(i+j)); } } result += adrStr + " " + QString("%1").arg(hexStr, -48) + " " + QString("%1").arg(ascStr, -17) + "\n"; } return result; } ostinato-0.5.1/extra/qhexedit2/src/xbytearray.h0000700000175300010010000000346612005505615021054 0ustar srivatspNone#ifndef XBYTEARRAY_H #define XBYTEARRAY_H /** \cond docNever */ #include /*! XByteArray represents the content of QHexEcit. XByteArray comprehend the data itself and informations to store if it was changed. The QHexEdit component uses these informations to perform nice rendering of the data XByteArray also provides some functionality to insert, replace and remove single chars and QByteArras. Additionally some functions support rendering and converting to readable strings. */ class XByteArray { public: explicit XByteArray(); int addressOffset(); void setAddressOffset(int offset); int addressWidth(); void setAddressWidth(int width); QByteArray & data(); void setData(QByteArray data); bool dataChanged(int i); QByteArray dataChanged(int i, int len); void setDataChanged(int i, bool state); void setDataChanged(int i, const QByteArray & state); int realAddressNumbers(); int size(); QByteArray & insert(int i, char ch); QByteArray & insert(int i, const QByteArray & ba); QByteArray & remove(int pos, int len); QByteArray & replace(int index, char ch); QByteArray & replace(int index, const QByteArray & ba); QByteArray & replace(int index, int length, const QByteArray & ba); QChar asciiChar(int index); QString toRedableString(int start=0, int end=-1); signals: public slots: private: QByteArray _data; QByteArray _changedData; int _addressNumbers; // wanted width of address area int _addressOffset; // will be added to the real addres inside bytearray int _realAddressNumbers; // real width of address area (can be greater then wanted width) int _oldSize; // size of data }; /** \endcond docNever */ #endif // XBYTEARRAY_H ostinato-0.5.1/install.pri0000700000175300010010000000055112005505615015054 0ustar srivatspNone# A custom install path prefix can be provided by passing PREFIX=/absolute/path # to qmake; if one is not provided, we use the below defaults - isEmpty(PREFIX) { unix:PREFIX = "/usr/local/" macx:PREFIX = "/Applications/" win32:PREFIX = "../" } macx { target.path = $$PREFIX/Ostinato } else { target.path = $$PREFIX/bin } INSTALLS += target ostinato-0.5.1/ost.pro0000700000175300010010000000023212005505615014215 0ustar srivatspNoneTEMPLATE = subdirs CONFIG += ordered SUBDIRS = \ extra \ rpc/pbrpc.pro \ common/ostproto.pro \ server/drone.pro \ client/ostinato.pro ostinato-0.5.1/protobuf.pri0000700000175300010010000000211112005505615015240 0ustar srivatspNone# # Qt qmake integration with Google Protocol Buffers compiler protoc # # To compile protocol buffers with qt qmake, specify PROTOS variable and # include this file # # Example: # PROTOS = a.proto b.proto # include(protobuf.pri) # # By default protoc looks for .proto files (including the imported ones) in # the current directory where protoc is run. If you need to include additional # paths specify the PROTOPATH variable # PROTOPATH += . PROTOPATHS = for(p, PROTOPATH):PROTOPATHS += --proto_path=$${p} protobuf_decl.name = protobuf header protobuf_decl.input = PROTOS protobuf_decl.output = ${QMAKE_FILE_BASE}.pb.h protobuf_decl.commands = protoc --cpp_out="." $${PROTOPATHS} ${QMAKE_FILE_NAME} protobuf_decl.variable_out = GENERATED_FILES QMAKE_EXTRA_COMPILERS += protobuf_decl protobuf_impl.name = protobuf implementation protobuf_impl.input = PROTOS protobuf_impl.output = ${QMAKE_FILE_BASE}.pb.cc protobuf_impl.depends = ${QMAKE_FILE_BASE}.pb.h protobuf_impl.commands = $$escape_expand(\n) protobuf_impl.variable_out = GENERATED_SOURCES QMAKE_EXTRA_COMPILERS += protobuf_impl ostinato-0.5.1/rpc/0000700000175300010010000000000012005505615013452 5ustar srivatspNoneostinato-0.5.1/rpc/pbhelper.h0000700000175300010010000001311712005505615015432 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PB_HELPER_H #define _PB_HELPER_H #include #include #include #if 0 // not reqd. any longer? class PbHelper { public: // FIXME: Change msg from * to & void ForceSetSingularDefault(::google::protobuf::Message *msg) { const ::google::protobuf::Descriptor *desc; ::google::protobuf::Message::Reflection *refl; qDebug("In %s", __FUNCTION__); desc = msg->GetDescriptor(); refl = msg->GetReflection(); for (int i=0; i < desc->field_count(); i++) { const ::google::protobuf::FieldDescriptor *f; f = desc->field(i); // Ensure field is singular and not already set if (f->label() == ::google::protobuf::FieldDescriptor::LABEL_REPEATED) continue; if (refl->HasField(f)) continue; switch(f->type()) { case ::google::protobuf::FieldDescriptor::TYPE_DOUBLE: refl->SetDouble(f, refl->GetDouble(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_FLOAT: refl->SetFloat(f, refl->GetFloat(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_INT32: case ::google::protobuf::FieldDescriptor::TYPE_SINT32: case ::google::protobuf::FieldDescriptor::TYPE_SFIXED32: refl->SetInt32(f, refl->GetInt32(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_INT64: case ::google::protobuf::FieldDescriptor::TYPE_SINT64: case ::google::protobuf::FieldDescriptor::TYPE_SFIXED64: refl->SetInt64(f, refl->GetInt64(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_UINT32: case ::google::protobuf::FieldDescriptor::TYPE_FIXED32: refl->SetUInt32(f, refl->GetUInt32(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_UINT64: case ::google::protobuf::FieldDescriptor::TYPE_FIXED64: refl->SetUInt64(f, refl->GetUInt64(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_BOOL: refl->SetBool(f, refl->GetBool(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_ENUM: refl->SetEnum(f, refl->GetEnum(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_STRING: case ::google::protobuf::FieldDescriptor::TYPE_BYTES: refl->SetString(f, refl->GetString(f)); break; case ::google::protobuf::FieldDescriptor::TYPE_MESSAGE: case ::google::protobuf::FieldDescriptor::TYPE_GROUP: ForceSetSingularDefault(refl->MutableMessage(f)); // recursion! break; default: qDebug("unhandled Field Type"); break; } } } bool update( ::google::protobuf::Message *target, ::google::protobuf::Message *source) { // FIXME(HI): Depracate: use MergeFrom() directly qDebug("In %s", __FUNCTION__); target->MergeFrom(*source); return true; #if 0 ::google::protobuf::Message::Reflection *sourceRef; ::google::protobuf::Message::Reflection *targetRef; std::vector srcFieldList; if (source->GetDescriptor()->full_name() != target->GetDescriptor()->full_name()) goto _error_exit; sourceRef = source->GetReflection(); targetRef = target->GetReflection(); sourceRef->ListFields(&srcFieldList); for (uint i=0; i < srcFieldList.size(); i++) { const ::google::protobuf::FieldDescriptor *srcField, *targetField; srcField = srcFieldList[i]; targetField = target->GetDescriptor()->FindFieldByName( srcField->name()); switch(targetField->type()) { case ::google::protobuf::FieldDescriptor::TYPE_UINT32: targetRef->SetUInt32(targetField, sourceRef->GetUInt32(srcField)); break; case ::google::protobuf::FieldDescriptor::TYPE_BOOL: targetRef->SetBool(targetField, sourceRef->GetBool(srcField)); break; case ::google::protobuf::FieldDescriptor::TYPE_STRING: targetRef->SetString(targetField, sourceRef->GetString(srcField)); break; default: qDebug("unhandled Field Type"); break; } } _error_exit: qDebug("%s: error!", __FUNCTION__); return false; #endif } }; #endif #endif ostinato-0.5.1/rpc/pbqtio.h0000700000175300010010000000170512005505615015127 0ustar srivatspNone#ifndef _PBQTIO_H #define _PBQTIO_H #include class PbQtInputStream : public google::protobuf::io::CopyingInputStream { public: PbQtInputStream(QIODevice *dev) : dev_(dev) {}; int Read(void *buffer, int size) { _top: if (dev_->bytesAvailable()) return dev_->read(static_cast(buffer), size); else if (dev_->waitForReadyRead(-1)) goto _top; else return -1; //return dev_->atEnd() ? 0 : -1; } private: QIODevice *dev_; }; class PbQtOutputStream : public google::protobuf::io::CopyingOutputStream { public: PbQtOutputStream(QIODevice *dev) : dev_(dev) {}; bool Write(const void *buffer, int size) { if (dev_->write(static_cast(buffer), size) == size) return true; else return false; } private: QIODevice *dev_; }; #endif ostinato-0.5.1/rpc/pbrpc.pro0000700000175300010010000000031112005505615015300 0ustar srivatspNoneTEMPLATE = lib CONFIG += qt staticlib QT += network DEFINES += HAVE_REMOTE LIBS += -lprotobuf HEADERS += rpcserver.h pbrpccontroller.h pbrpcchannel.h pbqtio.h SOURCES += rpcserver.cpp pbrpcchannel.cpp ostinato-0.5.1/rpc/pbrpcchannel.cpp0000700000175300010010000002177212005505615016631 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pbrpcchannel.h" #include "pbqtio.h" #include PbRpcChannel::PbRpcChannel(QHostAddress ip, quint16 port) { isPending = false; pendingMethodId = -1; // don't care as long as isPending is false controller = NULL; done = NULL; response = NULL; mServerAddress = ip; mServerPort = port; mpSocket = new QTcpSocket(this); inStream = new google::protobuf::io::CopyingInputStreamAdaptor( new PbQtInputStream(mpSocket)); inStream->SetOwnsCopyingStream(true); outStream = new google::protobuf::io::CopyingOutputStreamAdaptor( new PbQtOutputStream(mpSocket)); outStream->SetOwnsCopyingStream(true); // FIXME: Not quite sure why this ain't working! // QMetaObject::connectSlotsByName(this); connect(mpSocket, SIGNAL(connected()), this, SLOT(on_mpSocket_connected())); connect(mpSocket, SIGNAL(disconnected()), this, SLOT(on_mpSocket_disconnected())); connect(mpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(on_mpSocket_stateChanged(QAbstractSocket::SocketState))); connect(mpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_mpSocket_error(QAbstractSocket::SocketError))); connect(mpSocket, SIGNAL(readyRead()), this, SLOT(on_mpSocket_readyRead())); } PbRpcChannel::~PbRpcChannel() { delete inStream; delete outStream; delete mpSocket; } void PbRpcChannel::establish() { qDebug("In %s", __FUNCTION__); mpSocket->connectToHost(mServerAddress, mServerPort); } void PbRpcChannel::establish(QHostAddress ip, quint16 port) { mServerAddress = ip; mServerPort = port; establish(); } void PbRpcChannel::tearDown() { qDebug("In %s", __FUNCTION__); mpSocket->disconnectFromHost(); } void PbRpcChannel::CallMethod( const ::google::protobuf::MethodDescriptor *method, ::google::protobuf::RpcController *controller, const ::google::protobuf::Message *req, ::google::protobuf::Message *response, ::google::protobuf::Closure* done) { char msgBuf[PB_HDR_SIZE]; char* const msg = &msgBuf[0]; int len; bool ret; if (isPending) { RpcCall call; qDebug("RpcChannel: queueing method %d since %d is pending; " "queued message = <%s>", method->index(), pendingMethodId, req->DebugString().c_str()); call.method = method; call.controller = controller; call.request = req; call.response = response; call.done = done; pendingCallList.append(call); qDebug("pendingCallList size = %d", pendingCallList.size()); Q_ASSERT(pendingCallList.size() < 100); return; } if (!req->IsInitialized()) { qWarning("RpcChannel: missing required fields in request"); qDebug("%s", req->InitializationErrorString().c_str()); qFatal("exiting"); controller->SetFailed("Required fields missing"); done->Run(); return; } pendingMethodId = method->index(); this->controller=controller; this->done=done; this->response=response; isPending = true; len = req->ByteSize(); *((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_REQUEST)); // type *((quint16*)(msg+2)) = qToBigEndian(quint16(method->index())); // method id *((quint32*)(msg+4)) = qToBigEndian(quint32(len)); // len // Avoid printing stats since it happens every couple of seconds if (pendingMethodId != 13) { qDebug("client(%s) sending %d bytes encoding <%s>", __FUNCTION__, PB_HDR_SIZE + len, req->DebugString().c_str()); BUFDUMP(msg, PB_HDR_SIZE); } mpSocket->write(msg, PB_HDR_SIZE); ret = req->SerializeToZeroCopyStream(outStream); Q_ASSERT(ret == true); outStream->Flush(); } void PbRpcChannel::on_mpSocket_readyRead() { uchar msg[PB_HDR_SIZE]; uchar *p = (uchar*) &msg; int msgLen; static bool parsing = false; static quint16 type, method; static quint32 len; //qDebug("%s: bytesAvail = %d", __FUNCTION__, mpSocket->bytesAvailable()); if (!parsing) { // Do we have an entire header? If not, we'll wait ... if (mpSocket->bytesAvailable() < PB_HDR_SIZE) { qDebug("client: not enough data available for a complete header"); return; } msgLen = mpSocket->read((char*)msg, PB_HDR_SIZE); Q_ASSERT(msgLen == PB_HDR_SIZE); type = qFromBigEndian(p+0); method = qFromBigEndian(p+2); len = qFromBigEndian(p+4); //BUFDUMP(msg, PB_HDR_SIZE); //qDebug("type = %hu, method = %hu, len = %u", type, method, len); parsing = true; } switch (type) { case PB_MSG_TYPE_BINBLOB: { static quint32 cumLen = 0; QIODevice *blob; blob = static_cast(controller)->binaryBlob(); Q_ASSERT(blob != NULL); while ((cumLen < len) && mpSocket->bytesAvailable()) { int l; l = mpSocket->read((char*)msg, sizeof(msg)); blob->write((char*)msg, l); cumLen += l; } qDebug("%s: bin blob rcvd %d/%d", __PRETTY_FUNCTION__, cumLen, len); if (cumLen < len) return; cumLen = 0; if (!isPending) { qDebug("not waiting for response"); goto _error_exit2; } if (pendingMethodId != method) { qDebug("invalid method id %d (expected = %d)", method, pendingMethodId); goto _error_exit2; } break; } case PB_MSG_TYPE_RESPONSE: //qDebug("client(%s) rcvd %d bytes", __FUNCTION__, msgLen); //BUFDUMP(msg, msgLen); if (!isPending) { qDebug("not waiting for response"); goto _error_exit; } if (pendingMethodId != method) { qDebug("invalid method id %d (expected = %d)", method, pendingMethodId); goto _error_exit; } if (len) response->ParseFromBoundedZeroCopyStream(inStream, len); // Avoid printing stats if (method != 13) { qDebug("client(%s): Parsed as %s", __FUNCTION__, response->DebugString().c_str()); } if (!response->IsInitialized()) { qWarning("RpcChannel: missing required fields in response"); qDebug("%s", response->InitializationErrorString().c_str()); controller->SetFailed("Required fields missing"); } break; default: qFatal("%s: unexpected type %d", __PRETTY_FUNCTION__, type); goto _error_exit; } done->Run(); pendingMethodId = -1; controller = NULL; response = NULL; isPending = false; parsing = false; if (pendingCallList.size()) { RpcCall call = pendingCallList.takeFirst(); qDebug("RpcChannel: executing queued method %d <%s>", call.method->index(), call.request->DebugString().c_str()); CallMethod(call.method, call.controller, call.request, call.response, call.done); } return; _error_exit: inStream->Skip(len); _error_exit2: parsing = false; qDebug("client(%s) discarding received msg", __FUNCTION__); return; } void PbRpcChannel::on_mpSocket_stateChanged( QAbstractSocket::SocketState socketState) { qDebug("In %s", __FUNCTION__); emit stateChanged(socketState); } void PbRpcChannel::on_mpSocket_connected() { qDebug("In %s", __FUNCTION__); emit connected(); } void PbRpcChannel::on_mpSocket_disconnected() { qDebug("In %s", __FUNCTION__); pendingMethodId = -1; controller = NULL; response = NULL; isPending = false; // \todo convert parsing from static to data member //parsing = false pendingCallList.clear(); emit disconnected(); } void PbRpcChannel::on_mpSocket_error(QAbstractSocket::SocketError socketError) { qDebug("In %s", __FUNCTION__); emit error(socketError); } ostinato-0.5.1/rpc/pbrpcchannel.h0000700000175300010010000000700412005505615016266 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PB_RPC_CHANNEL_H #define _PB_RPC_CHANNEL_H #include #include #include #include #include #include #include "pbrpccommon.h" #include "pbrpccontroller.h" class PbRpcChannel : public QObject, public ::google::protobuf::RpcChannel { Q_OBJECT // If isPending is TRUE, then controller, done, response // and pendingMethodId correspond to the last method called by // the service stub bool isPending; int pendingMethodId; // controller, done, response are set to the corresponding values // passed by the stub to CallMethod(). They are reset to NULL when // we get a response back from the server in on_mpSocket_readyRead() // after calling done->Run(). /*! \todo (MED) : change controller, done and response to references instead of pointers? */ ::google::protobuf::RpcController *controller; ::google::protobuf::Closure *done; ::google::protobuf::Message *response; typedef struct _RpcCall { const ::google::protobuf::MethodDescriptor *method; ::google::protobuf::RpcController *controller; const ::google::protobuf::Message *request; ::google::protobuf::Message *response; ::google::protobuf::Closure *done; } RpcCall; QList pendingCallList; QHostAddress mServerAddress; quint16 mServerPort; QTcpSocket *mpSocket; ::google::protobuf::io::CopyingInputStreamAdaptor *inStream; ::google::protobuf::io::CopyingOutputStreamAdaptor *outStream; public: PbRpcChannel(QHostAddress ip, quint16 port); ~PbRpcChannel(); void establish(); void establish(QHostAddress ip, quint16 port); void tearDown(); const QHostAddress& serverAddress() const { return mServerAddress; } quint16 serverPort() const { return mServerPort; } QAbstractSocket::SocketState state() const { return mpSocket->state(); } void CallMethod(const ::google::protobuf::MethodDescriptor *method, ::google::protobuf::RpcController *controller, const ::google::protobuf::Message *req, ::google::protobuf::Message *response, ::google::protobuf::Closure* done); signals: void connected(); void disconnected(); void error(QAbstractSocket::SocketError socketError); void stateChanged(QAbstractSocket::SocketState socketState); private slots: void on_mpSocket_connected(); void on_mpSocket_disconnected(); void on_mpSocket_stateChanged(QAbstractSocket::SocketState socketState); void on_mpSocket_error(QAbstractSocket::SocketError socketError); void on_mpSocket_readyRead(); }; #endif ostinato-0.5.1/rpc/pbrpccommon.h0000700000175300010010000000214412005505615016146 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PB_RPC_COMMON_H #define _PB_RPC_COMMON_H // Print a HexDump #define BUFDUMP(ptr, len) qDebug("%s", QString(QByteArray((char*)(ptr), \ (len)).toHex()).toAscii().data()); /* ** RPC Header (8) ** - MSG_TYPE (2) ** - METHOD_ID (2) ** - LEN (4) [not including this header] */ #define PB_HDR_SIZE 8 #define PB_MSG_TYPE_REQUEST 1 #define PB_MSG_TYPE_RESPONSE 2 #define PB_MSG_TYPE_BINBLOB 3 #endif ostinato-0.5.1/rpc/pbrpccontroller.h0000700000175300010010000000420512005505615017041 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PB_RPC_CONTROLLER_H #define _PB_RPC_CONTROLLER_H #include class QIODevice; /*! PbRpcController takes ownership of the 'request' and 'response' messages and will delete them when it itself is destroyed */ class PbRpcController : public ::google::protobuf::RpcController { public: PbRpcController(::google::protobuf::Message *request, ::google::protobuf::Message *response) { request_ = request; response_ = response; Reset(); } ~PbRpcController() { delete request_; delete response_; } ::google::protobuf::Message* request() { return request_; } ::google::protobuf::Message* response() { return response_; } // Client Side Methods void Reset() { failed = false; blob = NULL; } bool Failed() const { return failed; } void StartCancel() { /*! \todo (MED) */} std::string ErrorText() const { return errStr; } // Server Side Methods void SetFailed(const std::string &reason) { failed = true; errStr = reason; } bool IsCanceled() const { return false; }; void NotifyOnCancel(::google::protobuf::Closure* /* callback */) { /*! \todo (MED) */ } // srivatsp added QIODevice* binaryBlob() { return blob; }; void setBinaryBlob(QIODevice *binaryBlob) { blob = binaryBlob; }; private: bool failed; QIODevice *blob; std::string errStr; ::google::protobuf::Message *request_; ::google::protobuf::Message *response_; }; #endif ostinato-0.5.1/rpc/rpcserver.cpp0000700000175300010010000001745412005505615016207 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ //#include "pbhelper.h" #include "rpcserver.h" #include "pbqtio.h" #include RpcServer::RpcServer() { server = NULL; clientSock = NULL; service = NULL; inStream = NULL; outStream = NULL; isPending = false; pendingMethodId = -1; // don't care as long as isPending is false } RpcServer::~RpcServer() { if (server) delete server; } bool RpcServer::registerService(::google::protobuf::Service *service, quint16 tcpPortNum) { this->service = service; server = new QTcpServer(); connect(server, SIGNAL(newConnection()), this, SLOT(when_newConnection())); if (!server->listen(QHostAddress::Any, tcpPortNum)) { qDebug("Unable to start the server: %s", server->errorString().toAscii().constData()); errorString_ = QString("Error starting Ostinato server: %1").arg( server->errorString()); return false; } qDebug("The server is running on %s: %d", server->serverAddress().toString().toAscii().constData(), server->serverPort()); errorString_ = QString(); return true; } QString RpcServer::errorString() { return errorString_; } void RpcServer::done(PbRpcController *controller) { google::protobuf::Message *response = controller->response(); QIODevice *blob; char msgBuf[PB_HDR_SIZE]; char* const msg = &msgBuf[0]; int len; //qDebug("In RpcServer::done"); if (controller->Failed()) { qDebug("rpc failed"); goto _exit; } blob = controller->binaryBlob(); if (blob) { len = blob->size(); qDebug("is binary blob of len %d", len); *((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_BINBLOB)); // type *((quint16*)(msg+2)) = qToBigEndian(quint16(pendingMethodId)); // method (*(quint32*)(msg+4)) = qToBigEndian(quint32(len)); // len clientSock->write(msg, PB_HDR_SIZE); blob->seek(0); while (!blob->atEnd()) { int l; len = blob->read(msg, sizeof(msgBuf)); l = clientSock->write(msg, len); Q_ASSERT(l == len); } goto _exit; } if (!response->IsInitialized()) { qWarning("response missing required fields!!"); qDebug("%s", response->InitializationErrorString().c_str()); qFatal("exiting"); goto _exit; } len = response->ByteSize(); *((quint16*)(msg+0)) = qToBigEndian(quint16(PB_MSG_TYPE_RESPONSE)); // type *((quint16*)(msg+2)) = qToBigEndian(quint16(pendingMethodId)); // method *((quint32*)(msg+4)) = qToBigEndian(quint32(len)); // len // Avoid printing stats since it happens once every couple of seconds if (pendingMethodId != 13) { qDebug("Server(%s): sending %d bytes to client encoding <%s>", __FUNCTION__, len + PB_HDR_SIZE, response->DebugString().c_str()); //BUFDUMP(msg, len + 8); } clientSock->write(msg, PB_HDR_SIZE); response->SerializeToZeroCopyStream(outStream); outStream->Flush(); _exit: delete controller; isPending = false; } void RpcServer::when_newConnection() { if (clientSock) { QTcpSocket *sock; qDebug("already connected, no new connections will be accepted"); // Accept and close connection //! \todo (MED) Send reason msg to client sock = server->nextPendingConnection(); sock->disconnectFromHost(); sock->deleteLater(); goto _exit; } clientSock = server->nextPendingConnection(); qDebug("accepting new connection from %s: %d", clientSock->peerAddress().toString().toAscii().constData(), clientSock->peerPort()); inStream = new google::protobuf::io::CopyingInputStreamAdaptor( new PbQtInputStream(clientSock)); inStream->SetOwnsCopyingStream(true); outStream = new google::protobuf::io::CopyingOutputStreamAdaptor( new PbQtOutputStream(clientSock)); outStream->SetOwnsCopyingStream(true); 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 RpcServer::when_disconnected() { qDebug("connection closed from %s: %d", clientSock->peerAddress().toString().toAscii().constData(), clientSock->peerPort()); delete inStream; delete outStream; clientSock->deleteLater(); clientSock = NULL; } void RpcServer::when_error(QAbstractSocket::SocketError socketError) { qDebug("%s (%d)", clientSock->errorString().toAscii().constData(), socketError); } void RpcServer::when_dataAvail() { uchar msg[PB_HDR_SIZE]; int msgLen; static bool parsing = false; static quint16 type, method; static quint32 len; const ::google::protobuf::MethodDescriptor *methodDesc; ::google::protobuf::Message *req, *resp; PbRpcController *controller; if (!parsing) { if (clientSock->bytesAvailable() < PB_HDR_SIZE) return; msgLen = clientSock->read((char*)msg, PB_HDR_SIZE); Q_ASSERT(msgLen == PB_HDR_SIZE); type = qFromBigEndian(&msg[0]); method = qFromBigEndian(&msg[2]); len = qFromBigEndian(&msg[4]); //qDebug("type = %d, method = %d, len = %d", type, method, len); parsing = true; } if (type != PB_MSG_TYPE_REQUEST) { qDebug("server(%s): unexpected msg type %d (expected %d)", __FUNCTION__, type, PB_MSG_TYPE_REQUEST); goto _error_exit; } methodDesc = service->GetDescriptor()->method(method); if (!methodDesc) { qDebug("server(%s): invalid method id %d", __FUNCTION__, method); goto _error_exit; //! \todo Return Error to client } if (isPending) { qDebug("server(%s): rpc pending, try again", __FUNCTION__); goto _error_exit; //! \todo Return Error to client } pendingMethodId = method; isPending = true; req = service->GetRequestPrototype(methodDesc).New(); resp = service->GetResponsePrototype(methodDesc).New(); if (len) req->ParseFromBoundedZeroCopyStream(inStream, len); if (!req->IsInitialized()) { qWarning("Missing required fields in request"); qDebug("%s", req->InitializationErrorString().c_str()); qFatal("exiting"); delete req; delete resp; goto _error_exit2; } //qDebug("Server(%s): successfully parsed as <%s>", __FUNCTION__, //resp->DebugString().c_str()); controller = new PbRpcController(req, resp); //qDebug("before service->callmethod()"); service->CallMethod(methodDesc, controller, req, resp, google::protobuf::NewCallback(this, &RpcServer::done, controller)); parsing = false; return; _error_exit: inStream->Skip(len); _error_exit2: parsing = false; qDebug("server(%s): discarding msg from client", __FUNCTION__); return; } ostinato-0.5.1/rpc/rpcserver.h0000700000175300010010000000335512005505615015647 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _RPC_SERVER_H #define _RPC_SERVER_H #include #include #include #include #include #include #include "pbrpccommon.h" #include "pbrpccontroller.h" class RpcServer : public QObject { Q_OBJECT QTcpServer *server; QTcpSocket *clientSock; ::google::protobuf::Service *service; ::google::protobuf::io::CopyingInputStreamAdaptor *inStream; ::google::protobuf::io::CopyingOutputStreamAdaptor *outStream; bool isPending; int pendingMethodId; QString errorString_; public: RpcServer(); //! \todo (LOW) use 'parent' param virtual ~RpcServer(); bool registerService(::google::protobuf::Service *service, quint16 tcpPortNum); QString errorString(); void done(PbRpcController *controller); private slots: void when_newConnection(); void when_disconnected(); void when_dataAvail(); void when_error(QAbstractSocket::SocketError socketError); }; #endif ostinato-0.5.1/server/0000700000175300010010000000000012005505615014174 5ustar srivatspNoneostinato-0.5.1/server/abstractport.cpp0000700000175300010010000004356512005505615017430 0ustar srivatspNone/* Copyright (C) 2010-2012 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #define __STDC_FORMAT_MACROS #include "abstractport.h" #include "../common/streambase.h" #include "../common/abstractprotocol.h" #include #include #include #include #include AbstractPort::AbstractPort(int id, const char *device) { isUsable_ = true; data_.mutable_port_id()->set_id(id); data_.set_name(device); //! \todo (LOW) admin enable/disable of port data_.set_is_enabled(true); data_.set_is_exclusive_control(false); isSendQueueDirty_ = false; linkState_ = OstProto::LinkStateUnknown; minPacketSetSize_ = 1; maxStatsValue_ = ULLONG_MAX; // assume 64-bit stats memset((void*) &stats_, 0, sizeof(stats_)); resetStats(); } AbstractPort::~AbstractPort() { } void AbstractPort::init() { } bool AbstractPort::modify(const OstProto::Port &port) { bool ret = false; //! \todo Use reflection to find out which fields are set if (port.has_is_exclusive_control()) { bool val = port.is_exclusive_control(); ret = setExclusiveControl(val); if (ret) data_.set_is_exclusive_control(val); } if (port.has_transmit_mode()) data_.set_transmit_mode(port.transmit_mode()); return ret; } StreamBase* AbstractPort::streamAtIndex(int index) { Q_ASSERT(index < streamList_.size()); return streamList_.at(index); } StreamBase* AbstractPort::stream(int streamId) { for (int i = 0; i < streamList_.size(); i++) { if ((uint)streamId == streamList_.at(i)->id()) return streamList_.at(i); } return NULL; } bool AbstractPort::addStream(StreamBase *stream) { streamList_.append(stream); isSendQueueDirty_ = true; return true; } bool AbstractPort::deleteStream(int streamId) { for (int i = 0; i < streamList_.size(); i++) { StreamBase *stream; if ((uint)streamId == streamList_.at(i)->id()) { stream = streamList_.takeAt(i); delete stream; isSendQueueDirty_ = true; return true; } } return false; } void AbstractPort::addNote(QString note) { QString notes = QString::fromStdString(data_.notes()); note.prepend("
  • "); note.append("
  • "); if (notes.isEmpty()) notes="Limitation(s)
      "; else notes.remove("
    "); notes.append(note); notes.append(""); data_.set_notes(notes.toStdString()); } void AbstractPort::updatePacketList() { switch(data_.transmit_mode()) { case OstProto::kSequentialTransmit: updatePacketListSequential(); break; case OstProto::kInterleavedTransmit: updatePacketListInterleaved(); break; default: Q_ASSERT(false); // Unreachable!!! break; } } void AbstractPort::updatePacketListSequential() { long sec = 0; long nsec = 0; qDebug("In %s", __FUNCTION__); // First sort the streams by ordinalValue qSort(streamList_.begin(), streamList_.end(), StreamBase::StreamLessThan); clearPacketList(); for (int i = 0; i < streamList_.size(); i++) { if (streamList_[i]->isEnabled()) { int len; ulong n, x, y; ulong burstSize; double ibg = 0; quint64 ibg1 = 0, ibg2 = 0; quint64 nb1 = 0, nb2 = 0; double ipg = 0; quint64 ipg1 = 0, ipg2 = 0; quint64 npx1 = 0, npx2 = 0; quint64 npy1 = 0, npy2 = 0; quint64 loopDelay; ulong frameVariableCount = streamList_[i]->frameVariableCount(); // We derive n, x, y such that // n * x + y = total number of packets to be sent switch (streamList_[i]->sendUnit()) { case OstProto::StreamControl::e_su_bursts: burstSize = streamList_[i]->burstSize(); x = AbstractProtocol::lcm(frameVariableCount, burstSize); n = ulong(burstSize * streamList_[i]->burstRate() * streamList_[i]->numBursts()) / x; y = ulong(burstSize * streamList_[i]->burstRate() * streamList_[i]->numBursts()) % x; if (streamList_[i]->burstRate() > 0) { ibg = 1e9/double(streamList_[i]->burstRate()); ibg1 = quint64(ceil(ibg)); ibg2 = quint64(floor(ibg)); nb1 = quint64((ibg - double(ibg2)) * double(x)); nb2 = x - nb1; } loopDelay = ibg2; break; case OstProto::StreamControl::e_su_packets: x = frameVariableCount; n = 2; while (x < minPacketSetSize_) x = frameVariableCount*n++; n = streamList_[i]->numPackets() / x; y = streamList_[i]->numPackets() % x; burstSize = x + y; if (streamList_[i]->packetRate() > 0) { ipg = 1e9/double(streamList_[i]->packetRate()); ipg1 = quint64(ceil(ipg)); ipg2 = quint64(floor(ipg)); npx1 = quint64((ipg - double(ipg2)) * double(x)); npx2 = x - npx1; npy1 = quint64((ipg - double(ipg2)) * double(y)); npy2 = y - npy1; } loopDelay = ipg2; break; default: qWarning("Unhandled stream control unit %d", streamList_[i]->sendUnit()); continue; } qDebug("\nframeVariableCount = %lu", frameVariableCount); qDebug("n = %lu, x = %lu, y = %lu, burstSize = %lu", n, x, y, burstSize); qDebug("ibg = %g", ibg); qDebug("ibg1 = %" PRIu64, ibg1); qDebug("nb1 = %" PRIu64, nb1); qDebug("ibg2 = %" PRIu64, ibg2); qDebug("nb2 = %" PRIu64 "\n", nb2); qDebug("ipg = %g", ipg); qDebug("ipg1 = %" PRIu64, ipg1); qDebug("npx1 = %" PRIu64, npx1); qDebug("npy1 = %" PRIu64, npy1); qDebug("ipg2 = %" PRIu64, ipg2); qDebug("npx2 = %" PRIu64, npx2); qDebug("npy2 = %" PRIu64 "\n", npy2); if (n > 1) loopNextPacketSet(x, n, 0, loopDelay); else if (n == 0) x = 0; for (uint j = 0; j < (x+y); j++) { if (j == 0 || frameVariableCount > 1) { len = streamList_[i]->frameValue( pktBuf_, sizeof(pktBuf_), j); } if (len <= 0) continue; qDebug("q(%d, %d) sec = %lu nsec = %lu", i, j, sec, nsec); appendToPacketList(sec, nsec, pktBuf_, len); if ((j > 0) && (((j+1) % burstSize) == 0)) { nsec += (j < nb1) ? ibg1 : ibg2; while (nsec >= long(1e9)) { sec++; nsec -= long(1e9); } } else { if (j < x) nsec += (j < npx1) ? ipg1 : ipg2; else nsec += ((j-x) < npy1) ? ipg1 : ipg2; while (nsec >= long(1e9)) { sec++; nsec -= long(1e9); } } } switch(streamList_[i]->nextWhat()) { case ::OstProto::StreamControl::e_nw_stop: goto _stop_no_more_pkts; case ::OstProto::StreamControl::e_nw_goto_id: /*! \todo (MED): define and use streamList_[i].d.control().goto_stream_id(); */ /*! \todo (MED): assumes goto Id is less than current!!!! To support goto to any id, do if goto_id > curr_id then i = goto_id; goto restart; else returnToQIdx = 0; */ setPacketListLoopMode(true, 0, streamList_[i]->sendUnit() == StreamBase::e_su_bursts ? ibg1 : ipg1); goto _stop_no_more_pkts; case ::OstProto::StreamControl::e_nw_goto_next: break; default: qFatal("---------- %s: Unhandled case (%d) -----------", __FUNCTION__, streamList_[i]->nextWhat() ); break; } } // if (stream is enabled) } // for (numStreams) _stop_no_more_pkts: isSendQueueDirty_ = false; } void AbstractPort::updatePacketListInterleaved() { int numStreams = 0; quint64 minGap = ULLONG_MAX; quint64 duration = quint64(1e9); QList ibg1, ibg2; QList nb1, nb2; QList ipg1, ipg2; QList np1, np2; QList schedSec, schedNsec; QList pktCount, burstCount; QList burstSize; QList isVariable; QList pktBuf; QList pktLen; qDebug("In %s", __FUNCTION__); // First sort the streams by ordinalValue qSort(streamList_.begin(), streamList_.end(), StreamBase::StreamLessThan); clearPacketList(); for (int i = 0; i < streamList_.size(); i++) { if (!streamList_[i]->isEnabled()) continue; double numBursts = 0; double numPackets = 0; quint64 _burstSize; double ibg = 0; quint64 _ibg1 = 0, _ibg2 = 0; quint64 _nb1 = 0, _nb2 = 0; double ipg = 0; quint64 _ipg1 = 0, _ipg2 = 0; quint64 _np1 = 0, _np2 = 0; switch (streamList_[i]->sendUnit()) { case OstProto::StreamControl::e_su_bursts: numBursts = streamList_[i]->burstRate(); if (streamList_[i]->burstRate() > 0) { ibg = 1e9/double(streamList_[i]->burstRate()); _ibg1 = quint64(ceil(ibg)); _ibg2 = quint64(floor(ibg)); _nb1 = quint64((ibg - double(_ibg2)) * double(numBursts)); _nb2 = quint64(numBursts) - _nb1; _burstSize = streamList_[i]->burstSize(); } break; case OstProto::StreamControl::e_su_packets: numPackets = streamList_[i]->packetRate(); if (streamList_[i]->packetRate() > 0) { ipg = 1e9/double(streamList_[i]->packetRate()); _ipg1 = llrint(ceil(ipg)); _ipg2 = quint64(floor(ipg)); _np1 = quint64((ipg - double(_ipg2)) * double(numPackets)); _np2 = quint64(numPackets) - _np1; _burstSize = 1; } break; default: qWarning("Unhandled stream control unit %d", streamList_[i]->sendUnit()); continue; } qDebug("numBursts = %g, numPackets = %g\n", numBursts, numPackets); qDebug("ibg = %g", ibg); qDebug("ibg1 = %" PRIu64, _ibg1); qDebug("nb1 = %" PRIu64, _nb1); qDebug("ibg2 = %" PRIu64, _ibg2); qDebug("nb2 = %" PRIu64 "\n", _nb2); qDebug("ipg = %g", ipg); qDebug("ipg1 = %" PRIu64, _ipg1); qDebug("np1 = %" PRIu64, _np1); qDebug("ipg2 = %" PRIu64, _ipg2); qDebug("np2 = %" PRIu64 "\n", _np2); if (_ibg2 && (_ibg2 < minGap)) minGap = _ibg2; if (_ibg1 && (_ibg1 > duration)) duration = _ibg1; ibg1.append(_ibg1); ibg2.append(_ibg2); nb1.append(_nb1); nb2.append(_nb1); burstSize.append(_burstSize); if (_ipg2 && (_ipg2 < minGap)) minGap = _ipg2; if (_np1) { if (_ipg1 && (_ipg1 > duration)) duration = _ipg1; } else { if (_ipg2 && (_ipg2 > duration)) duration = _ipg2; } ipg1.append(_ipg1); ipg2.append(_ipg2); np1.append(_np1); np2.append(_np1); schedSec.append(0); schedNsec.append(0); pktCount.append(0); burstCount.append(0); if (streamList_[i]->isFrameVariable()) { isVariable.append(true); pktBuf.append(QByteArray()); pktLen.append(0); } else { isVariable.append(false); pktBuf.append(QByteArray()); pktBuf.last().resize(kMaxPktSize); pktLen.append(streamList_[i]->frameValue( (uchar*)pktBuf.last().data(), pktBuf.last().size(), 0)); } numStreams++; } // for i qDebug("minGap = %" PRIu64, minGap); qDebug("duration = %" PRIu64, duration); uchar* buf; int len; quint64 durSec = duration/ulong(1e9); quint64 durNsec = duration % ulong(1e9); quint64 sec = 0; quint64 nsec = 0; quint64 lastPktTxSec = 0; quint64 lastPktTxNsec = 0; do { for (int i = 0; i < numStreams; i++) { // If a packet is not scheduled yet, look at the next stream if ((schedSec.at(i) > sec) || (schedNsec.at(i) > nsec)) continue; for (uint j = 0; j < burstSize[i]; j++) { if (isVariable.at(i)) { buf = pktBuf_; len = streamList_[i]->frameValue(pktBuf_, sizeof(pktBuf_), pktCount[i]); } else { buf = (uchar*) pktBuf.at(i).data(); len = pktLen.at(i); } if (len <= 0) continue; qDebug("q(%d) sec = %" PRIu64 " nsec = %" PRIu64, i, sec, nsec); appendToPacketList(sec, nsec, buf, len); lastPktTxSec = sec; lastPktTxNsec = nsec; pktCount[i]++; schedNsec[i] += (pktCount.at(i) < np1.at(i)) ? ipg1.at(i) : ipg2.at(i); while (schedNsec.at(i) >= 1e9) { schedSec[i]++; schedNsec[i] -= long(1e9); } } burstCount[i]++; schedNsec[i] += (burstCount.at(i) < nb1.at(i)) ? ibg1.at(i) : ibg2.at(i); while (schedNsec.at(i) >= 1e9) { schedSec[i]++; schedNsec[i] -= long(1e9); } } nsec += minGap; while (nsec >= 1e9) { sec++; nsec -= long(1e9); } } while ((sec < durSec) || (nsec < durNsec)); qint64 delaySec = durSec - lastPktTxSec; qint64 delayNsec = durNsec - lastPktTxNsec; while (delayNsec < 0) { delayNsec += long(1e9); delaySec--; } qDebug("loop Delay = %" PRId64 "/%" PRId64, delaySec, delayNsec); setPacketListLoopMode(true, delaySec, delayNsec); isSendQueueDirty_ = false; } void AbstractPort::stats(PortStats *stats) { stats->rxPkts = (stats_.rxPkts >= epochStats_.rxPkts) ? stats_.rxPkts - epochStats_.rxPkts : stats_.rxPkts + (maxStatsValue_ - epochStats_.rxPkts); stats->rxBytes = (stats_.rxBytes >= epochStats_.rxBytes) ? stats_.rxBytes - epochStats_.rxBytes : stats_.rxBytes + (maxStatsValue_ - epochStats_.rxBytes); stats->rxPps = stats_.rxPps; stats->rxBps = stats_.rxBps; stats->txPkts = (stats_.txPkts >= epochStats_.txPkts) ? stats_.txPkts - epochStats_.txPkts : stats_.txPkts + (maxStatsValue_ - epochStats_.txPkts); stats->txBytes = (stats_.txBytes >= epochStats_.txBytes) ? stats_.txBytes - epochStats_.txBytes : stats_.txBytes + (maxStatsValue_ - epochStats_.txBytes); stats->txPps = stats_.txPps; stats->txBps = stats_.txBps; stats->rxDrops = (stats_.rxDrops >= epochStats_.rxDrops) ? stats_.rxDrops - epochStats_.rxDrops : stats_.rxDrops + (maxStatsValue_ - epochStats_.rxDrops); stats->rxErrors = (stats_.rxErrors >= epochStats_.rxErrors) ? stats_.rxErrors - epochStats_.rxErrors : stats_.rxErrors + (maxStatsValue_ - epochStats_.rxErrors); stats->rxFifoErrors = (stats_.rxFifoErrors >= epochStats_.rxFifoErrors) ? stats_.rxFifoErrors - epochStats_.rxFifoErrors : stats_.rxFifoErrors + (maxStatsValue_ - epochStats_.rxFifoErrors); stats->rxFrameErrors = (stats_.rxFrameErrors >= epochStats_.rxFrameErrors) ? stats_.rxFrameErrors - epochStats_.rxFrameErrors : stats_.rxFrameErrors + (maxStatsValue_ - epochStats_.rxFrameErrors); } ostinato-0.5.1/server/abstractport.h0000700000175300010010000000665712005505615017076 0ustar srivatspNone/* Copyright (C) 2010-2012 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_ABSTRACT_PORT_H #define _SERVER_ABSTRACT_PORT_H #include #include #include "../common/protocol.pb.h" class StreamBase; class QIODevice; class AbstractPort { public: struct PortStats { quint64 rxPkts; quint64 rxBytes; quint64 rxPps; quint64 rxBps; quint64 rxDrops; quint64 rxErrors; quint64 rxFifoErrors; quint64 rxFrameErrors; quint64 txPkts; quint64 txBytes; quint64 txPps; quint64 txBps; }; AbstractPort(int id, const char *device); virtual ~AbstractPort(); bool isUsable() { return isUsable_; } virtual void init(); int id() { return data_.port_id().id(); } const char* name() { return data_.name().c_str(); } void protoDataCopyInto(OstProto::Port *port) { port->CopyFrom(data_); } bool modify(const OstProto::Port &port); virtual OstProto::LinkState linkState() { return linkState_; } virtual bool hasExclusiveControl() = 0; virtual bool setExclusiveControl(bool exclusive) = 0; int streamCount() { return streamList_.size(); } StreamBase* streamAtIndex(int index); StreamBase* stream(int streamId); bool addStream(StreamBase *stream); bool deleteStream(int streamId); bool isDirty() { return isSendQueueDirty_; } void setDirty() { isSendQueueDirty_ = true; } virtual void clearPacketList() = 0; virtual void loopNextPacketSet(qint64 size, qint64 repeats, long repeatDelaySec, long repeatDelayNsec) = 0; virtual bool appendToPacketList(long sec, long nsec, const uchar *packet, int length) = 0; virtual void setPacketListLoopMode(bool loop, quint64 secDelay, quint64 nsecDelay) = 0; void updatePacketList(); virtual void startTransmit() = 0; virtual void stopTransmit() = 0; virtual bool isTransmitOn() = 0; virtual void startCapture() = 0; virtual void stopCapture() = 0; virtual bool isCaptureOn() = 0; virtual QIODevice* captureData() = 0; void stats(PortStats *stats); void resetStats() { epochStats_ = stats_; } protected: void addNote(QString note); void updatePacketListSequential(); void updatePacketListInterleaved(); bool isUsable_; OstProto::Port data_; OstProto::LinkState linkState_; ulong minPacketSetSize_; quint64 maxStatsValue_; struct PortStats stats_; //! \todo Need lock for stats access/update private: bool isSendQueueDirty_; static const int kMaxPktSize = 16384; uchar pktBuf_[kMaxPktSize]; /*! \note StreamBase::id() and index into streamList[] are NOT same! */ QList streamList_; struct PortStats epochStats_; }; #endif ostinato-0.5.1/server/bsdport.cpp0000700000175300010010000002347712005505615016375 0ustar srivatspNone/* Copyright (C) 2012 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "bsdport.h" #ifdef Q_OS_BSD4 #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_MAC #define ifr_flagshigh ifr_flags #define IFF_PPROMISC (IFF_PROMISC << 16) #endif QList BsdPort::allPorts_; BsdPort::StatsMonitor *BsdPort::monitor_; const quint32 kMaxValue32 = 0xffffffff; BsdPort::BsdPort(int id, const char *device) : PcapPort(id, device) { isPromisc_ = true; clearPromisc_ = false; // We don't need per port Rx/Tx monitors for Bsd delete monitorRx_; delete monitorTx_; monitorRx_ = monitorTx_ = NULL; // We have one monitor for both Rx/Tx of all ports if (!monitor_) monitor_ = new StatsMonitor(); data_.set_is_exclusive_control(hasExclusiveControl()); minPacketSetSize_ = 16; qDebug("adding dev to all ports list <%s>", device); allPorts_.append(this); maxStatsValue_ = ULONG_MAX; } BsdPort::~BsdPort() { qDebug("In %s", __FUNCTION__); if (monitor_->isRunning()) { monitor_->stop(); monitor_->wait(); } if (clearPromisc_) { int sd = socket(AF_INET, SOCK_DGRAM, 0); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, name(), sizeof(ifr.ifr_name)); if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1) { short promisc = IFF_PPROMISC >> 16; if (ifr.ifr_flagshigh & promisc) { ifr.ifr_flagshigh &= ~promisc; if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1) qDebug("Failed clearing promisc flag. SIOCSIFFLAGS failed: %s", strerror(errno)); else qDebug("Cleared promisc successfully"); } else qDebug("clear_promisc is set but IFF_PPROMISC is not?"); } else qDebug("Failed clearing promisc flag. SIOCGIFFLAGS failed: %s", strerror(errno)); close(sd); } } void BsdPort::init() { if (!monitor_->isRunning()) monitor_->start(); monitor_->waitForSetupFinished(); if (!isPromisc_) addNote("Non Promiscuous Mode"); } bool BsdPort::hasExclusiveControl() { // TODO return false; } bool BsdPort::setExclusiveControl(bool /*exclusive*/) { // TODO return false; } BsdPort::StatsMonitor::StatsMonitor() : QThread() { stop_ = false; setupDone_ = false; } void BsdPort::StatsMonitor::run() { int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; const int mibLen = sizeof(mib)/sizeof(mib[0]); QHash portStats; QHash linkState; int sd; QByteArray buf; size_t len; char *p, *end; int count; struct ifreq ifr; // // We first setup stuff before we start polling for stats // if (sysctl(mib, mibLen, NULL, &len, NULL, 0) < 0) { qWarning("sysctl NET_RT_IFLIST(1) failed (%s)\n", strerror(errno)); return; } qDebug("sysctl mib returns reqd len = %d\n", (int) len); len *= 2; // for extra room, just in case! buf.fill('\0', len); if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0) { qWarning("sysctl NET_RT_IFLIST(2) failed(%s)\n", strerror(errno)); return; } sd = socket(AF_INET, SOCK_DGRAM, 0); Q_ASSERT(sd >= 0); memset(&ifr, 0, sizeof(ifr)); // // Populate the port stats hash table // p = buf.data(); end = p + len; count = 0; while (p < end) { struct if_msghdr *ifm = (struct if_msghdr*) p; struct sockaddr_dl *sdl = (struct sockaddr_dl*) (ifm + 1); if (ifm->ifm_type == RTM_IFINFO) { char ifname[1024]; strncpy(ifname, sdl->sdl_data, sdl->sdl_nlen); ifname[sdl->sdl_nlen] = 0; qDebug("if: %s(%d, %d)", ifname, ifm->ifm_index, sdl->sdl_index); foreach(BsdPort* port, allPorts_) { if (strncmp(port->name(), sdl->sdl_data, sdl->sdl_nlen) == 0) { Q_ASSERT(ifm->ifm_index == sdl->sdl_index); portStats[uint(ifm->ifm_index)] = &(port->stats_); linkState[uint(ifm->ifm_index)] = &(port->linkState_); // Set promisc mode, if not already set strncpy(ifr.ifr_name, port->name(), sizeof(ifr.ifr_name)); if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1) { short promisc = IFF_PPROMISC >> 16; if ((ifr.ifr_flagshigh & promisc) == 0) { ifr.ifr_flagshigh |= promisc; if (ioctl(sd, SIOCSIFFLAGS, &ifr) != -1) { qDebug("%s: set promisc successful", port->name()); port->clearPromisc_ = true; } else { port->isPromisc_ = false; qDebug("%s: failed to set promisc; " "SIOCSIFFLAGS failed (%s)", port->name(), strerror(errno)); } } else qDebug("%s: promisc already set", port->name()); } else { port->isPromisc_ = false; qDebug("%s: failed to set promisc; SIOCGIFFLAGS failed (%s)", port->name(), strerror(errno)); } break; } } count++; } p += ifm->ifm_msglen; } qDebug("port count = %d\n", count); if (count <= 0) { qWarning("no ports in NET_RT_IFLIST - no stats will be available"); return; } close(sd); qDebug("stats for %d ports setup", count); setupDone_ = true; // // We are all set - Let's start polling for stats! // while (!stop_) { if (sysctl(mib, mibLen, buf.data(), &len, NULL, 0) < 0) { qWarning("sysctl NET_RT_IFLIST(3) failed(%s)\n", strerror(errno)); goto _try_later; } p = buf.data(); end = p + len; while (p < end) { struct if_msghdr *ifm = (struct if_msghdr*) p; AbstractPort::PortStats *stats; if (ifm->ifm_type != RTM_IFINFO) goto _next; stats = portStats[ifm->ifm_index]; if (stats) { struct if_data *ifd = &(ifm->ifm_data); OstProto::LinkState *state = linkState[ifm->ifm_index]; u_long in_packets; Q_ASSERT(state); #ifdef Q_OS_MAC *state = ifm->ifm_flags & IFF_RUNNING ? OstProto::LinkStateUp : OstProto::LinkStateDown; #else *state = (OstProto::LinkState) ifd->ifi_link_state; #endif in_packets = ifd->ifi_ipackets + ifd->ifi_noproto; stats->rxPps = ((in_packets >= stats->rxPkts) ? in_packets - stats->rxPkts : in_packets + (kMaxValue32 - stats->rxPkts)) / kRefreshFreq_; stats->rxBps = ((ifd->ifi_ibytes >= stats->rxBytes) ? ifd->ifi_ibytes - stats->rxBytes : ifd->ifi_ibytes + (kMaxValue32 - stats->rxBytes)) / kRefreshFreq_; stats->rxPkts = in_packets; stats->rxBytes = ifd->ifi_ibytes; stats->txPps = ((ifd->ifi_opackets >= stats->txPkts) ? ifd->ifi_opackets - stats->txPkts : ifd->ifi_opackets + (kMaxValue32 - stats->txPkts)) / kRefreshFreq_; stats->txBps = ((ifd->ifi_obytes >= stats->txBytes) ? ifd->ifi_obytes - stats->txBytes : ifd->ifi_obytes + (kMaxValue32 - stats->txBytes)) / kRefreshFreq_; stats->txPkts = ifd->ifi_opackets; stats->txBytes = ifd->ifi_obytes; stats->rxDrops = ifd->ifi_iqdrops; stats->rxErrors = ifd->ifi_ierrors; } _next: p += ifm->ifm_msglen; } _try_later: QThread::sleep(kRefreshFreq_); } portStats.clear(); linkState.clear(); } void BsdPort::StatsMonitor::stop() { stop_ = true; } bool BsdPort::StatsMonitor::waitForSetupFinished(int msecs) { QTime t; t.start(); while (!setupDone_) { if (t.elapsed() > msecs) return false; QThread::msleep(10); } return true; } #endif ostinato-0.5.1/server/bsdport.h0000700000175300010010000000271012005505615016025 0ustar srivatspNone/* Copyright (C) 2012 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_BSD_PORT_H #define _SERVER_BSD_PORT_H #include #ifdef Q_OS_BSD4 #include "pcapport.h" class BsdPort : public PcapPort { public: BsdPort(int id, const char *device); ~BsdPort(); void init(); virtual bool hasExclusiveControl(); virtual bool setExclusiveControl(bool exclusive); protected: class StatsMonitor: public QThread { public: StatsMonitor(); void run(); void stop(); bool waitForSetupFinished(int msecs = 10000); private: static const int kRefreshFreq_ = 1; // in seconds bool stop_; bool setupDone_; }; bool isPromisc_; bool clearPromisc_; static QList allPorts_; static StatsMonitor *monitor_; // rx/tx stats for ALL ports }; #endif #endif ostinato-0.5.1/server/drone.cpp0000700000175300010010000000502412005505615016013 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "drone.h" #include "rpcserver.h" #include "myservice.h" #include #include extern int myport; extern const char* version; extern const char* revision; Drone::Drone(QWidget *parent) : QWidget(parent) { setupUi(this); versionLabel->setText( QString("Version: %1 Revision: %2").arg(version).arg(revision)); rpcServer = new RpcServer(); service = new MyService(); } Drone::~Drone() { trayIcon_->hide(); delete trayIcon_; delete trayIconMenu_; delete rpcServer; delete service; } bool Drone::init() { Q_ASSERT(rpcServer); if (!rpcServer->registerService(service, myport ? myport : 7878)) { QMessageBox::critical(0, qApp->applicationName(), rpcServer->errorString()); return false; } trayIconMenu_ = new QMenu(this); trayIconMenu_->addAction(actionShow); trayIconMenu_->addAction(actionExit); trayIconMenu_->setDefaultAction(actionShow); trayIcon_ = new QSystemTrayIcon(); trayIcon_->setIcon(QIcon(":/icons/portgroup.png")); trayIcon_->setToolTip(qApp->applicationName()); trayIcon_->setContextMenu(trayIconMenu_); trayIcon_->show(); connect(trayIcon_, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); connect(this, SIGNAL(hideMe(bool)), this, SLOT(setHidden(bool)), Qt::QueuedConnection); return true; } void Drone::changeEvent(QEvent *event) { if (event->type() == QEvent::WindowStateChange && isMinimized()) { emit hideMe(true); event->ignore(); return; } QWidget::changeEvent(event); } void Drone::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::DoubleClick) { showNormal(); activateWindow(); } } ostinato-0.5.1/server/drone.h0000700000175300010010000000246012005505615015461 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _DRONE_H #define _DRONE_H #include "ui_drone.h" #include #include class RpcServer; namespace OstProto { class OstService; } class Drone : public QWidget, Ui::Drone { Q_OBJECT public: Drone(QWidget *parent = 0); ~Drone(); bool init(); signals: void hideMe(bool hidden); protected: void changeEvent(QEvent *event); private: QSystemTrayIcon *trayIcon_; QMenu *trayIconMenu_; RpcServer *rpcServer; OstProto::OstService *service; private slots: void trayIconActivated(QSystemTrayIcon::ActivationReason reason); }; #endif ostinato-0.5.1/server/drone.pro0000700000175300010010000000232312005505615016030 0ustar srivatspNoneTEMPLATE = app CONFIG += qt QT += network script DEFINES += HAVE_REMOTE WPCAP INCLUDEPATH += "../rpc" win32 { LIBS += -lwpcap -lpacket CONFIG(debug, debug|release) { LIBS += -L"../common/debug" -lostproto LIBS += -L"../rpc/debug" -lpbrpc POST_TARGETDEPS += \ "../common/debug/libostproto.a" \ "../rpc/debug/libpbrpc.a" } else { LIBS += -L"../common/release" -lostproto LIBS += -L"../rpc/release" -lpbrpc POST_TARGETDEPS += \ "../common/release/libostproto.a" \ "../rpc/release/libpbrpc.a" } } else { LIBS += -lpcap LIBS += -L"../common" -lostproto LIBS += -L"../rpc" -lpbrpc POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a" } LIBS += -lm LIBS += -lprotobuf LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2 RESOURCES += drone.qrc HEADERS += drone.h FORMS += drone.ui SOURCES += \ drone_main.cpp \ drone.cpp \ portmanager.cpp \ abstractport.cpp \ pcapport.cpp \ bsdport.cpp \ linuxport.cpp \ winpcapport.cpp SOURCES += myservice.cpp SOURCES += pcapextra.cpp QMAKE_DISTCLEAN += object_script.* include (../install.pri) include (../version.pri) ostinato-0.5.1/server/drone.qrc0000700000175300010010000000014312005505615016013 0ustar srivatspNone icons/portgroup.png ostinato-0.5.1/server/drone.ui0000700000175300010010000001074212005505615015651 0ustar srivatspNone Drone 0 0 268 216 Drone :/icons/portgroup.png Qt::Vertical 20 40 <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 Version/Revision Placeholder Qt::AlignCenter (Server) Qt::AlignCenter TODO: Info/Status here Qt::AlignCenter Qt::Vertical 20 51 Qt::Horizontal 40 20 Exit Qt::Horizontal 40 20 Show Exit pushButton clicked() actionExit trigger() 134 194 -1 -1 actionShow triggered() Drone showNormal() -1 -1 133 107 actionExit triggered() Drone close() -1 -1 133 107 ostinato-0.5.1/server/drone_main.cpp0000700000175300010010000000363612005505615017026 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "drone.h" #include "../common/protocolmanager.h" #include #ifdef Q_OS_UNIX #include #endif extern ProtocolManager *OstProtocolManager; int myport; void cleanup(int /*signum*/) { qApp->exit(-1); } int main(int argc, char *argv[]) { int exitCode = 0; QApplication app(argc, argv); Drone *drone = new Drone(); OstProtocolManager = new ProtocolManager(); app.setApplicationName(drone->objectName()); if (argc > 1) myport = atoi(argv[1]); if (!drone->init()) { exitCode = -1; goto _exit; } #ifdef Q_OS_UNIX struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = cleanup; if (sigaction(SIGTERM, &sa, NULL)) qDebug("Failed to install SIGTERM handler. Cleanup may not happen!!!"); if (sigaction(SIGINT, &sa, NULL)) qDebug("Failed to install SIGINT handler. Cleanup may not happen!!!"); #endif drone->setWindowFlags(drone->windowFlags() | Qt::WindowMaximizeButtonHint | Qt::WindowMinimizeButtonHint); drone->showMinimized(); exitCode = app.exec(); _exit: delete drone; delete OstProtocolManager; google::protobuf::ShutdownProtobufLibrary(); return exitCode; } ostinato-0.5.1/server/icons/0000700000175300010010000000000012005505615015307 5ustar srivatspNoneostinato-0.5.1/server/icons/portgroup.png0000700000175300010010000000123312005505615020060 0ustar srivatspNonePNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<-IDAT8}S;lA}w8؎7RD !ACIDh)kQ  H(4 $I}ٳEP={ovf1 GQt# C<ȋ}Nfs \n!I )X,`i-%. */ #include "linuxport.h" #ifdef Q_OS_LINUX #include #include #include #include #include #include #include #include #include #include #include #include QList LinuxPort::allPorts_; LinuxPort::StatsMonitor *LinuxPort::monitor_; const quint32 kMaxValue32 = 0xffffffff; LinuxPort::LinuxPort(int id, const char *device) : PcapPort(id, device) { isPromisc_ = true; clearPromisc_ = false; // We don't need per port Rx/Tx monitors for Linux delete monitorRx_; delete monitorTx_; monitorRx_ = monitorTx_ = NULL; // We have one monitor for both Rx/Tx of all ports if (!monitor_) monitor_ = new StatsMonitor(); data_.set_is_exclusive_control(hasExclusiveControl()); minPacketSetSize_ = 16; qDebug("adding dev to all ports list <%s>", device); allPorts_.append(this); maxStatsValue_ = 0xffffffff; } LinuxPort::~LinuxPort() { qDebug("In %s", __FUNCTION__); if (monitor_->isRunning()) { monitor_->stop(); monitor_->wait(); } if (clearPromisc_) { int sd = socket(AF_INET, SOCK_DGRAM, 0); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, name(), sizeof(ifr.ifr_name)); if (ioctl(sd, SIOCGIFFLAGS, &ifr) != -1) { if (ifr.ifr_flags & IFF_PROMISC) { ifr.ifr_flags &= ~IFF_PROMISC; if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1) qDebug("Failed clearing promisc flag. SIOCSIFFLAGS failed: %s", strerror(errno)); } } else qDebug("Failed clearing promisc flag. SIOCGIFFLAGS failed: %s", strerror(errno)); close(sd); } } void LinuxPort::init() { if (!monitor_->isRunning()) monitor_->start(); monitor_->waitForSetupFinished(); if (!isPromisc_) addNote("Non Promiscuous Mode"); } OstProto::LinkState LinuxPort::linkState() { return linkState_; } bool LinuxPort::hasExclusiveControl() { // TODO return false; } bool LinuxPort::setExclusiveControl(bool /*exclusive*/) { // TODO return false; } LinuxPort::StatsMonitor::StatsMonitor() : QThread() { stop_ = false; setupDone_ = false; ioctlSocket_ = socket(AF_INET, SOCK_DGRAM, 0); Q_ASSERT(ioctlSocket_ >= 0); } LinuxPort::StatsMonitor::~StatsMonitor() { close(ioctlSocket_); } void LinuxPort::StatsMonitor::run() { if (netlinkStats() < 0) { qDebug("netlink stats not available - using /proc stats"); procStats(); } } void LinuxPort::StatsMonitor::procStats() { PortStats **portStats; int fd; QByteArray buf; int len; char *p, *end; int count, index; const char* fmtopt[] = { "%llu%llu%llu%llu%llu%llu%u%u%llu%llu%u%u%u%u%u%u\n", "%llu%llu%llu%llu%llu%llu%n%n%llu%llu%u%u%u%u%u%n\n", }; const char *fmt; // // We first setup stuff before we start polling for stats // fd = open("/proc/net/dev", O_RDONLY); if (fd < 0) { qWarning("Unable to open /proc/net/dev - no stats will be available"); return; } buf.fill('\0', 8192); len = read(fd, (void*) buf.data(), buf.size()); if (len < 0) { qWarning("initial buffer size is too small. no stats will be available"); return; } p = buf.data(); end = p + len; // Select scanf format if (strstr(buf, "compressed")) fmt = fmtopt[0]; else fmt = fmtopt[1]; // Count number of lines - number of ports is 2 less than number of lines count = 0; while (p < end) { if (*p == '\n') count++; p++; } count -= 2; if (count <= 0) { qWarning("no ports in /proc/dev/net - no stats will be available"); return; } portStats = (PortStats**) calloc(count, sizeof(PortStats)); Q_ASSERT(portStats != NULL); // // Populate the port stats array // p = buf.data(); // Skip first two lines while (*p != '\n') p++; p++; while (*p != '\n') p++; p++; index = 0; while (p < end) { char* q; // Skip whitespace while ((p < end) && (*p == ' ')) p++; q = p; // Get interface name while ((q < end) && (*q != ':') && (*q != '\n')) q++; if ((q < end) && (*q == ':')) { foreach(LinuxPort* port, allPorts_) { if (strncmp(port->name(), p, int(q-p)) == 0) { portStats[index] = &(port->stats_); if (setPromisc(port->name())) port->clearPromisc_ = true; else port->isPromisc_ = false; break; } } } index++; // Skip till newline p = q; while (*p != '\n') p++; p++; } Q_ASSERT(index == count); qDebug("stats for %d ports setup", count); setupDone_ = true; // // We are all set - Let's start polling for stats! // while (!stop_) { lseek(fd, 0, SEEK_SET); len = read(fd, (void*) buf.data(), buf.size()); if (len < 0) { if (buf.size() > 1*1024*1024) { qWarning("buffer size hit limit. no more stats"); return; } qDebug("doubling buffer size. curr = %d", buf.size()); buf.resize(buf.size() * 2); continue; } p = buf.data(); end = p + len; // Skip first two lines while (*p != '\n') p++; p++; while (*p != '\n') p++; p++; index = 0; while (p < end) { uint dummy; quint64 rxBytes, rxPkts; quint64 rxErrors, rxDrops, rxFifo, rxFrame; quint64 txBytes, txPkts; // Skip interface name - we assume the number and order of ports // won't change since we parsed the output before we started polling while ((p < end) && (*p != ':') && (*p != '\n')) p++; if (p >= end) break; if (*p == '\n') { index++; continue; } p++; sscanf(p, fmt, &rxBytes, &rxPkts, &rxErrors, &rxDrops, &rxFifo, &rxFrame, &dummy, &dummy, &txBytes, &txPkts, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy); if (index < count) { AbstractPort::PortStats *stats = portStats[index]; if (stats) { stats->rxPps = ((rxPkts >= stats->rxPkts) ? rxPkts - stats->rxPkts : rxPkts + (kMaxValue32 - stats->rxPkts)) / kRefreshFreq_; stats->rxBps = ((rxBytes >= stats->rxBytes) ? rxBytes - stats->rxBytes : rxBytes + (kMaxValue32 - stats->rxBytes)) / kRefreshFreq_; stats->rxPkts = rxPkts; stats->rxBytes = rxBytes; stats->txPps = ((txPkts >= stats->txPkts) ? txPkts - stats->txPkts : txPkts + (kMaxValue32 - stats->txPkts)) / kRefreshFreq_; stats->txBps = ((txBytes >= stats->txBytes) ? txBytes - stats->txBytes : txBytes + (kMaxValue32 - stats->txBytes)) / kRefreshFreq_; stats->txPkts = txPkts; stats->txBytes = txBytes; stats->rxDrops = rxDrops; stats->rxErrors = rxErrors; stats->rxFifoErrors = rxFifo; stats->rxFrameErrors = rxFrame; } } while (*p != '\n') p++; p++; index++; } QThread::sleep(kRefreshFreq_); } free(portStats); } int LinuxPort::StatsMonitor::netlinkStats() { QHash portStats; QHash linkState; int fd; struct sockaddr_nl local; struct sockaddr_nl kernel; QByteArray buf; int len, count; struct { struct nlmsghdr nlh; struct rtgenmsg rtg; } ifListReq; struct iovec iov; struct msghdr msg; struct nlmsghdr *nlm; bool done = false; // // We first setup stuff before we start polling for stats // fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (fd < 0) { qWarning("Unable to open netlink socket (errno %d)", errno); return -1; } memset(&local, 0, sizeof(local)); local.nl_family = AF_NETLINK; if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) { qWarning("Unable to bind netlink socket (errno %d)", errno); return -1; } memset(&ifListReq, 0, sizeof(ifListReq)); ifListReq.nlh.nlmsg_len = sizeof(ifListReq); ifListReq.nlh.nlmsg_type = RTM_GETLINK; ifListReq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; ifListReq.nlh.nlmsg_pid = 0; ifListReq.rtg.rtgen_family = AF_PACKET; buf.fill('\0', 1024); msg.msg_name = &kernel; msg.msg_namelen = sizeof(kernel); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; qDebug("nlmsg_flags = %x", ifListReq.nlh.nlmsg_flags); if (send(fd, (void*)&ifListReq, sizeof(ifListReq), 0) < 0) { qWarning("Unable to send GETLINK request (errno %d)", errno); return -1; } // Find required size of buffer and resize accordingly while (1) { iov.iov_base = buf.data(); iov.iov_len = buf.size(); msg.msg_flags = 0; // Peek at reply to check buffer size required len = recvmsg(fd, &msg, MSG_PEEK|MSG_TRUNC); if (len < 0) { if (errno == EINTR || errno == EAGAIN) continue; qWarning("netlink recv error %d", errno); return -1; } else if (len == 0) { qWarning("netlink closed the socket on my face!"); return -1; } else { if (msg.msg_flags & MSG_TRUNC) { if (len == buf.size()) // Older Kernel returns truncated size { qDebug("netlink buffer size %d not enough", buf.size()); qDebug("retrying with double the size"); // Double the size and retry buf.resize(buf.size()*2); continue; } else // Newer Kernel returns actual size required { qDebug("netlink required buffer size = %d", len); buf.resize(len); continue; } } else qDebug("buffer size %d enough for netlink", buf.size()); break; } } count = 0; _retry: msg.msg_flags = 0; // Actually receive the reply now len = recvmsg(fd, &msg, 0); if (len < 0) { if (errno == EINTR || errno == EAGAIN) goto _retry; qWarning("netlink recv error %d", errno); return -1; } else if (len == 0) { qWarning("netlink socket closed unexpectedly"); return -1; } // // Populate the port stats hash table // nlm = (struct nlmsghdr*) buf.data(); while (NLMSG_OK(nlm, (uint)len)) { struct ifinfomsg *ifi; struct rtattr *rta; int rtaLen; char ifname[64] = ""; if (nlm->nlmsg_type == NLMSG_DONE) { done = true; break; } if (nlm->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*) NLMSG_DATA(nlm); qDebug("RTNETLINK error %d", err->error); done = true; break; } Q_ASSERT(nlm->nlmsg_type == RTM_NEWLINK); ifi = (struct ifinfomsg*) NLMSG_DATA(nlm); rta = IFLA_RTA(ifi); rtaLen = len - NLMSG_LENGTH(sizeof(*ifi)); while (RTA_OK(rta, rtaLen)) { if (rta->rta_type == IFLA_IFNAME) { strncpy(ifname, (char*)RTA_DATA(rta), RTA_PAYLOAD(rta)); ifname[RTA_PAYLOAD(rta)] = 0; break; } rta = RTA_NEXT(rta, rtaLen); } qDebug("if: %s(%d)", ifname, ifi->ifi_index); foreach(LinuxPort* port, allPorts_) { if (strcmp(port->name(), ifname) == 0) { portStats[uint(ifi->ifi_index)] = &(port->stats_); linkState[uint(ifi->ifi_index)] = &(port->linkState_); if (setPromisc(port->name())) port->clearPromisc_ = true; else port->isPromisc_ = false; count++; break; } } nlm = NLMSG_NEXT(nlm, len); } if (!done) goto _retry; qDebug("port count = %d\n", count); if (count <= 0) { qWarning("no ports in RTNETLINK GET_LINK - no stats will be available"); return - 1; } qDebug("stats for %d ports setup", count); setupDone_ = true; // // We are all set - Let's start polling for stats! // while (!stop_) { if (send(fd, (void*)&ifListReq, sizeof(ifListReq), 0) < 0) { qWarning("Unable to send GETLINK request (errno %d)", errno); goto _try_later; } done = false; _retry_recv: msg.msg_flags = 0; len = recvmsg(fd, &msg, 0); if (len < 0) { if (errno == EINTR || errno == EAGAIN) goto _retry_recv; qWarning("netlink recv error %d", errno); break; } else if (len == 0) { qWarning("netlink socket closed unexpectedly"); break; } nlm = (struct nlmsghdr*) buf.data(); while (NLMSG_OK(nlm, (uint)len)) { struct ifinfomsg *ifi; struct rtattr *rta; int rtaLen; if (nlm->nlmsg_type == NLMSG_DONE) { done = true; break; } if (nlm->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*) NLMSG_DATA(nlm); qDebug("RTNETLINK error: %s", strerror(-err->error)); done = true; break; } Q_ASSERT(nlm->nlmsg_type == RTM_NEWLINK); ifi = (struct ifinfomsg*) NLMSG_DATA(nlm); rta = IFLA_RTA(ifi); rtaLen = len - NLMSG_LENGTH(sizeof(*ifi)); while (RTA_OK(rta, rtaLen)) { // TODO: IFLA_STATS64 if (rta->rta_type == IFLA_STATS) { struct rtnl_link_stats *rtnlStats = (struct rtnl_link_stats*) RTA_DATA(rta); AbstractPort::PortStats *stats = portStats[ifi->ifi_index]; OstProto::LinkState *state = linkState[ifi->ifi_index]; if (!stats) break; stats->rxPps = ((rtnlStats->rx_packets >= stats->rxPkts) ? rtnlStats->rx_packets - stats->rxPkts : rtnlStats->rx_packets + (kMaxValue32 - stats->rxPkts)) / kRefreshFreq_; stats->rxBps = ((rtnlStats->rx_bytes >= stats->rxBytes) ? rtnlStats->rx_bytes - stats->rxBytes : rtnlStats->rx_bytes + (kMaxValue32 - stats->rxBytes)) / kRefreshFreq_; stats->rxPkts = rtnlStats->rx_packets; stats->rxBytes = rtnlStats->rx_bytes; stats->txPps = ((rtnlStats->tx_packets >= stats->txPkts) ? rtnlStats->tx_packets - stats->txPkts : rtnlStats->tx_packets + (kMaxValue32 - stats->txPkts)) / kRefreshFreq_; stats->txBps = ((rtnlStats->tx_bytes >= stats->txBytes) ? rtnlStats->tx_bytes - stats->txBytes : rtnlStats->tx_bytes + (kMaxValue32 - stats->txBytes)) / kRefreshFreq_; stats->txPkts = rtnlStats->tx_packets; stats->txBytes = rtnlStats->tx_bytes; // TODO: export detailed error stats stats->rxDrops = rtnlStats->rx_dropped + rtnlStats->rx_missed_errors; stats->rxErrors = rtnlStats->rx_errors; stats->rxFifoErrors = rtnlStats->rx_fifo_errors; stats->rxFrameErrors = rtnlStats->rx_crc_errors + rtnlStats->rx_length_errors + rtnlStats->rx_over_errors + rtnlStats->rx_frame_errors; Q_ASSERT(state); *state = ifi->ifi_flags & IFF_RUNNING ? OstProto::LinkStateUp : OstProto::LinkStateDown; break; } rta = RTA_NEXT(rta, rtaLen); } nlm = NLMSG_NEXT(nlm, len); } if (!done) goto _retry_recv; _try_later: QThread::sleep(kRefreshFreq_); } portStats.clear(); linkState.clear(); return 0; } int LinuxPort::StatsMonitor::setPromisc(const char * portName) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, portName, sizeof(ifr.ifr_name)); if (ioctl(ioctlSocket_, SIOCGIFFLAGS, &ifr) != -1) { if ((ifr.ifr_flags & IFF_PROMISC) == 0) { ifr.ifr_flags |= IFF_PROMISC; if (ioctl(ioctlSocket_, SIOCSIFFLAGS, &ifr) != -1) { return 1; } else { qDebug("%s: failed to set promisc; " "SIOCSIFFLAGS failed (%s)", portName, strerror(errno)); } } } else { qDebug("%s: failed to set promisc; SIOCGIFFLAGS failed (%s)", portName, strerror(errno)); } return 0; } void LinuxPort::StatsMonitor::stop() { stop_ = true; } bool LinuxPort::StatsMonitor::waitForSetupFinished(int msecs) { QTime t; t.start(); while (!setupDone_) { if (t.elapsed() > msecs) return false; QThread::msleep(10); } return true; } #endif ostinato-0.5.1/server/linuxport.h0000700000175300010010000000323212005505615016414 0ustar srivatspNone/* Copyright (C) 2011 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_LINUX_PORT_H #define _SERVER_LINUX_PORT_H #include #ifdef Q_OS_LINUX #include "pcapport.h" class LinuxPort : public PcapPort { public: LinuxPort(int id, const char *device); ~LinuxPort(); void init(); virtual OstProto::LinkState linkState(); virtual bool hasExclusiveControl(); virtual bool setExclusiveControl(bool exclusive); protected: class StatsMonitor: public QThread { public: StatsMonitor(); ~StatsMonitor(); void run(); void stop(); bool waitForSetupFinished(int msecs = 10000); private: int netlinkStats(); void procStats(); int setPromisc(const char* portName); static const int kRefreshFreq_ = 1; // in seconds bool stop_; bool setupDone_; int ioctlSocket_; }; bool isPromisc_; bool clearPromisc_; static QList allPorts_; static StatsMonitor *monitor_; // rx/tx stats for ALL ports }; #endif #endif ostinato-0.5.1/server/myservice.cpp0000700000175300010010000003041112005505615016710 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "myservice.h" #if 0 #include #include #include "qdebug.h" #include "../common/protocollistiterator.h" #include "../common/abstractprotocol.h" #endif #include "../common/streambase.h" #include "../rpc/pbrpccontroller.h" #include "portmanager.h" MyService::MyService() { PortManager *portManager = PortManager::instance(); int n = portManager->portCount(); for (int i = 0; i < n; i++) portInfo.append(portManager->port(i)); } MyService::~MyService() { //! \todo Use a singleton destroyer instead // http://www.research.ibm.com/designpatterns/pubs/ph-jun96.txt delete PortManager::instance(); } void MyService::getPortIdList(::google::protobuf::RpcController* /*controller*/, const ::OstProto::Void* /*request*/, ::OstProto::PortIdList* response, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < portInfo.size(); i++) { ::OstProto::PortId *p; p = response->add_port_id(); p->set_id(portInfo[i]->id()); } done->Run(); } void MyService::getPortConfig(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::PortConfigList* response, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int id; id = request->port_id(i).id(); if (id < portInfo.size()) { OstProto::Port *p; p = response->add_port(); portInfo[id]->protoDataCopyInto(p); } } done->Run(); } void MyService::modifyPort(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortConfigList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_size(); i++) { OstProto::Port port; int id; port = request->port(i); id = port.port_id().id(); if (id < portInfo.size()) { portInfo[id]->modify(port); } } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } void MyService::getStreamIdList(::google::protobuf::RpcController* controller, const ::OstProto::PortId* request, ::OstProto::StreamIdList* response, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; response->mutable_port_id()->set_id(portId); for (int i = 0; i < portInfo[portId]->streamCount(); i++) { OstProto::StreamId *s; s = response->add_stream_id(); s->set_id(portInfo[portId]->streamAtIndex(i)->id()); } done->Run(); return; _invalid_port: controller->SetFailed("Invalid Port Id"); done->Run(); } void MyService::getStreamConfig(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::StreamConfigList* response, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->port_id().id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; response->mutable_port_id()->set_id(portId); for (int i = 0; i < request->stream_id_size(); i++) { StreamBase *stream; OstProto::Stream *s; stream = portInfo[portId]->stream(request->stream_id(i).id()); if (!stream) continue; //! \todo(LOW): Partial status of RPC s = response->add_stream(); stream->protoDataCopyInto(*s); } done->Run(); return; _invalid_port: controller->SetFailed("invalid portid"); done->Run(); } void MyService::addStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->port_id().id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; for (int i = 0; i < request->stream_id_size(); i++) { StreamBase *stream; // If stream with same id as in request exists already ==> error!! stream = portInfo[portId]->stream(request->stream_id(i).id()); if (stream) continue; //! \todo (LOW): Partial status of RPC // Append a new "default" stream - actual contents of the new stream is // expected in a subsequent "modifyStream" request - set the stream id // now itself however!!! stream = new StreamBase; stream->setId(request->stream_id(i).id()); portInfo[portId]->addStream(stream); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); return; _invalid_port: controller->SetFailed("invalid portid"); done->Run(); } void MyService::deleteStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->port_id().id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; for (int i = 0; i < request->stream_id_size(); i++) portInfo[portId]->deleteStream(request->stream_id(i).id()); //! \todo (LOW): fill-in response "Ack"???? done->Run(); return; _invalid_port: controller->SetFailed("invalid portid"); done->Run(); } void MyService::modifyStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamConfigList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->port_id().id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; for (int i = 0; i < request->stream_size(); i++) { StreamBase *stream; stream = portInfo[portId]->stream(request->stream(i).stream_id().id()); if (stream) { stream->protoDataCopyFrom(request->stream(i)); portInfo[portId]->setDirty(); } } if (portInfo[portId]->isDirty()) portInfo[portId]->updatePacketList(); //! \todo(LOW): fill-in response "Ack"???? done->Run(); return; _invalid_port: controller->SetFailed("invalid portid"); done->Run(); } void MyService::startTx(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int portId; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo (LOW): partial RPC? portInfo[portId]->startTransmit(); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } void MyService::stopTx(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int portId; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo (LOW): partial RPC? portInfo[portId]->stopTransmit(); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } void MyService::startCapture(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int portId; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo (LOW): partial RPC? portInfo[portId]->startCapture(); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } void MyService::stopCapture(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i=0; i < request->port_id_size(); i++) { int portId; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo (LOW): partial RPC? portInfo[portId]->stopCapture(); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } void MyService::getCaptureBuffer(::google::protobuf::RpcController* controller, const ::OstProto::PortId* request, ::OstProto::CaptureBuffer* /*response*/, ::google::protobuf::Closure* done) { int portId; qDebug("In %s", __PRETTY_FUNCTION__); portId = request->id(); if ((portId < 0) || (portId >= portInfo.size())) goto _invalid_port; portInfo[portId]->stopCapture(); static_cast(controller)->setBinaryBlob( portInfo[portId]->captureData()); done->Run(); return; _invalid_port: controller->SetFailed("invalid portid"); done->Run(); } void MyService::getStats(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::PortStatsList* response, ::google::protobuf::Closure* done) { //qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int portId; AbstractPort::PortStats stats; OstProto::PortStats *s; OstProto::PortState *st; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo(LOW): partial rpc? s = response->add_port_stats(); s->mutable_port_id()->set_id(request->port_id(i).id()); st = s->mutable_state(); st->set_link_state(portInfo[portId]->linkState()); st->set_is_transmit_on(portInfo[portId]->isTransmitOn()); st->set_is_capture_on(portInfo[portId]->isCaptureOn()); portInfo[portId]->stats(&stats); #if 0 if (portId == 2) qDebug(">%llu", stats.rxPkts); #endif s->set_rx_pkts(stats.rxPkts); s->set_rx_bytes(stats.rxBytes); s->set_rx_pps(stats.rxPps); s->set_rx_bps(stats.rxBps); s->set_tx_pkts(stats.txPkts); s->set_tx_bytes(stats.txBytes); s->set_tx_pps(stats.txPps); s->set_tx_bps(stats.txBps); s->set_rx_drops(stats.rxDrops); s->set_rx_errors(stats.rxErrors); s->set_rx_fifo_errors(stats.rxFifoErrors); s->set_rx_frame_errors(stats.rxFrameErrors); } done->Run(); } void MyService::clearStats(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortIdList* request, ::OstProto::Ack* /*response*/, ::google::protobuf::Closure* done) { qDebug("In %s", __PRETTY_FUNCTION__); for (int i = 0; i < request->port_id_size(); i++) { int portId; portId = request->port_id(i).id(); if ((portId < 0) || (portId >= portInfo.size())) continue; //! \todo (LOW): partial RPC? portInfo[portId]->resetStats(); } //! \todo (LOW): fill-in response "Ack"???? done->Run(); } ostinato-0.5.1/server/myservice.h0000700000175300010010000001022212005505615016353 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _MY_SERVICE_H #define _MY_SERVICE_H #include #include "../common/protocol.pb.h" #define MAX_PKT_HDR_SIZE 1536 #define MAX_STREAM_NAME_SIZE 64 class AbstractPort; class MyService: public OstProto::OstService { public: MyService(); virtual ~MyService(); /* Methods provided by the service */ virtual void getPortIdList(::google::protobuf::RpcController* controller, const ::OstProto::Void* request, ::OstProto::PortIdList* response, ::google::protobuf::Closure* done); virtual void getPortConfig(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::PortConfigList* response, ::google::protobuf::Closure* done); virtual void modifyPort(::google::protobuf::RpcController* /*controller*/, const ::OstProto::PortConfigList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void getStreamIdList(::google::protobuf::RpcController* controller, const ::OstProto::PortId* request, ::OstProto::StreamIdList* response, ::google::protobuf::Closure* done); virtual void getStreamConfig(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::StreamConfigList* response, ::google::protobuf::Closure* done); virtual void addStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void deleteStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void modifyStream(::google::protobuf::RpcController* controller, const ::OstProto::StreamConfigList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void startTx(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void stopTx(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void startCapture(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void stopCapture(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); virtual void getCaptureBuffer(::google::protobuf::RpcController* controller, const ::OstProto::PortId* request, ::OstProto::CaptureBuffer* response, ::google::protobuf::Closure* done); virtual void getStats(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::PortStatsList* response, ::google::protobuf::Closure* done); virtual void clearStats(::google::protobuf::RpcController* controller, const ::OstProto::PortIdList* request, ::OstProto::Ack* response, ::google::protobuf::Closure* done); private: /*! AbstractPort::id() and index into portInfo[] are same! */ QList portInfo; }; #endif ostinato-0.5.1/server/pcapextra.cpp0000700000175300010010000000367712005505615016707 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pcapextra.h" #include // memcpy() #include // malloc(), free() /* NOTE: All code borrowed from WinPcap */ #ifndef Q_OS_WIN32 pcap_send_queue* pcap_sendqueue_alloc (u_int memsize) { pcap_send_queue *tqueue; /* Allocate the queue */ tqueue = (pcap_send_queue*)malloc(sizeof(pcap_send_queue)); if(tqueue == NULL){ return NULL; } /* Allocate the buffer */ tqueue->buffer = (char*)malloc(memsize); if(tqueue->buffer == NULL){ free(tqueue); return NULL; } tqueue->maxlen = memsize; tqueue->len = 0; return tqueue; } void pcap_sendqueue_destroy (pcap_send_queue *queue) { free(queue->buffer); free(queue); } int pcap_sendqueue_queue (pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) { if(queue->len + sizeof(struct pcap_pkthdr) + pkt_header->caplen > queue->maxlen) { return -1; } /* Copy the pcap_pkthdr header*/ memcpy(queue->buffer + queue->len, pkt_header, sizeof(struct pcap_pkthdr)); queue->len += sizeof(struct pcap_pkthdr); /* copy the packet */ memcpy(queue->buffer + queue->len, pkt_data, pkt_header->caplen); queue->len += pkt_header->caplen; return 0; } #endif ostinato-0.5.1/server/pcapextra.h0000700000175300010010000000221512005505615016337 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _PCAP_EXTRA_H #define _PCAP_EXTRA_H #include #include #ifndef Q_OS_WIN32 #define PCAP_OPENFLAG_PROMISCUOUS 1 struct pcap_send_queue { u_int maxlen; u_int len; char *buffer; }; pcap_send_queue* pcap_sendqueue_alloc (u_int memsize); void pcap_sendqueue_destroy (pcap_send_queue *queue); int pcap_sendqueue_queue (pcap_send_queue *queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); #endif #endif ostinato-0.5.1/server/pcapport.cpp0000700000175300010010000005142612005505615016543 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "pcapport.h" #include #ifdef Q_OS_WIN32 #include #endif pcap_if_t *PcapPort::deviceList_ = NULL; #if defined(Q_OS_LINUX) typedef struct timeval TimeStamp; static void inline getTimeStamp(TimeStamp *stamp) { gettimeofday(stamp, NULL); } // Returns time diff in usecs between end and start static long inline udiffTimeStamp(const TimeStamp *start, const TimeStamp *end) { struct timeval diff; long usecs; timersub(end, start, &diff); usecs = diff.tv_usec; if (diff.tv_sec) usecs += diff.tv_sec*1e6; return usecs; } #elif defined(Q_OS_WIN32) static quint64 gTicksFreq; typedef LARGE_INTEGER TimeStamp; static void inline getTimeStamp(TimeStamp* stamp) { QueryPerformanceCounter(stamp); } static long inline udiffTimeStamp(const TimeStamp *start, const TimeStamp *end) { if (end->QuadPart >= start->QuadPart) return (end->QuadPart - start->QuadPart)*long(1e6)/gTicksFreq; else { // FIXME: incorrect! what's the max value for this counter before // it rolls over? return (start->QuadPart)*long(1e6)/gTicksFreq; } } #else typedef int TimeStamp; static void inline getTimeStamp(TimeStamp*) {} static long inline udiffTimeStamp(const TimeStamp*, const TimeStamp*) { return 0; } #endif PcapPort::PcapPort(int id, const char *device) : AbstractPort(id, device) { monitorRx_ = new PortMonitor(device, kDirectionRx, &stats_); monitorTx_ = new PortMonitor(device, kDirectionTx, &stats_); transmitter_ = new PortTransmitter(device); capturer_ = new PortCapturer(device); if (!monitorRx_->handle() || !monitorTx_->handle()) isUsable_ = false; if (!deviceList_) { char errbuf[PCAP_ERRBUF_SIZE]; if (pcap_findalldevs(&deviceList_, errbuf) == -1) qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf); } for (pcap_if_t *dev = deviceList_; dev != NULL; dev = dev->next) { if (strcmp(device, dev->name) == 0) { #ifdef Q_OS_WIN32 data_.set_name(QString("if%1 ").arg(id).toStdString()); #else if (dev->name) data_.set_name(dev->name); #endif if (dev->description) data_.set_description(dev->description); //! \todo set port IP addr also } } } void PcapPort::init() { if (!monitorTx_->isDirectional()) transmitter_->useExternalStats(&stats_); transmitter_->setHandle(monitorRx_->handle()); updateNotes(); monitorRx_->start(); monitorTx_->start(); } PcapPort::~PcapPort() { qDebug("In %s", __FUNCTION__); if (monitorRx_) monitorRx_->stop(); if (monitorTx_) monitorTx_->stop(); delete capturer_; delete transmitter_; if (monitorRx_) monitorRx_->wait(); delete monitorRx_; if (monitorTx_) monitorTx_->wait(); delete monitorTx_; } void PcapPort::updateNotes() { QString notes; if ((!monitorRx_->isPromiscuous()) || (!monitorTx_->isPromiscuous())) notes.append("
  • Non Promiscuous Mode
  • "); if (!monitorRx_->isDirectional() && !hasExclusiveControl()) notes.append("
  • Rx Frames/Bytes: Includes non Ostinato Tx pkts also (Tx by Ostinato are not included)
  • "); if (!monitorTx_->isDirectional() && !hasExclusiveControl()) notes.append("
  • Tx Frames/Bytes: Only Ostinato Tx pkts (Tx by others NOT included)
  • "); if (notes.isEmpty()) data_.set_notes(""); else data_.set_notes(QString("Limitation(s)" "
      %1
    " "Rx/Tx Rates are also subject to above limitation(s)"). arg(notes).toStdString()); } PcapPort::PortMonitor::PortMonitor(const char *device, Direction direction, AbstractPort::PortStats *stats) { int ret; char errbuf[PCAP_ERRBUF_SIZE] = ""; bool noLocalCapture; direction_ = direction; isDirectional_ = true; isPromisc_ = true; noLocalCapture = true; stats_ = stats; stop_ = false; _retry: #ifdef Q_OS_WIN32 int flags = 0; if (isPromisc_) flags |= PCAP_OPENFLAG_PROMISCUOUS; if (noLocalCapture) flags |= PCAP_OPENFLAG_NOCAPTURE_LOCAL; handle_ = pcap_open(device, 64 /* FIXME */, flags, 1000 /* ms */, NULL, errbuf); #else handle_ = pcap_open_live(device, 64 /* FIXME */, int(isPromisc_), 1000 /* ms */, errbuf); #endif if (handle_ == NULL) { if (isPromisc_ && QString(errbuf).contains("promiscuous")) { qDebug("Can't set promiscuous mode, trying non-promisc %s", device); isPromisc_ = false; goto _retry; } else if (noLocalCapture && QString(errbuf).contains("loopback")) { qDebug("Can't set no local capture mode %s", device); noLocalCapture = false; goto _retry; } else goto _open_error; } #ifdef Q_OS_WIN32 // pcap_setdirection() API is not supported in Windows. // NOTE: WinPcap 4.1.1 and above exports a dummy API that returns -1 // but since we would like to work with previous versions of WinPcap // also, we assume the API does not exist ret = -1; #else switch (direction_) { case kDirectionRx: ret = pcap_setdirection(handle_, PCAP_D_IN); break; case kDirectionTx: ret = pcap_setdirection(handle_, PCAP_D_OUT); break; default: ret = -1; // avoid 'may be used uninitialized' warning Q_ASSERT(false); } #endif if (ret < 0) goto _set_direction_error; return; _set_direction_error: qDebug("Error setting direction(%d) %s: %s\n", direction, device, pcap_geterr(handle_)); isDirectional_ = false; return; _open_error: qDebug("%s: Error opening port %s: %s\n", __FUNCTION__, device, errbuf); } PcapPort::PortMonitor::~PortMonitor() { if (handle_) pcap_close(handle_); } void PcapPort::PortMonitor::run() { while (!stop_) { int ret; struct pcap_pkthdr *hdr; const uchar *data; ret = pcap_next_ex(handle_, &hdr, &data); switch (ret) { case 1: switch (direction_) { case kDirectionRx: stats_->rxPkts++; stats_->rxBytes += hdr->len; break; case kDirectionTx: if (isDirectional_) { stats_->txPkts++; stats_->txBytes += hdr->len; } break; default: Q_ASSERT(false); } //! \todo TODO pkt/bit rates break; case 0: //qDebug("%s: timeout. continuing ...", __PRETTY_FUNCTION__); continue; case -1: qWarning("%s: error reading packet (%d): %s", __PRETTY_FUNCTION__, ret, pcap_geterr(handle_)); break; case -2: qWarning("%s: error reading packet (%d): %s", __PRETTY_FUNCTION__, ret, pcap_geterr(handle_)); break; default: qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret); } } } void PcapPort::PortMonitor::stop() { stop_ = true; pcap_breakloop(handle()); } PcapPort::PortTransmitter::PortTransmitter(const char *device) { char errbuf[PCAP_ERRBUF_SIZE] = ""; #ifdef Q_OS_WIN32 LARGE_INTEGER freq; if (QueryPerformanceFrequency(&freq)) gTicksFreq = ticksFreq_ = freq.QuadPart; else Q_ASSERT_X(false, "PortTransmitter::PortTransmitter", "This Win32 platform does not support performance counter"); #endif returnToQIdx_ = -1; loopDelay_ = 0; stop_ = false; stats_ = new AbstractPort::PortStats; usingInternalStats_ = true; handle_ = pcap_open_live(device, 64 /* FIXME */, 0, 1000 /* ms */, errbuf); if (handle_ == NULL) goto _open_error; usingInternalHandle_ = true; return; _open_error: qDebug("%s: Error opening port %s: %s\n", __FUNCTION__, device, errbuf); usingInternalHandle_ = false; } PcapPort::PortTransmitter::~PortTransmitter() { if (usingInternalStats_) delete stats_; if (usingInternalHandle_) pcap_close(handle_); } void PcapPort::PortTransmitter::clearPacketList() { Q_ASSERT(!isRunning()); // \todo lock for packetSequenceList while(packetSequenceList_.size()) delete packetSequenceList_.takeFirst(); currentPacketSequence_ = NULL; repeatSequenceStart_ = -1; repeatSize_ = 0; packetCount_ = 0; returnToQIdx_ = -1; setPacketListLoopMode(false, 0, 0); } void PcapPort::PortTransmitter::loopNextPacketSet(qint64 size, qint64 repeats, long repeatDelaySec, long repeatDelayNsec) { currentPacketSequence_ = new PacketSequence; currentPacketSequence_->repeatCount_ = repeats; currentPacketSequence_->usecDelay_ = repeatDelaySec * long(1e6) + repeatDelayNsec/1000; repeatSequenceStart_ = packetSequenceList_.size(); repeatSize_ = size; packetCount_ = 0; packetSequenceList_.append(currentPacketSequence_); } bool PcapPort::PortTransmitter::appendToPacketList(long sec, long nsec, const uchar *packet, int length) { bool op = true; pcap_pkthdr pktHdr; pktHdr.caplen = pktHdr.len = length; pktHdr.ts.tv_sec = sec; pktHdr.ts.tv_usec = nsec/1000; if (currentPacketSequence_ == NULL || !currentPacketSequence_->hasFreeSpace(2*sizeof(pcap_pkthdr)+length)) { if (currentPacketSequence_ != NULL) { long usecs; usecs = (pktHdr.ts.tv_sec - currentPacketSequence_->lastPacket_->ts.tv_sec) * long(1e6); usecs += (pktHdr.ts.tv_usec - currentPacketSequence_->lastPacket_->ts.tv_usec); currentPacketSequence_->usecDelay_ = usecs; } //! \todo (LOW): calculate sendqueue size currentPacketSequence_ = new PacketSequence; packetSequenceList_.append(currentPacketSequence_); // Validate that the pkt will fit inside the new currentSendQueue_ Q_ASSERT(currentPacketSequence_->hasFreeSpace( sizeof(pcap_pkthdr) + length)); } if (currentPacketSequence_->appendPacket(&pktHdr, (u_char*) packet) < 0) { op = false; } packetCount_++; if (repeatSize_ > 0 && packetCount_ == repeatSize_) { qDebug("repeatSequenceStart_=%d, repeatSize_ = %llu", repeatSequenceStart_, repeatSize_); // Set the packetSequence repeatSize Q_ASSERT(repeatSequenceStart_ >= 0); Q_ASSERT(repeatSequenceStart_ < packetSequenceList_.size()); if (currentPacketSequence_ != packetSequenceList_[repeatSequenceStart_]) { PacketSequence *start = packetSequenceList_[repeatSequenceStart_]; currentPacketSequence_->usecDelay_ = start->usecDelay_; start->usecDelay_ = 0; start->repeatSize_ = packetSequenceList_.size() - repeatSequenceStart_; } repeatSize_ = 0; // End current pktSeq and trigger a new pktSeq allocation for next pkt currentPacketSequence_ = NULL; } return op; } void PcapPort::PortTransmitter::setHandle(pcap_t *handle) { if (usingInternalHandle_) pcap_close(handle_); handle_ = handle; usingInternalHandle_ = false; } void PcapPort::PortTransmitter::useExternalStats(AbstractPort::PortStats *stats) { if (usingInternalStats_) delete stats_; stats_ = stats; usingInternalStats_ = false; } void PcapPort::PortTransmitter::run() { //! \todo (MED) Stream Mode - continuous: define before implement // NOTE1: We can't use pcap_sendqueue_transmit() directly even on Win32 // 'coz of 2 reasons - there's no way of stopping it before all packets // in the sendQueue are sent out and secondly, stats are available only // when all packets have been sent - no periodic updates // // NOTE2: Transmit on the Rx Handle so that we can receive it back // on the Tx Handle to do stats // // NOTE3: Update pcapExtra counters - port TxStats will be updated in the // 'stats callback' function so that both Rx and Tx stats are updated // together const int kSyncTransmit = 1; int i; long overHead = 0; // overHead should be negative or zero qDebug("packetSequenceList_.size = %d", packetSequenceList_.size()); if (packetSequenceList_.size() <= 0) return; for(i = 0; i < packetSequenceList_.size(); i++) { qDebug("sendQ[%d]: rptCnt = %d, rptSz = %d, usecDelay = %ld", i, packetSequenceList_.at(i)->repeatCount_, packetSequenceList_.at(i)->repeatSize_, packetSequenceList_.at(i)->usecDelay_); qDebug("sendQ[%d]: pkts = %ld, usecDuration = %ld", i, packetSequenceList_.at(i)->packets_, packetSequenceList_.at(i)->usecDuration_); } for(i = 0; i < packetSequenceList_.size(); i++) { _restart: int rptSz = packetSequenceList_.at(i)->repeatSize_; int rptCnt = packetSequenceList_.at(i)->repeatCount_; for (int j = 0; j < rptCnt; j++) { for (int k = 0; k < rptSz; k++) { int ret; PacketSequence *seq = packetSequenceList_.at(i+k); #ifdef Q_OS_WIN32 TimeStamp ovrStart, ovrEnd; if (seq->usecDuration_ <= long(1e6)) // 1s { getTimeStamp(&ovrStart); ret = pcap_sendqueue_transmit(handle_, seq->sendQueue_, kSyncTransmit); if (ret >= 0) { stats_->txPkts += seq->packets_; stats_->txBytes += seq->bytes_; getTimeStamp(&ovrEnd); overHead += seq->usecDuration_ - udiffTimeStamp(&ovrStart, &ovrEnd); Q_ASSERT(overHead <= 0); } if (stop_) ret = -2; } else { ret = sendQueueTransmit(handle_, seq->sendQueue_, overHead, kSyncTransmit); } #else ret = sendQueueTransmit(handle_, seq->sendQueue_, overHead, kSyncTransmit); #endif if (ret >= 0) { long usecs = seq->usecDelay_ + overHead; if (usecs > 0) { udelay(usecs); overHead = 0; } else overHead = usecs; } else { qDebug("error %d in sendQueueTransmit()", ret); qDebug("overHead = %ld", overHead); stop_ = false; return; } } } } if (returnToQIdx_ >= 0) { long usecs = loopDelay_ + overHead; if (usecs > 0) { udelay(usecs); overHead = 0; } else overHead = usecs; i = returnToQIdx_; goto _restart; } } void PcapPort::PortTransmitter::stop() { if (isRunning()) stop_ = true; } int PcapPort::PortTransmitter::sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead, int sync) { TimeStamp ovrStart, ovrEnd; struct timeval ts; struct pcap_pkthdr *hdr = (struct pcap_pkthdr*) queue->buffer; char *end = queue->buffer + queue->len; ts = hdr->ts; getTimeStamp(&ovrStart); while((char*) hdr < end) { uchar *pkt = (uchar*)hdr + sizeof(*hdr); int pktLen = hdr->caplen; if (sync) { long usec = (hdr->ts.tv_sec - ts.tv_sec) * 1000000 + (hdr->ts.tv_usec - ts.tv_usec); getTimeStamp(&ovrEnd); overHead -= udiffTimeStamp(&ovrStart, &ovrEnd); Q_ASSERT(overHead <= 0); usec += overHead; if (usec > 0) { udelay(usec); overHead = 0; } else overHead = usec; ts = hdr->ts; getTimeStamp(&ovrStart); } Q_ASSERT(pktLen > 0); pcap_sendpacket(p, pkt, pktLen); stats_->txPkts++; stats_->txBytes += pktLen; // Step to the next packet in the buffer hdr = (struct pcap_pkthdr*) (pkt + pktLen); pkt = (uchar*) ((uchar*)hdr + sizeof(*hdr)); if (stop_) { return -2; } } return 0; } void PcapPort::PortTransmitter::udelay(long usec) { #if defined(Q_OS_WIN32) LARGE_INTEGER tgtTicks; LARGE_INTEGER curTicks; QueryPerformanceCounter(&curTicks); tgtTicks.QuadPart = curTicks.QuadPart + (usec*ticksFreq_)/1000000; while (curTicks.QuadPart < tgtTicks.QuadPart) QueryPerformanceCounter(&curTicks); #elif defined(Q_OS_LINUX) struct timeval delay, target, now; //qDebug("usec delay = %ld", usec); delay.tv_sec = 0; delay.tv_usec = usec; while (delay.tv_usec >= 1000000) { delay.tv_sec++; delay.tv_usec -= 1000000; } gettimeofday(&now, NULL); timeradd(&now, &delay, &target); do { gettimeofday(&now, NULL); } while (timercmp(&now, &target, <)); #else QThread::usleep(usec); #endif } PcapPort::PortCapturer::PortCapturer(const char *device) { device_ = QString::fromAscii(device); stop_ = false; if (!capFile_.open()) qWarning("Unable to open temp cap file"); qDebug("cap file = %s", capFile_.fileName().toAscii().constData()); dumpHandle_ = NULL; handle_ = NULL; } PcapPort::PortCapturer::~PortCapturer() { capFile_.close(); } void PcapPort::PortCapturer::run() { int flag = PCAP_OPENFLAG_PROMISCUOUS; char errbuf[PCAP_ERRBUF_SIZE] = ""; qDebug("In %s", __PRETTY_FUNCTION__); if (!capFile_.isOpen()) { qWarning("temp cap file is not open"); return; } _retry: handle_ = pcap_open_live(device_.toAscii().constData(), 65535, flag, 1000 /* ms */, errbuf); if (handle_ == NULL) { if (flag && QString(errbuf).contains("promiscuous")) { qDebug("%s:can't set promiscuous mode, trying non-promisc", device_.toAscii().constData()); flag = 0; goto _retry; } else { qDebug("%s: Error opening port %s: %s\n", __FUNCTION__, device_.toAscii().constData(), errbuf); return; } } dumpHandle_ = pcap_dump_open(handle_, capFile_.fileName().toAscii().constData()); while (1) { int ret; struct pcap_pkthdr *hdr; const uchar *data; ret = pcap_next_ex(handle_, &hdr, &data); switch (ret) { case 1: pcap_dump((uchar*) dumpHandle_, hdr, data); break; case 0: // timeout: just go back to the loop break; case -1: qWarning("%s: error reading packet (%d): %s", __PRETTY_FUNCTION__, ret, pcap_geterr(handle_)); break; case -2: default: qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret); } if (stop_) { qDebug("user requested capture stop\n"); break; } } pcap_dump_close(dumpHandle_); pcap_close(handle_); dumpHandle_ = NULL; handle_ = NULL; stop_ = false; } void PcapPort::PortCapturer::stop() { if (isRunning()) stop_ = true; } QFile* PcapPort::PortCapturer::captureFile() { return &capFile_; } ostinato-0.5.1/server/pcapport.h0000700000175300010010000001504412005505615016204 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_PCAP_PORT_H #define _SERVER_PCAP_PORT_H #include #include #include #include "abstractport.h" #include "pcapextra.h" class PcapPort : public AbstractPort { public: PcapPort(int id, const char *device); ~PcapPort(); void init(); virtual bool hasExclusiveControl() { return false; } virtual bool setExclusiveControl(bool /*exclusive*/) { return false; } virtual void clearPacketList() { transmitter_->clearPacketList(); setPacketListLoopMode(false, 0, 0); } virtual void loopNextPacketSet(qint64 size, qint64 repeats, long repeatDelaySec, long repeatDelayNsec) { transmitter_->loopNextPacketSet(size, repeats, repeatDelaySec, repeatDelayNsec); } virtual bool appendToPacketList(long sec, long nsec, const uchar *packet, int length) { return transmitter_->appendToPacketList(sec, nsec, packet, length); } virtual void setPacketListLoopMode(bool loop, quint64 secDelay, quint64 nsecDelay) { transmitter_->setPacketListLoopMode(loop, secDelay, nsecDelay); } virtual void startTransmit() { Q_ASSERT(!isDirty()); transmitter_->start(); } virtual void stopTransmit() { transmitter_->stop(); } virtual bool isTransmitOn() { return transmitter_->isRunning(); } virtual void startCapture() { capturer_->start(); } virtual void stopCapture() { capturer_->stop(); } virtual bool isCaptureOn() { return capturer_->isRunning(); } virtual QIODevice* captureData() { return capturer_->captureFile(); } protected: enum Direction { kDirectionRx, kDirectionTx }; class PortMonitor: public QThread { public: PortMonitor(const char *device, Direction direction, AbstractPort::PortStats *stats); ~PortMonitor(); void run(); void stop(); pcap_t* handle() { return handle_; } Direction direction() { return direction_; } bool isDirectional() { return isDirectional_; } bool isPromiscuous() { return isPromisc_; } protected: AbstractPort::PortStats *stats_; bool stop_; private: pcap_t *handle_; Direction direction_; bool isDirectional_; bool isPromisc_; }; class PortTransmitter: public QThread { public: PortTransmitter(const char *device); ~PortTransmitter(); void clearPacketList(); void loopNextPacketSet(qint64 size, qint64 repeats, long repeatDelaySec, long repeatDelayNsec); bool appendToPacketList(long sec, long usec, const uchar *packet, int length); void setPacketListLoopMode(bool loop, quint64 secDelay, quint64 nsecDelay) { returnToQIdx_ = loop ? 0 : -1; loopDelay_ = secDelay*long(1e6) + nsecDelay/1000; } void setHandle(pcap_t *handle); void useExternalStats(AbstractPort::PortStats *stats); void run(); void stop(); private: class PacketSequence { public: PacketSequence() { sendQueue_ = pcap_sendqueue_alloc(1*1024*1024); lastPacket_ = NULL; packets_ = 0; bytes_ = 0; usecDuration_ = 0; repeatCount_ = 1; repeatSize_ = 1; usecDelay_ = 0; } ~PacketSequence() { pcap_sendqueue_destroy(sendQueue_); } bool hasFreeSpace(int size) { if ((sendQueue_->len + size) <= sendQueue_->maxlen) return true; else return false; } int appendPacket(const struct pcap_pkthdr *pktHeader, const uchar *pktData) { if (lastPacket_) { usecDuration_ += (pktHeader->ts.tv_sec - lastPacket_->ts.tv_sec) * long(1e6); usecDuration_ += (pktHeader->ts.tv_usec - lastPacket_->ts.tv_usec); } packets_++; bytes_ += pktHeader->caplen; lastPacket_ = (struct pcap_pkthdr *) (sendQueue_->buffer + sendQueue_->len); return pcap_sendqueue_queue(sendQueue_, pktHeader, pktData); } pcap_send_queue *sendQueue_; struct pcap_pkthdr *lastPacket_; long packets_; long bytes_; ulong usecDuration_; int repeatCount_; int repeatSize_; long usecDelay_; }; void udelay(long usec); int sendQueueTransmit(pcap_t *p, pcap_send_queue *queue, long &overHead, int sync); quint64 ticksFreq_; QList packetSequenceList_; PacketSequence *currentPacketSequence_; int repeatSequenceStart_; quint64 repeatSize_; quint64 packetCount_; int returnToQIdx_; quint64 loopDelay_; bool usingInternalStats_; AbstractPort::PortStats *stats_; bool usingInternalHandle_; pcap_t *handle_; volatile bool stop_; }; class PortCapturer: public QThread { public: PortCapturer(const char *device); ~PortCapturer(); void run(); void stop(); QFile* captureFile(); private: QString device_; volatile bool stop_; QTemporaryFile capFile_; pcap_t *handle_; pcap_dumper_t *dumpHandle_; }; PortMonitor *monitorRx_; PortMonitor *monitorTx_; void updateNotes(); private: PortTransmitter *transmitter_; PortCapturer *capturer_; static pcap_if_t *deviceList_; }; #endif ostinato-0.5.1/server/portmanager.cpp0000700000175300010010000000443112005505615017224 0ustar srivatspNone/* Copyright (C) 2010-2012 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "portmanager.h" #include #include #include "bsdport.h" #include "linuxport.h" #include "pcapport.h" #include "winpcapport.h" PortManager *PortManager::instance_ = NULL; PortManager::PortManager() { int i; pcap_if_t *deviceList; pcap_if_t *device; char errbuf[PCAP_ERRBUF_SIZE]; qDebug("Retrieving the device list from the local machine\n"); if (pcap_findalldevs(&deviceList, errbuf) == -1) qDebug("Error in pcap_findalldevs_ex: %s\n", errbuf); for(device = deviceList, i = 0; device != NULL; device = device->next, i++) { AbstractPort *port; qDebug("%d. %s", i, device->name); if (device->description) qDebug(" (%s)\n", device->description); #if defined(Q_OS_WIN32) port = new WinPcapPort(i, device->name); #elif defined(Q_OS_LINUX) port = new LinuxPort(i, device->name); #elif defined(Q_OS_BSD4) port = new BsdPort(i, device->name); #else port = new PcapPort(i, device->name); #endif if (!port->isUsable()) { qDebug("%s: unable to open %s. Skipping!", __FUNCTION__, device->name); delete port; i--; continue; } portList_.append(port); } pcap_freealldevs(deviceList); foreach(AbstractPort *port, portList_) port->init(); return; } PortManager::~PortManager() { while (!portList_.isEmpty()) delete portList_.takeFirst(); } PortManager* PortManager::instance() { if (!instance_) instance_ = new PortManager; return instance_; } ostinato-0.5.1/server/portmanager.h0000700000175300010010000000210512005505615016665 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_PORT_MANAGER_H #define _SERVER_PORT_MANAGER_H #include #include "abstractport.h" class PortManager { public: PortManager(); ~PortManager(); int portCount() { return portList_.size(); } AbstractPort* port(int id) { return portList_[id]; } static PortManager* instance(); private: QList portList_; static PortManager *instance_; }; #endif ostinato-0.5.1/server/winpcapport.cpp0000700000175300010010000001457212005505615017262 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #include "winpcapport.h" #include #include #ifdef Q_OS_WIN32 const uint OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114; WinPcapPort::WinPcapPort(int id, const char *device) : PcapPort(id, device) { monitorRx_->stop(); monitorTx_->stop(); monitorRx_->wait(); monitorTx_->wait(); delete monitorRx_; delete monitorTx_; monitorRx_ = new PortMonitor(device, kDirectionRx, &stats_); monitorTx_ = new PortMonitor(device, kDirectionTx, &stats_); adapter_ = PacketOpenAdapter((CHAR*)device); if (!adapter_) qFatal("Unable to open adapter %s", device); linkStateOid_ = (PPACKET_OID_DATA) malloc(sizeof(PACKET_OID_DATA) + sizeof(uint)); if (!linkStateOid_) qFatal("failed to alloc oidData"); data_.set_is_exclusive_control(hasExclusiveControl()); minPacketSetSize_ = 256; } WinPcapPort::~WinPcapPort() { } OstProto::LinkState WinPcapPort::linkState() { memset(linkStateOid_, 0, sizeof(PACKET_OID_DATA) + sizeof(uint)); linkStateOid_->Oid = OID_GEN_MEDIA_CONNECT_STATUS; linkStateOid_->Length = sizeof(uint); if (PacketRequest(adapter_, 0, linkStateOid_)) { uint state; if (linkStateOid_->Length == sizeof(state)) { memcpy((void*)&state, (void*)linkStateOid_->Data, linkStateOid_->Length); if (state == 0) linkState_ = OstProto::LinkStateUp; else if (state == 1) linkState_ = OstProto::LinkStateDown; } } return linkState_; } bool WinPcapPort::hasExclusiveControl() { QString portName(adapter_->Name + strlen("\\Device\\NPF_")); QString bindConfigFilePath(QCoreApplication::applicationDirPath() + "/bindconfig.exe"); int exitCode; qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData()); if (!QFile::exists(bindConfigFilePath)) return false; exitCode = QProcess::execute(bindConfigFilePath, QStringList() << "comp" << portName); qDebug("%s: exit code %d", __FUNCTION__, exitCode); if (exitCode == 0) return true; else return false; } bool WinPcapPort::setExclusiveControl(bool exclusive) { QString portName(adapter_->Name + strlen("\\Device\\NPF_")); QString bindConfigFilePath(QCoreApplication::applicationDirPath() + "/bindconfig.exe"); QString status; qDebug("%s: %s", __FUNCTION__, portName.toAscii().constData()); if (!QFile::exists(bindConfigFilePath)) return false; status = exclusive ? "disable" : "enable"; QProcess::execute(bindConfigFilePath, QStringList() << "comp" << portName << status); updateNotes(); return (exclusive == hasExclusiveControl()); } WinPcapPort::PortMonitor::PortMonitor(const char *device, Direction direction, AbstractPort::PortStats *stats) : PcapPort::PortMonitor(device, direction, stats) { if (handle()) pcap_setmode(handle(), MODE_STAT); } void WinPcapPort::PortMonitor::run() { struct timeval lastTs; quint64 lastTxPkts = 0; quint64 lastTxBytes = 0; qWarning("in %s", __PRETTY_FUNCTION__); lastTs.tv_sec = 0; lastTs.tv_usec = 0; while (!stop_) { int ret; struct pcap_pkthdr *hdr; const uchar *data; ret = pcap_next_ex(handle(), &hdr, &data); switch (ret) { case 1: { quint64 pkts = *((quint64*)(data + 0)); quint64 bytes = *((quint64*)(data + 8)); // TODO: is it 12 or 16? bytes -= pkts * 12; uint usec = (hdr->ts.tv_sec - lastTs.tv_sec) * 1000000 + (hdr->ts.tv_usec - lastTs.tv_usec); switch (direction()) { case kDirectionRx: stats_->rxPkts += pkts; stats_->rxBytes += bytes; stats_->rxPps = (pkts * 1000000) / usec; stats_->rxBps = (bytes * 1000000) / usec; break; case kDirectionTx: if (isDirectional()) { stats_->txPkts += pkts; stats_->txBytes += bytes; } else { // Assuming stats_->txXXX are updated externally quint64 txPkts = stats_->txPkts; quint64 txBytes = stats_->txBytes; pkts = txPkts - lastTxPkts; bytes = txBytes - lastTxBytes; lastTxPkts = txPkts; lastTxBytes = txBytes; } stats_->txPps = (pkts * 1000000) / usec; stats_->txBps = (bytes * 1000000) / usec; break; default: Q_ASSERT(false); } break; } case 0: //qDebug("%s: timeout. continuing ...", __PRETTY_FUNCTION__); continue; case -1: qWarning("%s: error reading packet (%d): %s", __PRETTY_FUNCTION__, ret, pcap_geterr(handle())); break; case -2: qWarning("%s: error reading packet (%d): %s", __PRETTY_FUNCTION__, ret, pcap_geterr(handle())); break; default: qFatal("%s: Unexpected return value %d", __PRETTY_FUNCTION__, ret); } lastTs.tv_sec = hdr->ts.tv_sec; lastTs.tv_usec = hdr->ts.tv_usec; if (!stop_) QThread::msleep(1000); } } #endif ostinato-0.5.1/server/winpcapport.h0000700000175300010010000000255112005505615016721 0ustar srivatspNone/* Copyright (C) 2010 Srivats P. This file is part of "Ostinato" This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ #ifndef _SERVER_WIN_PCAP_PORT_H #define _SERVER_WIN_PCAP_PORT_H #include #ifdef Q_OS_WIN32 #include "pcapport.h" #include class WinPcapPort : public PcapPort { public: WinPcapPort(int id, const char *device); ~WinPcapPort(); virtual OstProto::LinkState linkState(); virtual bool hasExclusiveControl(); virtual bool setExclusiveControl(bool exclusive); protected: class PortMonitor: public PcapPort::PortMonitor { public: PortMonitor(const char *device, Direction direction, AbstractPort::PortStats *stats); void run(); }; private: LPADAPTER adapter_; PPACKET_OID_DATA linkStateOid_ ; }; #endif #endif ostinato-0.5.1/test/0000700000175300010010000000000012005505615013645 5ustar srivatspNoneostinato-0.5.1/test/main.cpp0000700000175300010010000000527412005505615015310 0ustar srivatspNone #include "ostprotolib.h" #include "pcapfileformat.h" #include "protocol.pb.h" #include "protocolmanager.h" #include "settings.h" #include #include #include #include extern ProtocolManager *OstProtocolManager; QSettings *appSettings; #if defined(Q_OS_WIN32) QString kGzipPathDefaultValue; QString kDiffPathDefaultValue; QString kAwkPathDefaultValue; #endif int usage(int /*argc*/, char* argv[]) { printf("usage:\n"); printf("%s \n", argv[0]); printf("command -\n"); printf(" importpcap\n"); return 255; } int testImportPcap(int argc, char* argv[]) { bool isOk; QString error; if (argc != 3) { printf("usage:\n"); printf("%s importpcap \n", argv[0]); return 255; } OstProto::StreamConfigList streams; QString inFile(argv[2]); isOk = pcapFileFormat.openStreams(inFile, streams, error); if (!error.isEmpty()) { printf("%s: %s\n", inFile.toAscii().constData(), error.toAscii().constData()); } if (!isOk) return 1; return 0; } int main(int argc, char* argv[]) { QCoreApplication app(argc, argv); int exitCode = 0; // app init starts ... #if defined(Q_OS_WIN32) kGzipPathDefaultValue = app.applicationDirPath() + "/gzip.exe"; kDiffPathDefaultValue = app.applicationDirPath() + "/diff.exe"; kAwkPathDefaultValue = app.applicationDirPath() + "/gawk.exe"; #endif app.setApplicationName("Ostinato"); app.setOrganizationName("Ostinato"); OstProtocolManager = new ProtocolManager(); /* (Portable Mode) If we have a .ini file in the same directory as the executable, we use that instead of the platform specific location and format for the settings */ QString portableIni = QCoreApplication::applicationDirPath() + "/ostinato.ini"; if (QFile::exists(portableIni)) appSettings = new QSettings(portableIni, QSettings::IniFormat); else appSettings = new QSettings(); OstProtoLib::setExternalApplicationPaths( appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(), appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString(), appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(), appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString()); // ... app init finished // // identify and run specified test // if (argc < 2) exitCode = usage(argc, argv); else if (strcmp(argv[1],"importpcap") == 0) exitCode = testImportPcap(argc, argv); else exitCode = usage(argc, argv); delete appSettings; return exitCode; } ostinato-0.5.1/test/test.pro0000700000175300010010000000166712005505615015363 0ustar srivatspNoneTEMPLATE = app CONFIG += qt console QT += xml network script INCLUDEPATH += "../rpc/" "../common/" "../client" win32 { LIBS += -lwpcap -lpacket CONFIG(debug, debug|release) { LIBS += -L"../common/debug" -lostproto LIBS += -L"../rpc/debug" -lpbrpc POST_TARGETDEPS += \ "../common/debug/libostproto.a" \ "../rpc/debug/libpbrpc.a" } else { LIBS += -L"../common/release" -lostproto LIBS += -L"../rpc/release" -lpbrpc POST_TARGETDEPS += \ "../common/release/libostproto.a" \ "../rpc/release/libpbrpc.a" } } else { LIBS += -lpcap LIBS += -L"../common" -lostproto LIBS += -L"../rpc" -lpbrpc POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a" } LIBS += -lprotobuf LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2 HEADERS += SOURCES += main.cpp QMAKE_DISTCLEAN += object_script.* include(../install.pri) ostinato-0.5.1/version.pri0000700000175300010010000000140512005505741015072 0ustar srivatspNoneAPP_VERSION = 0.5.1 #APP_REVISION = $(shell hg identify -i) #uncomment the below line in a source package and fill-in the correct revision APP_REVISION = 74c9dcf830e3@ APP_VERSION_FILE = version.cpp revtarget.target = $$APP_VERSION_FILE win32:revtarget.commands = echo "const char *version = \"$$APP_VERSION\";" \ "const char *revision = \"$$APP_REVISION\";" \ > $$APP_VERSION_FILE unix:revtarget.commands = echo \ "\"const char *version = \\\"$$APP_VERSION\\\";" \ "const char *revision = \\\"$$APP_REVISION\\\";\"" \ > $$APP_VERSION_FILE revtarget.depends = $$SOURCES $$HEADERS $$FORMS $$POST_TARGETDEPS SOURCES += $$APP_VERSION_FILE QMAKE_EXTRA_TARGETS += revtarget POST_TARGETDEPS += $$APP_VERSION_FILE QMAKE_DISTCLEAN += $$APP_VERSION_FILE