From: Hiroaki Yamamoto Date: Sat, 6 Nov 2010 02:00:50 +0000 (+0900) Subject: Added: X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=99103843c2a61d725959c96db09be1be142efc09;p=greensite%2Fjasmine.git Added: * QtLockedFile: Locking file needs this class. This class is in Qt developpers website: http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Utilities/qtlockedfile/ * threadedTcpSocket: This is tcpSocket class that run in non-main thread. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 67c3f86..31b1ac0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ set(ui_h ui/settingdialog.h ui/rtfeditor.h ) +#set(file_h file/qtlockedfile.h) #Ui files set(ui @@ -58,6 +59,9 @@ set(ui_src ui/settingdialog.cxx ui/rtfeditor.cxx ) +set(file_impl file/qtlockedfile.cxx) +set(file_win32 file/qtlockedfile_win.cxx) +set(file_unix file/qtlockedfile_unix.cxx) #resource files set(res @@ -65,7 +69,7 @@ set(res ) qt4_wrap_cpp(network_moc ${network_h}) - +#qt4_wrap_cpp(file_moc ${file_h}) qt4_wrap_cpp(ui_moc ${ui_h}) qt4_wrap_ui(ui_moc ${ui}) qt4_add_resources(res_moc ${res}) @@ -74,14 +78,15 @@ if(WIN32) add_executable(jasmine WIN32 ${main} ${ui_moc} ${ui_src} ${network_moc} ${network_src} ${structures} ${res_moc} - ${validator} ${ported_rmd6}) + ${validator} ${ported_rmd6} ${file_win32} + ${file_impl}) set_property(TARGET jasmine PROPERTY COMPLILE_FLAGS ${OpenMP_CXX_FLAGS} APPEND) target_link_libraries(jasmine gomp ${QT_LIBRARIES}) else(OPENMP_FOUND) add_executable(jasmine WIN32 ${main} ${ui_moc} ${ui_src} ${network_moc} ${network_src} ${structures} ${res_moc} - ${validator} ${ported_rmd6}) + ${validator} ${ported_rmd6} ${file_win32} ${file_impl}) target_link_libraries(jasmine ${QT_LIBRARIES}) endif(OPENMP_FOUND) else(WIN32) @@ -92,6 +97,7 @@ else(WIN32) add_library(network SHARED ${network_moc} ${network_src}) add_library(ui SHARED ${ui_moc} ${ui_src}) + add_library(file SHARED ${file_unix} ${file_impl}) add_executable(jasmine ${main}) @@ -99,10 +105,11 @@ else(WIN32) target_link_libraries(validator ${QT_LIBRARIES}) target_link_libraries(resource ${QT_LIBRARIES}) target_link_libraries(structures ${QT_LIBRARIES}) + target_link_libraries(file ${QT_LIBRARIES}) target_link_libraries(structures qripemd160 ${QT_LIBRARIES}) - target_link_libraries(network structures validator ${QT_LIBRARIES}) - target_link_libraries(ui resource network ${QT_LIBRARIES}) + target_link_libraries(network structures validator file ${QT_LIBRARIES}) + target_link_libraries(ui resource network file ${QT_LIBRARIES}) target_link_libraries(jasmine ui ${QT_LIBRARIES}) if(OPENMP_FOUND) diff --git a/file/QtLockedFile b/file/QtLockedFile new file mode 100644 index 0000000..16b48ba --- /dev/null +++ b/file/QtLockedFile @@ -0,0 +1 @@ +#include "qtlockedfile.h" diff --git a/file/qtlockedfile.cxx b/file/qtlockedfile.cxx new file mode 100644 index 0000000..2cf0805 --- /dev/null +++ b/file/qtlockedfile.cxx @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of a Qt Solutions component. +** +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Solutions Commercial License Agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** Please note Third Party Software included with Qt Solutions may impose +** additional restrictions and it is the user's responsibility to ensure +** that they have met the licensing requirements of the GPL, LGPL, or Qt +** Solutions Commercial license and the relevant license of the Third +** Party Software they are using. +** +** If you are unsure which license is appropriate for your use, please +** contact Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#include "qtlockedfile.h" + +/*! + \class QtLockedFile + + \brief The QtLockedFile class extends QFile with advisory locking + functions. + + A file may be locked in read or write mode. Multiple instances of + \e QtLockedFile, created in multiple processes running on the same + machine, may have a file locked in read mode. Exactly one instance + may have it locked in write mode. A read and a write lock cannot + exist simultaneously on the same file. + + The file locks are advisory. This means that nothing prevents + another process from manipulating a locked file using QFile or + file system functions offered by the OS. Serialization is only + guaranteed if all processes that access the file use + QLockedFile. Also, while holding a lock on a file, a process + must not open the same file again (through any API), or locks + can be unexpectedly lost. + + The lock provided by an instance of \e QtLockedFile is released + whenever the program terminates. This is true even when the + program crashes and no destructors are called. +*/ + +/*! \enum QtLockedFile::LockMode + + This enum describes the available lock modes. + + \value ReadLock A read lock. + \value WriteLock A write lock. + \value NoLock Neither a read lock nor a write lock. +*/ + +/*! + Constructs an unlocked \e QtLockedFile object. This constructor + behaves in the same way as \e QFile::QFile(). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile() + : QFile() +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Constructs an unlocked QtLockedFile object with file \a name. This + constructor behaves in the same way as \e QFile::QFile(const + QString&). + + \sa QFile::QFile() +*/ +QtLockedFile::QtLockedFile(const QString &name) + : QFile(name) +{ +#ifdef Q_OS_WIN + wmutex = 0; + rmutex = 0; +#endif + m_lock_mode = NoLock; +} + +/*! + Opens the file in OpenMode \a mode. + + This is identical to QFile::open(), with the one exception that the + Truncate mode flag is disallowed. Truncation would conflict with the + advisory file locking, since the file would be modified before the + write lock is obtained. If truncation is required, use resize(0) + after obtaining the write lock. + + Returns true if successful; otherwise false. + + \sa QFile::open(), QFile::resize() +*/ +bool QtLockedFile::open(OpenMode mode) +{ + if (mode & QIODevice::Truncate) { + qWarning("QtLockedFile::open(): Truncate mode not allowed."); + return false; + } + return QFile::open(mode); +} + +/*! + Returns \e true if this object has a in read or write lock; + otherwise returns \e false. + + \sa lockMode() +*/ +bool QtLockedFile::isLocked() const +{ + return m_lock_mode != NoLock; +} + +/*! + Returns the type of lock currently held by this object, or \e + QtLockedFile::NoLock. + + \sa isLocked() +*/ +QtLockedFile::LockMode QtLockedFile::lockMode() const +{ + return m_lock_mode; +} + +/*! + \fn bool QtLockedFile::lock(LockMode mode, bool block = true) + + Obtains a lock of type \a mode. The file must be opened before it + can be locked. + + If \a block is true, this function will block until the lock is + aquired. If \a block is false, this function returns \e false + immediately if the lock cannot be aquired. + + If this object already has a lock of type \a mode, this function + returns \e true immediately. If this object has a lock of a + different type than \a mode, the lock is first released and then a + new lock is obtained. + + This function returns \e true if, after it executes, the file is + locked by this object, and \e false otherwise. + + \sa unlock(), isLocked(), lockMode() +*/ + +/*! + \fn bool QtLockedFile::unlock() + + Releases a lock. + + If the object has no lock, this function returns immediately. + + This function returns \e true if, after it executes, the file is + not locked by this object, and \e false otherwise. + + \sa lock(), isLocked(), lockMode() +*/ + +/*! + \fn QtLockedFile::~QtLockedFile() + + Destroys the \e QtLockedFile object. If any locks were held, they + are released. +*/ diff --git a/file/qtlockedfile.h b/file/qtlockedfile.h new file mode 100644 index 0000000..1d3b918 --- /dev/null +++ b/file/qtlockedfile.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of a Qt Solutions component. +** +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Solutions Commercial License Agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** Please note Third Party Software included with Qt Solutions may impose +** additional restrictions and it is the user's responsibility to ensure +** that they have met the licensing requirements of the GPL, LGPL, or Qt +** Solutions Commercial license and the relevant license of the Third +** Party Software they are using. +** +** If you are unsure which license is appropriate for your use, please +** contact Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#ifndef QTLOCKEDFILE_H +#define QTLOCKEDFILE_H + +#include +#ifdef Q_OS_WIN +#include +#endif + +#if defined(Q_WS_WIN) +# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT) +# define QT_QTLOCKEDFILE_EXPORT +# elif defined(QT_QTLOCKEDFILE_IMPORT) +# if defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# endif +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport) +# elif defined(QT_QTLOCKEDFILE_EXPORT) +# undef QT_QTLOCKEDFILE_EXPORT +# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTLOCKEDFILE_EXPORT +#endif + +class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile +{ +public: + enum LockMode { NoLock = 0, ReadLock, WriteLock }; + + QtLockedFile(); + QtLockedFile(const QString &name); + ~QtLockedFile(); + + bool open(OpenMode mode); + + bool lock(LockMode mode, bool block = true); + bool unlock(); + bool isLocked() const; + LockMode lockMode() const; + +private: +#ifdef Q_OS_WIN + Qt::HANDLE wmutex; + Qt::HANDLE rmutex; + QVector rmutexes; + QString mutexname; + + Qt::HANDLE getMutexHandle(int idx, bool doCreate); + bool waitMutex(Qt::HANDLE mutex, bool doBlock); + +#endif + LockMode m_lock_mode; +}; + +#endif diff --git a/file/qtlockedfile_unix.cxx b/file/qtlockedfile_unix.cxx new file mode 100644 index 0000000..2881bdd --- /dev/null +++ b/file/qtlockedfile_unix.cxx @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of a Qt Solutions component. +** +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Solutions Commercial License Agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** Please note Third Party Software included with Qt Solutions may impose +** additional restrictions and it is the user's responsibility to ensure +** that they have met the licensing requirements of the GPL, LGPL, or Qt +** Solutions Commercial license and the relevant license of the Third +** Party Software they are using. +** +** If you are unsure which license is appropriate for your use, please +** contact Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qtlockedfile.h" + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK; + int cmd = block ? F_SETLKW : F_SETLK; + int ret = fcntl(handle(), cmd, &fl); + + if (ret == -1) { + if (errno != EINTR && errno != EAGAIN) + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + + m_lock_mode = mode; + return true; +} + + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + struct flock fl; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_type = F_UNLCK; + int ret = fcntl(handle(), F_SETLKW, &fl); + + if (ret == -1) { + qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno)); + return false; + } + + m_lock_mode = NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); +} + diff --git a/file/qtlockedfile_win.cxx b/file/qtlockedfile_win.cxx new file mode 100644 index 0000000..d4bf9e1 --- /dev/null +++ b/file/qtlockedfile_win.cxx @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of a Qt Solutions component. +** +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Solutions Commercial License Agreement provided +** with the Software or, alternatively, in accordance with the terms +** contained in a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** Please note Third Party Software included with Qt Solutions may impose +** additional restrictions and it is the user's responsibility to ensure +** that they have met the licensing requirements of the GPL, LGPL, or Qt +** Solutions Commercial license and the relevant license of the Third +** Party Software they are using. +** +** If you are unsure which license is appropriate for your use, please +** contact Nokia at qt-info@nokia.com. +** +****************************************************************************/ + +#include "qtlockedfile.h" +#include +#include + +#define MUTEX_PREFIX "QtLockedFile mutex " +// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS +#define MAX_READERS MAXIMUM_WAIT_OBJECTS + +Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate) +{ + if (mutexname.isEmpty()) { + QFileInfo fi(*this); + mutexname = QString::fromLatin1(MUTEX_PREFIX) + + fi.absoluteFilePath().toLower(); + } + QString mname(mutexname); + if (idx >= 0) + mname += QString::number(idx); + + Qt::HANDLE mutex; + if (doCreate) { + QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + qErrnoWarning("QtLockedFile::lock(): CreateMutex failed"); + return 0; + } + } + else { + QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); }, + { mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } ); + if (!mutex) { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + qErrnoWarning("QtLockedFile::lock(): OpenMutex failed"); + return 0; + } + } + return mutex; +} + +bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock) +{ + Q_ASSERT(mutex); + DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0); + switch (res) { + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + return true; + break; + case WAIT_TIMEOUT: + break; + default: + qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed"); + } + return false; +} + + + +bool QtLockedFile::lock(LockMode mode, bool block) +{ + if (!isOpen()) { + qWarning("QtLockedFile::lock(): file is not opened"); + return false; + } + + if (mode == NoLock) + return unlock(); + + if (mode == m_lock_mode) + return true; + + if (m_lock_mode != NoLock) + unlock(); + + if (!wmutex && !(wmutex = getMutexHandle(-1, true))) + return false; + + if (!waitMutex(wmutex, block)) + return false; + + if (mode == ReadLock) { + int idx = 0; + for (; idx < MAX_READERS; idx++) { + rmutex = getMutexHandle(idx, false); + if (!rmutex || waitMutex(rmutex, false)) + break; + CloseHandle(rmutex); + } + bool ok = true; + if (idx >= MAX_READERS) { + qWarning("QtLockedFile::lock(): too many readers"); + rmutex = 0; + ok = false; + } + else if (!rmutex) { + rmutex = getMutexHandle(idx, true); + if (!rmutex || !waitMutex(rmutex, false)) + ok = false; + } + if (!ok && rmutex) { + CloseHandle(rmutex); + rmutex = 0; + } + ReleaseMutex(wmutex); + if (!ok) + return false; + } + else { + Q_ASSERT(rmutexes.isEmpty()); + for (int i = 0; i < MAX_READERS; i++) { + Qt::HANDLE mutex = getMutexHandle(i, false); + if (mutex) + rmutexes.append(mutex); + } + if (rmutexes.size()) { + DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(), + TRUE, block ? INFINITE : 0); + if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) { + if (res != WAIT_TIMEOUT) + qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed"); + m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky + unlock(); + return false; + } + } + } + + m_lock_mode = mode; + return true; +} + +bool QtLockedFile::unlock() +{ + if (!isOpen()) { + qWarning("QtLockedFile::unlock(): file is not opened"); + return false; + } + + if (!isLocked()) + return true; + + if (m_lock_mode == ReadLock) { + ReleaseMutex(rmutex); + CloseHandle(rmutex); + rmutex = 0; + } + else { + foreach(Qt::HANDLE mutex, rmutexes) { + ReleaseMutex(mutex); + CloseHandle(mutex); + } + rmutexes.clear(); + ReleaseMutex(wmutex); + } + + m_lock_mode = QtLockedFile::NoLock; + return true; +} + +QtLockedFile::~QtLockedFile() +{ + if (isOpen()) + unlock(); + if (wmutex) + CloseHandle(wmutex); +} diff --git a/jasmine.pro b/jasmine.pro index f2553e6..aa6b01b 100644 --- a/jasmine.pro +++ b/jasmine.pro @@ -6,6 +6,7 @@ DEPENDPATH += . \ res \ network \ ported_rmd6 \ + file \ INCLUDEPATH \ += \ . @@ -25,7 +26,9 @@ HEADERS += ported_rmd6/basis.h \ network/tcpnetwork.h \ app_version.h \ settings.h \ - definition.h + definition.h \ + file/QtLockedFile \ + file/qtlockedfile.h FORMS += ui/uifiles/about.ui \ ui/uifiles/jasmine_main.ui \ ui/uifiles/settings.ui @@ -45,5 +48,9 @@ SOURCES += ported_rmd6/basis.cxx \ validator/ipaddressvalidator.cxx \ structures/header.cxx \ network/tcpnetwork.cxx \ + file/qtlockedfile.cxx \ settings.cxx \ main.cxx + +unix:SOURCES+=file/qtlockedfile_unix.cxx +win32:SOURCES+=file/qtlockedfile_win.cxx diff --git a/main.cxx b/main.cxx index 41d0c62..089ad7c 100644 --- a/main.cxx +++ b/main.cxx @@ -7,9 +7,13 @@ QString Non_public_title(QObject::tr("Warning! This software is not public version!")), Non_public_body(QObject::tr("This software is not public version. So, please note that many bugs may exist and many features are not implemented.")); -//I will implement i18n. Unfortunately, I have no time because I'm studying third language, researching japanese ideology, and so on. int main(int argc,char* argv[]){ QApplication app(argc,argv); + app.setApplicationName("jasmine"); + app.setApplicationVersion(QString("Gen.%1 Rev.%2").arg(gen).arg(rev)); + QTranslator translator; + translator.load(app.applicationName()+"-"+QLocale::system().name(),qApp->applicationDirPath()+"/translators"); + app.installTranslator(&translator); mainWindow window; if(rev==0) QMessageBox::warning(NULL,Non_public_title,Non_public_body); QFileInfo memberlist(default_memberlist),setting(default_setting); diff --git a/network/tcpnetwork.cxx b/network/tcpnetwork.cxx index ad946db..5bde241 100644 --- a/network/tcpnetwork.cxx +++ b/network/tcpnetwork.cxx @@ -7,15 +7,101 @@ using namespace enc_hash; using namespace structures; using namespace std; tcpServer::tcpServer(quint64 buffersize, QObject *parent):QTcpServer(parent){this->buffersize=buffersize;} + void tcpServer::incomingConnection(int handle){ tcpSocket *socket=new tcpSocket(this->buffersize,this); - if(!socket->setSocketDescriptor(handle)){ emit this->socket_error(*socket); - delete socket; return; } - emit (emit this->pending(*socket))?this->newConnection():socket->abort(); + if(emit this->pending(*socket)) this->newConnection(); + else socket->abort(); +} + +threadedTcpSocket::threadedTcpSocket(int descriptor, quint64 buffersize, QObject *parent):QThread(parent){ + this->handle=descriptor; + this->buffersize=buffersize; + this->mode=threadedTcpSocket::receive; + this->locker=new QReadWriteLock(QReadWriteLock::Recursive); + this->start(); +} +threadedTcpSocket::threadedTcpSocket(const QString &senderName, const AddressAndPort &to,quint64 buffersize, QObject *parent):QThread(parent){ + this->senderName=senderName; + this->buffersize=buffersize; + this->mode=threadedTcpSocket::send; + this->to=to; + this->locker=new QReadWriteLock(QReadWriteLock::Recursive); + this->start(); +} +QString threadedTcpSocket::errorString() const{ + return this->eStr; +} +void threadedTcpSocket::getErrorStringAndEmitError(const QAbstractSocket::SocketError &error){ + tcpSocket *socket=qobject_cast(this->sender()); + this->eStr=socket->errorString(); + emit this->error(error); +} + +void threadedTcpSocket::connect_function(tcpSocket *socket){ + Qt::ConnectionType connection=Qt::BlockingQueuedConnection; + connect(socket,SIGNAL(file_pending()),SIGNAL(file_pending()),connection); + connect(socket, + SIGNAL(fileStream_openFailed(const QFile::FileError &,const QString &)), + SIGNAL(fileStream_openFailed(const QFile::FileError &,const QString &)), + connection); + connect(socket,SIGNAL(msg_received(const QString &)), + SIGNAL(msg_received(const QString &)),connection); + connect(socket,SIGNAL(file_receive_progress(const quint64)), + SIGNAL(file_receive_progress(const quint64)),connection); + connect(socket,SIGNAL(file_saved()),SIGNAL(file_saved()),connection); + + connect(socket,SIGNAL(sentData()),SIGNAL(sentData()),connection); + connect(socket,SIGNAL(file_header_sent()),SIGNAL(file_header_sent()),connection); + connect(socket,SIGNAL(sending_file_progress(const quint64)), + SIGNAL(sending_file_progress(const quint64)),connection); + connect(socket,SIGNAL(error(const QAbstractSocket::SocketError &)), + SLOT(getErrorStringAndEmitError(const QAbstractSocket::SocketError &)),connection); +} +void threadedTcpSocket::run(){ + switch(this->mode){ + case threadedTcpSocket::receive: + this->socket=new tcpSocket(this->buffersize,this); + this->locker->lockForRead(); + this->connect_function(this->socket); + this->locker->unlock(); + this->locker->lockForWrite(); + this->socket->setSocketDescriptor(this->handle); + this->locker->unlock(); + break; + case threadedTcpSocket::send: + this->socket=new tcpSocket(this->senderName,this->buffersize,this); + this->locker->lockForRead(); + this->connect_function(this->socket); + this->locker->unlock(); + break; + case threadedTcpSocket::send_msg: + this->locker->lockForWrite(); + (*this->socket)<msg; + this->locker->unlock(); + break; + case threadedTcpSocket::send_file: + this->locker->lockForWrite(); + (*this->socket)<file; + this->locker->unlock(); + break; + } +} +threadedTcpSocket &threadedTcpSocket::operator<<(const QString &msg){ + this->msg=msg; + this->mode=threadedTcpSocket::send_msg; + this->start(); +return (*this); +} +threadedTcpSocket &threadedTcpSocket::operator<<(const QFileInfo &file){ + this->file=file; + this->mode=threadedTcpSocket::send_file; + this->start(); + return (*this); } tcpSocket::tcpSocket(quint64 buffersize, QObject *parent):QTcpSocket(parent){ @@ -174,8 +260,8 @@ tcpSocket &tcpSocket::operator<<(const QString &msg){ emit this->sentData(); return (*this); } -tcpSocket &tcpSocket::operator<<(QFile &src_file){ - QFile file(src_file.fileName(),this); +tcpSocket &tcpSocket::operator<<(const QFileInfo &src_file){ + QtLockedFile file(src_file.fileName()); if(!this->state()!=QAbstractSocket::ConnectedState)return (*this); this->head_data=header(this->senderName,QFileInfo(file)); QByteArray tmp_buffer; @@ -193,10 +279,13 @@ tcpSocket &tcpSocket::operator<<(QFile &src_file){ emit this->error(QAbstractSocket::UnknownSocketError); return (*this); } + file.lock(QtLockedFile::ReadLock); while(this->write(file.read(this->buffer_size))>0&&!this->check_canceled_then_abort()){ if(!this->flush())return (*this); emit this->sending_file_progress(file.pos()); } + file.unlock(); + file.close(); emit this->sentData(); return (*this); } diff --git a/network/tcpnetwork.h b/network/tcpnetwork.h index 77c882f..45d174a 100644 --- a/network/tcpnetwork.h +++ b/network/tcpnetwork.h @@ -1,5 +1,6 @@ #pragma once #include +#include "../file/QtLockedFile" #include "../definition.h" #include "../structures/header.h" #include "../definition.h" @@ -22,6 +23,46 @@ namespace network{ quint64 buffersize; }; + class threadedTcpSocket:virtual public QThread{ + Q_OBJECT + public: + //This constructor is for server. it works as a session. + threadedTcpSocket(int,quint64 buffersize=default_bandwidth,QObject *parent=NULL); + //This constructor is for client. it works as a client. + threadedTcpSocket(const QString &senderName,const AddressAndPort &,quint64 buffersize=default_buffer_size,QObject *parent=NULL); + QString errorString() const; + threadedTcpSocket &operator<<(const QString &); + threadedTcpSocket &operator<<(const QFileInfo &); + //threadedTcpSocket &operator<<(QFile &); + signals: + QString file_pending() const; + QString fileStream_openFailed(const QFile::FileError &,const QString &) const; + + void msg_received(const QString &) const; + + void file_receive_progress(const quint64 streamPos) const; + void file_saved() const; + + void sentData(); + void file_header_sent(); + void sending_file_progress(const quint64 pos); + void error(const QAbstractSocket::SocketError &); + private slots: + void getErrorStringAndEmitError(const QAbstractSocket::SocketError &); + protected: + void run(); + private: + void connect_function(tcpSocket *socket); + enum Mode{receive,send,send_msg,send_file} mode; + tcpSocket *socket; + AddressAndPort to; + QString senderName,eStr,msg; + QFileInfo file; + QReadWriteLock *locker; + int handle; + quint64 buffersize; + }; + class tcpSocket:public QTcpSocket{ Q_OBJECT public: @@ -33,7 +74,7 @@ namespace network{ structures::header header_data() const; //Calling operator<<(QFile), the specified file stream will be copied. tcpSocket &operator<<(const QString &), - &operator<<(QFile &); + &operator<<(const QFileInfo &); signals: QString file_pending() const; QString fileStream_openFailed(const QFile::FileError &,const QString &) const; @@ -61,7 +102,6 @@ namespace network{ quint16 header_size,buffer_size,timeout_time; structures::header head_data; bool canceled; - QString where_to_save; - QString senderName; + QString where_to_save, senderName; }; } diff --git a/ui/jasmine_mainwindow.cxx b/ui/jasmine_mainwindow.cxx index a4e9eb1..c535582 100644 --- a/ui/jasmine_mainwindow.cxx +++ b/ui/jasmine_mainwindow.cxx @@ -70,7 +70,7 @@ void mainWindow::showEvent(QShowEvent *event){ //Client behavior void mainWindow::on_sendButton_clicked(){ QList addressList=this->memberList->addressPortList(); -#ifdef _OMP +#ifdef _OPENMP #pragma omp parallel for #endif for(int index=0;index