diff --git a/client/port.cpp b/client/port.cpp index 90992ab..3130432 100644 --- a/client/port.cpp +++ b/client/port.cpp @@ -22,10 +22,14 @@ along with this program. If not, see #include "abstractfileformat.h" #include +#include +#include #include #include #include +extern QMainWindow *mainWindow; + uint Port::mAllocStreamId = 0; uint Port::newStreamId() @@ -225,52 +229,137 @@ void Port::updateStats(OstProto::PortStats *portStats) bool Port::openStreams(QString fileName, bool append, QString &error) { + bool ret = false; + QProgressDialog progress("Opening Streams", "Cancel", 0, 0, mainWindow); OstProto::StreamConfigList streams; AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromFile(fileName); if (fmt == NULL) goto _fail; - if (!fmt->openStreams(fileName, streams, error)) + 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) { - while (numStreams()) + 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); - - return true; + ret = true; _fail: - return false; + progress.close(); + mainWindow->setEnabled(true); + 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(); } - return fmt->saveStreams(streams, fileName, error); + 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); - return false; + goto _exit; + +_exit: + progress.close(); + mainWindow->setEnabled(true); + return ret; } diff --git a/client/portswindow.cpp b/client/portswindow.cpp index 86bcf71..a2cf238 100644 --- a/client/portswindow.cpp +++ b/client/portswindow.cpp @@ -458,14 +458,15 @@ void PortsWindow::on_actionOpen_Streams_triggered() Q_ASSERT(plm->isPort(current)); - fileName = QFileDialog::getOpenFileName(this, tr("Open Streams")); + fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"), "D:/srivatsp/projects/ostinato/testfiles/pcaps"); if (fileName.isEmpty()) goto _exit; if (tvStreamList->model()->rowCount()) { QMessageBox msgBox(QMessageBox::Question, qApp->applicationName(), - tr("Append to existing streams? Or overwrite?")); + tr("Append to existing streams? Or overwrite?"), + QMessageBox::NoButton, this); QPushButton *appendBtn = msgBox.addButton(tr("Append"), QMessageBox::ActionRole); QPushButton *overwriteBtn = msgBox.addButton(tr("Overwrite"), diff --git a/common/abstractfileformat.cpp b/common/abstractfileformat.cpp index cb3fa43..f748447 100644 --- a/common/abstractfileformat.cpp +++ b/common/abstractfileformat.cpp @@ -27,6 +27,7 @@ along with this program. If not, see AbstractFileFormat::AbstractFileFormat() { + stop_ = false; } AbstractFileFormat::~AbstractFileFormat() @@ -40,10 +41,40 @@ QStringList AbstractFileFormat::supportedFileTypes() << "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; @@ -71,3 +102,16 @@ AbstractFileFormat* AbstractFileFormat::fileFormatFromType( 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_); +} diff --git a/common/abstractfileformat.h b/common/abstractfileformat.h index 7a648ee..031e4e1 100644 --- a/common/abstractfileformat.h +++ b/common/abstractfileformat.h @@ -22,12 +22,12 @@ along with this program. If not, see #include "protocol.pb.h" -#include +#include #include -class AbstractFileFormat : public QObject +class AbstractFileFormat : public QThread { - Q_OBJECT + Q_OBJECT public: AbstractFileFormat(); virtual ~AbstractFileFormat(); @@ -37,6 +37,13 @@ public: virtual bool saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error) = 0; + void openStreamsOffline(const QString fileName, + OstProto::StreamConfigList &streams, QString &error); + void saveStreamsOffline(const OstProto::StreamConfigList streams, + const QString fileName, QString &error); + + bool result(); + static AbstractFileFormat* fileFormatFromFile(const QString fileName); static AbstractFileFormat* fileFormatFromType(const QString fileType); @@ -46,6 +53,33 @@ public: 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 diff --git a/common/fileformat.cpp b/common/fileformat.cpp index 7ddc65b..aada8b1 100644 --- a/common/fileformat.cpp +++ b/common/fileformat.cpp @@ -322,6 +322,8 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams, goto _zero_cksum_serialize_fail; } + emit status("Calculating checksum..."); + // Calculate and write checksum calcCksum = checksumCrc32C((quint8*)buf.constData(), buf.size()); cksum.set_value(calcCksum); @@ -335,6 +337,7 @@ bool FileFormat::saveStreams(const OstProto::StreamConfigList streams, 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; diff --git a/common/pcapfileformat.cpp b/common/pcapfileformat.cpp index a893565..04ace99 100644 --- a/common/pcapfileformat.cpp +++ b/common/pcapfileformat.cpp @@ -64,7 +64,7 @@ PcapFileFormat::~PcapFileFormat() bool PcapFileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { - bool viaPdml = true; // TODO: shd be a param to function + bool viaPdml = false; // TODO: shd be a param to function bool isOk = false; QFile file(fileName); @@ -77,6 +77,8 @@ bool PcapFileFormat::openStreams(const QString fileName, OstProto::Stream *prevStream = NULL; uint lastUsec = 0; int pktCount; + qint64 byteCount = 0; + qint64 byteTotal; QByteArray pktBuf; if (!file.open(QIODevice::ReadOnly)) @@ -90,6 +92,9 @@ bool PcapFileFormat::openStreams(const QString fileName, { QProcess gzip; + emit status("Decompressing..."); + emit target(0); + if (!file2.open()) { error.append("Unable to open temporary file to uncompress .gz\n"); @@ -126,6 +131,11 @@ bool PcapFileFormat::openStreams(const QString fileName, fd_.setDevice(&file); } + byteTotal = fd_.device()->size() - sizeof(fileHdr); + + emit status("Reading File Header..."); + emit target(0); + fd_ >> magic; qDebug("magic = %08x", magic); @@ -173,6 +183,8 @@ bool PcapFileFormat::openStreams(const QString fileName, } qDebug("generating PDML %s", pdmlFile.fileName().toAscii().constData()); + emit status("Generating PDML..."); + emit target(0); tshark.setStandardOutputFile(pdmlFile.fileName()); // FIXME: hardcoded prog name @@ -193,12 +205,18 @@ bool PcapFileFormat::openStreams(const QString fileName, goto _non_pdml; } - isOk = reader.read(&pdmlFile, this); // TODO: pass error string? + 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_); // TODO: pass error string? goto _exit; } _non_pdml: + emit status("Reading Packets..."); + emit target(100); // in percentage pktCount = 1; while (!fd_.atEnd()) { @@ -235,11 +253,20 @@ _non_pdml: 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; + #if 1 _err_unsupported_encap: error = QString(tr("%1 has non-ethernet encapsulation (%2) which is " @@ -344,6 +371,9 @@ bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams, 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++) @@ -377,6 +407,8 @@ bool PcapFileFormat::saveStreams(const OstProto::StreamConfigList streams, pktHdr.tsSec++; pktHdr.tsUsec -= 1000000; } + + emit progress(i); } file.close(); diff --git a/common/pdml_p.cpp b/common/pdml_p.cpp index ae1c7ce..3dac8e0 100644 --- a/common/pdml_p.cpp +++ b/common/pdml_p.cpp @@ -115,6 +115,8 @@ PdmlReader::PdmlReader(OstProto::StreamConfigList *streams) currentStream_ = NULL; prevStream_ = NULL; + stop_ = NULL; + factory_.insert("hexdump", PdmlUnknownProtocol::createInstance); factory_.insert("geninfo", PdmlGenInfoProtocol::createInstance); factory_.insert("frame", PdmlFrameProtocol::createInstance); @@ -128,12 +130,13 @@ PdmlReader::~PdmlReader() { } -bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap) +bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap, bool *stop) { setDevice(device); pcap_ = pcap; packetCount_ = 0; + stop_ = stop; while (!atEnd()) { readNext(); @@ -146,7 +149,7 @@ bool PdmlReader::read(QIODevice *device, PcapFileFormat *pcap) } } - if (error()) + if (error() && (errorString() != "USER-CANCEL")) { qDebug("Line %lld", lineNumber()); qDebug("Col %lld", columnNumber()); @@ -325,8 +328,11 @@ void PdmlReader::readPacket() } packetCount_++; + emit progress(int(characterOffset()*100/device()->size())); if (prevStream_) prevStream_->mutable_control()->CopyFrom(currentStream_->control()); + if (stop_ && *stop_) + raiseError("USER-CANCEL"); } void PdmlReader::readProto() diff --git a/common/pdml_p.h b/common/pdml_p.h index 42ea327..af7c4f6 100644 --- a/common/pdml_p.h +++ b/common/pdml_p.h @@ -62,14 +62,18 @@ protected: class PdmlUnknownProtocol; class PcapFileFormat; -class PdmlReader : public QXmlStreamReader +class PdmlReader : public QObject, public QXmlStreamReader { + Q_OBJECT friend class PdmlUnknownProtocol; public: PdmlReader(OstProto::StreamConfigList *streams); ~PdmlReader(); - bool read(QIODevice *device, PcapFileFormat *pcap = NULL); + bool read(QIODevice *device, PcapFileFormat *pcap = NULL, + bool *stop = NULL); +signals: + void progress(int value); private: PdmlDefaultProtocol* allocPdmlProtocol(QString protoName); @@ -103,6 +107,7 @@ private: OstProto::Stream *currentStream_; QByteArray pktBuf_; + bool *stop_; }; class PdmlUnknownProtocol : public PdmlDefaultProtocol diff --git a/common/pdmlfileformat.cpp b/common/pdmlfileformat.cpp index 0c51652..1e2c4c8 100644 --- a/common/pdmlfileformat.cpp +++ b/common/pdmlfileformat.cpp @@ -30,39 +30,6 @@ PdmlFileFormat::~PdmlFileFormat() { } -#if 0 -bool PdmlFileFormat::openStreams(const QString fileName, - OstProto::StreamConfigList &streams, QString &error) -{ - bool isOk; - QFile file(fileName); - PdmlParser *pdml; - QXmlSimpleReader *xmlReader; - QXmlInputSource *xmlSource; - - if (!file.open(QIODevice::ReadOnly)) - goto _open_fail; - - pdml = new PdmlParser(&streams); - xmlSource = new QXmlInputSource(&file); - xmlReader = new QXmlSimpleReader; - xmlReader->setContentHandler(pdml); - xmlReader->setErrorHandler(pdml); - isOk = xmlReader->parse(xmlSource, false); // non-incremental parse - - goto _exit; - -_open_fail: - isOk = false; - -_exit: - delete xmlReader; - delete xmlSource; - delete pdml; - - return isOk; -} -#else bool PdmlFileFormat::openStreams(const QString fileName, OstProto::StreamConfigList &streams, QString &error) { @@ -73,6 +40,10 @@ bool PdmlFileFormat::openStreams(const QString fileName, 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 + // TODO: fill in error string isOk = reader->read(&file); @@ -87,7 +58,6 @@ _exit: return isOk; } -#endif bool PdmlFileFormat::saveStreams(const OstProto::StreamConfigList streams, const QString fileName, QString &error)