OSDN Git Service

Added:
authorHiroaki Yamamoto <admin@hysoftware.net>
Sat, 6 Nov 2010 02:00:50 +0000 (11:00 +0900)
committerHiroaki Yamamoto <admin@hysoftware.net>
Sat, 6 Nov 2010 02:00:50 +0000 (11:00 +0900)
* 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.

CMakeLists.txt
file/QtLockedFile [new file with mode: 0644]
file/qtlockedfile.cxx [new file with mode: 0644]
file/qtlockedfile.h [new file with mode: 0644]
file/qtlockedfile_unix.cxx [new file with mode: 0644]
file/qtlockedfile_win.cxx [new file with mode: 0644]
jasmine.pro
main.cxx
network/tcpnetwork.cxx
network/tcpnetwork.h
ui/jasmine_mainwindow.cxx

index 67c3f86..31b1ac0 100644 (file)
@@ -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 (file)
index 0000000..16b48ba
--- /dev/null
@@ -0,0 +1 @@
+#include "qtlockedfile.h"
diff --git a/file/qtlockedfile.cxx b/file/qtlockedfile.cxx
new file mode 100644 (file)
index 0000000..2cf0805
--- /dev/null
@@ -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 (file)
index 0000000..1d3b918
--- /dev/null
@@ -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 <QtCore/QFile>
+#ifdef Q_OS_WIN
+#include <QtCore/QVector>
+#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<Qt::HANDLE> 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 (file)
index 0000000..2881bdd
--- /dev/null
@@ -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 <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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 (file)
index 0000000..d4bf9e1
--- /dev/null
@@ -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 <qt_windows.h>
+#include <QtCore/QFileInfo>
+
+#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);
+}
index f2553e6..aa6b01b 100644 (file)
@@ -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
index 41d0c62..089ad7c 100644 (file)
--- 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);
index ad946db..5bde241 100644 (file)
@@ -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<tcpSocket *>(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)<<this->msg;
+               this->locker->unlock();
+               break;
+       case threadedTcpSocket::send_file:
+               this->locker->lockForWrite();
+                       (*this->socket)<<this->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);
 }
index 77c882f..45d174a 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 #include <QtNetwork>
+#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;
        };
 }
index a4e9eb1..c535582 100644 (file)
@@ -70,7 +70,7 @@ void mainWindow::showEvent(QShowEvent *event){
 //Client behavior
 void mainWindow::on_sendButton_clicked(){
        QList<AddressAndPort> addressList=this->memberList->addressPortList();
-#ifdef _OMP
+#ifdef _OPENMP
 #pragma omp parallel for
 #endif
        for(int index=0;index<addressList.size();index++){