OSDN Git Service

Added threadedTcpSocket
authorHiroaki Yamamoto <admin@hysoftware.net>
Thu, 10 Mar 2011 01:13:24 +0000 (10:13 +0900)
committerHiroaki Yamamoto <admin@hysoftware.net>
Thu, 10 Mar 2011 01:13:24 +0000 (10:13 +0900)
Unlike tcpSocket, this socket works as tcp socket in the different thread.

However, checking if the memberlist contains sender is not available. This will be fixed in next commit.

12 files changed:
CMakeLists.txt
jasmine.pro
main.cxx
network/client.cxx [new file with mode: 0644]
network/server.cxx [new file with mode: 0644]
network/tcpnetwork.cxx
network/tcpnetwork.h
readme.txt
structures/header.cxx
structures/header.h
ui/jasmine_mainwindow.cxx
ui/jasmine_mainwindow.h

index a7cd247..ee3c6c5 100644 (file)
@@ -50,6 +50,8 @@ set(ui
 #The implementation files
 set(network_src
     network/tcpnetwork.cxx
+    network/server.cxx
+    network/client.cxx
 )
 set(ui_src
     ui/about.cxx
index aa6b01b..7c4479e 100644 (file)
@@ -48,6 +48,8 @@ SOURCES += ported_rmd6/basis.cxx \
     validator/ipaddressvalidator.cxx \
     structures/header.cxx \
        network/tcpnetwork.cxx \
+    network/server.cxx \
+    network/client.cxx \
        file/qtlockedfile.cxx \
     settings.cxx \
     main.cxx
index dbbd13d..068e6f3 100644 (file)
--- a/main.cxx
+++ b/main.cxx
@@ -1,5 +1,6 @@
 #include <QtGui>
 #include <QCoreApplication>
+#include <iostream>
 #include "ui/jasmine_mainwindow.h"
 #include "app_version.h"
 #include "definition.h"
diff --git a/network/client.cxx b/network/client.cxx
new file mode 100644 (file)
index 0000000..5fc7e9b
--- /dev/null
@@ -0,0 +1,207 @@
+#include "tcpnetwork.h"
+#include <cstring>
+#include "../structures/header.h"
+
+using namespace network;
+using namespace enc_hash;
+using namespace structures;
+using namespace std;
+
+//Tcp socket(for client) constructor
+tcpSocket::tcpSocket(const QString &senderName,const quint64 buffersize,QObject *parent):QTcpSocket(parent){
+    this->buffer_size=buffersize;
+    this->senderName=senderName;
+    this->event=tcpSocket::Size;
+    connect(this,SIGNAL(readyRead()),SLOT(client_receive_flag()));
+}
+//Moving event
+void tcpSocket::client_move_section(){
+    switch(this->event){
+    case tcpSocket::Size:
+        this->event=tcpSocket::Header;
+        break;
+    case tcpSocket::Header:
+        this->event=(this->head_data.fileName().isNull()?tcpSocket::Msg:tcpSocket::File);
+        break;
+    default:
+        this->event=tcpSocket::End;
+        break;
+    }
+    this->client_process_event();
+}
+//Dispatch events
+bool tcpSocket::client_process_event(){
+    bool result;
+#ifdef DEBUG
+        qDebug()<<"Client Event:"<<this->event;
+#endif
+    switch(this->event){
+    case tcpSocket::Size:
+        result=this->client_send_size();
+        break;
+    case tcpSocket::Header:
+        result=this->client_send_header();
+        break;
+    case tcpSocket::Msg:
+        result=this->client_send_msg();
+        break;
+    case tcpSocket::File:
+        result=this->client_send_file();
+    case tcpSocket::End:
+        emit this->sentData();
+        result=true;
+        break;
+    }
+    return result;
+}
+bool tcpSocket::client_flush(){
+    bool result=this->flush();
+    if(!result){
+        this->setErrorString(tr("The data couldn't be sent"));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+    }
+    return result;
+}
+
+bool tcpSocket::client_send_size(){
+    this->head_data=header(this->senderName,this->msg);
+    QDataStream datastream(&this->tmp_buffer,QIODevice::WriteOnly);
+    datastream<<this->head_data;
+    quint16 size=(quint16)this->tmp_buffer.size();
+    this->write((char*)&size,sizeof(size));
+    if(!this->client_flush()) return false;
+#ifdef DEBUG
+    qDebug()<<"Client:size of header has been sent successfully. The size is:"<<size;
+#endif
+    this->client_move_section();
+    return true;
+}
+
+bool tcpSocket::client_send_header(){
+    this->write(this->tmp_buffer);
+    if(!this->client_flush()) return false;
+#ifdef DEBUG
+    qDebug()<<"Client:header has been sent successfully.";
+#endif
+    this->client_move_section();
+    return true;
+}
+
+bool tcpSocket::client_send_msg(){
+    QBuffer memoryStream(&this->msg);
+    if(!memoryStream.open(QIODevice::ReadOnly)){
+        this->setErrorString(tr("Memory Stream couldn't open."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+        return false;
+    }
+    while(this->write(memoryStream.read(this->buffer_size))>0)
+        if(!this->client_flush()){
+        memoryStream.close();
+        return false;
+    }
+    memoryStream.close();
+#ifdef DEBUG
+    qDebug()<<"Client:data has been sent successfully.";
+#endif
+    this->client_move_section();
+    return true;
+}
+
+bool tcpSocket::client_send_file(){
+return false;
+}
+
+void tcpSocket::client_receive_flag(){
+    if(this->bytesAvailable()<4) return;
+    QByteArray data=this->readAll();
+#ifdef DEBUG
+    qDebug()<<"Client:received flag:"<<(Flag)data.toInt();
+#endif
+    switch((Flag)data.toInt()){
+    case tcpSocket::accepted:
+        break;
+    case tcpSocket::refused:
+        this->setErrorString(tr("Access Refused"));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+        return;
+    }
+}
+
+tcpSocket &tcpSocket::operator<<(const QString &msg){
+    if(this->state()!=QAbstractSocket::ConnectedState){
+        this->setErrorString(tr("Haven't been connecting yet."));
+        emit this->error(QAbstractSocket::NetworkError);
+        return (*this);
+    }
+    this->msg=msg.toUtf8();
+    this->event=tcpSocket::Size;
+    this->client_process_event();
+    return (*this);
+}
+
+tcpSocket &tcpSocket::operator<<(const QFileInfo &src_file){
+    this->src_file=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;
+    QDataStream datastream(tmp_buffer);
+    quint16 size=(quint16)tmp_buffer.size();
+    datastream<<this->head_data;
+    this->write((char*)&size,sizeof(size)/sizeof(char));
+    if(!this->flush())return (*this);
+    this->write(tmp_buffer);
+    if(!this->flush())return (*this);
+    tmp_buffer.clear();
+    emit this->file_header_sent();
+    if(!file.open(QIODevice::ReadOnly)){
+        this->setErrorString(tr("The file stream couldn't open."));
+        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);
+}
+
+//Threaded TCP socket (for client) implementation
+threadedTcpSocket::threadedTcpSocket(const AddressAndPort &to,const QString &senderName, const quint64 buffersize, QObject *parent):QThread(parent){
+    connect(this,SIGNAL(finished()),SLOT(deleteLater()));
+    connect(this,SIGNAL(terminated()),SLOT(deleteLater()));
+    this->locks[threadedTcpSocket::Mode].lockForWrite();
+    this->locks[threadedTcpSocket::SenderName].lockForWrite();
+    this->locks[threadedTcpSocket::BufferSize].lockForWrite();
+    this->locks[threadedTcpSocket::RWMode].lockForWrite();
+    this->locks[threadedTcpSocket::AddrAndPort].lockForWrite();
+        this->_addrPort=to;
+        this->mode=threadedTcpSocket::Client;
+        this->_senderName=senderName;
+        this->_buffersize=buffersize;
+        this->open_mode=QAbstractSocket::ReadWrite;
+    this->locks[threadedTcpSocket::Mode].unlock();
+    this->locks[threadedTcpSocket::SenderName].unlock();
+    this->locks[threadedTcpSocket::BufferSize].unlock();
+    this->locks[threadedTcpSocket::RWMode].unlock();
+    this->locks[threadedTcpSocket::AddrAndPort].unlock();
+}
+//Implementation of threadedTcpSocket
+threadedTcpSocket &threadedTcpSocket::operator<<(const QString &msg){
+    this->locks[threadedTcpSocket::Msg].lockForWrite();
+        this->_msg=msg;
+    this->locks[threadedTcpSocket::Msg].unlock();
+    this->start();
+    return (*this);
+}
+threadedTcpSocket &threadedTcpSocket::operator<<(const QFileInfo &file){
+    this->locks[threadedTcpSocket::File].lockForWrite();
+        this->_file=file;
+    this->locks[threadedTcpSocket::File].unlock();
+    this->start();
+    return (*this);
+}
diff --git a/network/server.cxx b/network/server.cxx
new file mode 100644 (file)
index 0000000..e790ed8
--- /dev/null
@@ -0,0 +1,201 @@
+#include "tcpnetwork.h"
+#include <cstring>
+#include "../structures/header.h"
+
+using namespace network;
+using namespace enc_hash;
+using namespace structures;
+using namespace std;
+
+//Tcp server implementation
+tcpServer::tcpServer(quint64 buffersize, QObject *parent):QTcpServer(parent){this->buffersize=buffersize;}
+
+void tcpServer::incomingConnection(int handle){
+    threadedTcpSocket *socket=new threadedTcpSocket(this->buffersize,this);
+    socket->socketDescriptor(handle);
+    if(! emit this->pending(*socket)){
+        socket->exit(1);
+        return;
+    }
+    socket->start();
+    emit this->newConnection();
+}
+
+//Tcp socket implementation
+tcpSocket::tcpSocket(const quint64 buffersize, QObject *parent):QTcpSocket(parent){
+    this->buffer_size=buffersize;
+    this->canceled=false;
+    this->event=tcpSocket::Size;
+    connect(this,SIGNAL(readyRead()),SLOT(read_data()));
+    connect(this,SIGNAL(bytesWritten(qint64)),SLOT(move_next_section(const qint64)));
+#ifdef DEBUG
+    qDebug()<<"Server:tcpSocket is constructed.";
+    qDebug()<<"Server:blocked:"<<this->signalsBlocked();
+#endif
+}
+void tcpSocket::read_data(){
+    /*TODO: remove this loop*/
+        while(this->bytesAvailable()>=0){
+#ifdef DEBUG
+          qDebug()<<"Server:server Event Mode:"<<this->event;
+          qDebug()<<"Server:server Available bytes:"<<this->bytesAvailable();
+#endif
+            switch(this->event){
+            case tcpSocket::Size:            this->size_event();               break;
+            case tcpSocket::Header:          this->header_event();             break;
+            case tcpSocket::Msg:             this->msg_event();         break;
+            case tcpSocket::File:            this->file_event();        break;
+            default: this->disconnectFromHost(); return;
+            }
+        }
+}
+void tcpSocket::move_next_section(const qint64 size){
+    Q_UNUSED(size);
+    switch(this->event){
+    case tcpSocket::Size: this->event=tcpSocket::Header; break;
+    case tcpSocket::Header:
+        this->event=(this->head_data.fileName().isEmpty()?tcpSocket::Msg:tcpSocket::File);
+        break;
+    default:
+        this->event=tcpSocket::End;
+        break;
+    }
+}
+void tcpSocket::send_flag(const Flag flag){
+    QByteArray send_data;
+    send_data.append((int)flag);
+    this->write(send_data);
+    if(!this->flush()){
+        this->setErrorString(tr("Accept signal couldn't be sent."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+        return;
+    }
+#ifdef DEBUG
+    qDebug()<<"Server:the flag:"<<flag<<" has been sent.";
+#endif
+}
+
+void tcpSocket::size_event(){
+    if(this->bytesAvailable()<2) return;
+    char size_buf[2];
+    this->read(size_buf,sizeof(size_buf));
+    memcpy(&this->header_size,size_buf,
+           (sizeof(quint16)>sizeof(size_buf))?sizeof(quint16):sizeof(size_buf)
+           );
+    //this->send_flag(tcpSocket::accepted);
+    this->move_next_section(0);
+}
+void tcpSocket::header_event(){
+    if(this->bytesAvailable()<this->header_size) return;
+    else{
+        QByteArray data=this->read(this->header_size);
+        QDataStream datastream(data);
+        datastream>>this->head_data;
+        if(this->head_data==structures::header()){
+            this->setErrorString(tr("The header is empty."));
+            emit this->error(QAbstractSocket::UnknownSocketError);
+            this->disconnectFromHost();
+            return;
+        }
+        if(!this->head_data.fileName().isEmpty()){
+            this->where_to_save=(emit this->file_pending());
+            if(this->where_to_save.isEmpty()){
+                this->write(QByteArray(1,0x00));
+
+                this->setErrorString(tr("The filename is empty."));
+                emit this->error(QAbstractSocket::UnknownSocketError);
+
+                this->disconnectFromHost();
+                return;
+            }
+        }
+        emit this->header_received();
+    }
+    //this->send_flag(tcpSocket::accepted);
+    this->move_next_section(0);
+}
+void tcpSocket::msg_event(){
+    if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
+    quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
+    read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
+    QByteArray msg;
+    for(quint64 count=0;count<read_count;count++){
+        if(this->check_canceled_then_abort())return;
+        msg+=this->read(this->buffer_size);
+    }
+    if(this->check_canceled_then_abort())return;
+    msg+=this->read(final_readsize);
+
+    rmd6 generator;
+    if(this->head_data.ripemd160()==generator.compute_hash(msg)){
+        emit this->msg_received(QString::fromUtf8(msg.data()));
+    }
+    else{
+#ifdef DEBUG
+        qDebug()<<"Hash digest error. the received message may be broken or modified.";
+        qDebug()<<"this->head_date.ripemd160():"<<this->head_data.ripemd160();
+        qDebug()<<"RIPEMD160-Hash"<<generator.compute_hash(msg);
+#endif
+        this->setErrorString(tr("The data has been broken."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+    }
+    //this->send_flag(tcpSocket::accepted);
+    this->move_next_section(0);
+}
+void tcpSocket::file_event(){
+    if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
+    quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
+    read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
+    streamopen:
+    if(this->where_to_save.isEmpty()){
+        this->setErrorString(tr("The filename is empty."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+        this->disconnectFromHost();
+        return;
+    }
+    QFile file(this->where_to_save,this);
+    if(!file.open(QIODevice::Truncate|QIODevice::WriteOnly)){
+        this->where_to_save=emit this->fileStream_openFailed(file.error(),file.errorString());
+        goto streamopen;
+    }
+    for(quint64 count=0;count<read_count&&!this->check_canceled_then_abort();count++){
+        if(this->check_canceled_then_abort())return;
+        file.write(this->read(this->buffer_size));
+        emit this->file_receive_progress(file.pos());
+    }
+    if(this->check_canceled_then_abort())return;
+    file.write(this->read(final_readsize));
+    emit this->file_receive_progress(file.pos());
+    file.close();
+
+    rmd6 generator;
+    if(this->head_data.ripemd160()==generator.compute_hash(file))
+        emit this->file_saved();
+    else{
+        this->setErrorString(tr("The file has been broken."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+    }
+    //this->send_flag(tcpSocket::accepted);
+    this->move_next_section(0);
+}
+void threadedTcpSocket::header_received(){
+    tcpSocket *socket=qobject_cast<tcpSocket *>(this->sender());
+    this->locks[threadedTcpSocket::HeaderData].lockForWrite();
+        this->_header=socket->header_data();
+    this->locks[threadedTcpSocket::HeaderData].unlock();
+}
+
+//Threaded TCP socket (for server) implemantation
+threadedTcpSocket::threadedTcpSocket(const quint64 buffersize, QObject *parent):QThread(parent){
+    connect(this,SIGNAL(finished()),SLOT(deleteLater()));
+    connect(this,SIGNAL(terminated()),SLOT(deleteLater()));
+    this->locks[threadedTcpSocket::Mode].lockForWrite();
+    this->locks[threadedTcpSocket::BufferSize].lockForWrite();
+    this->locks[threadedTcpSocket::RWMode].lockForWrite();
+        this->mode=threadedTcpSocket::Session;
+        this->_buffersize=buffersize;
+        this->open_mode=QAbstractSocket::ReadWrite;
+    this->locks[threadedTcpSocket::Mode].unlock();
+    this->locks[threadedTcpSocket::BufferSize].unlock();
+    this->locks[threadedTcpSocket::RWMode].unlock();;
+}
index 547e36a..c0df51c 100644 (file)
@@ -7,212 +7,197 @@ using namespace enc_hash;
 using namespace structures;
 using namespace std;
 
-//Tpc server implementation
-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);
-        return;
+void tcpSocket::disconnectFromHostImplementation(){
+    this->canceled=true;
+    QTcpSocket::disconnectFromHost();
+}
+bool tcpSocket::check_canceled_then_abort(){
+    if(this->canceled){
+        this->setErrorString(tr("The process has been canceled by user."));
+        emit this->error(QAbstractSocket::UnknownSocketError);
+        this->abort();
+        return true;
     }
-    if(emit this->pending(*socket)) this->newConnection();
-    else socket->abort();
+    return false;
 }
+void tcpSocket::cancel(){this->canceled=true;}
+QString tcpSocket::path_to_save() const{return this->where_to_save;}
+header tcpSocket::header_data() const{return this->head_data;}
 
-//Tcp socket implementation
-tcpSocket::tcpSocket(const quint64 buffersize, QObject *parent):QTcpSocket(parent){
-    this->buffer_size=buffersize;
-    this->canceled=false;
-    this->event=tcpSocket::headsize;
-    connect(this,SIGNAL(disconnected()),SLOT(deleteLater()));
-    connect(this,SIGNAL(readyRead()),SLOT(read_data()));
-#ifdef DEBUG
-    qDebug()<<"TcpSocket is constructed.";
-    qDebug()<<"Status:";
-    qDebug()<<"Blocked:"<<this->signalsBlocked();
-#endif
+/* Threaded TCP socket implementation. */
+QString threadedTcpSocket::senderName(){
+    QString senderName;
+    this->locks[threadedTcpSocket::SenderName].lockForRead();;
+        senderName=this->_senderName;
+    this->locks[threadedTcpSocket::SenderName].unlock();
+    return senderName;
 }
-tcpSocket::tcpSocket(const QString &senderName,const quint64 buffersize,QObject *parent):QTcpSocket(parent){
-    this->buffer_size=buffersize;
-    this->senderName=senderName;
+quint64 threadedTcpSocket::buffersize(){
+    quint64 size;
+    this->locks[threadedTcpSocket::BufferSize].lockForRead();
+        size=this->_buffersize;
+    this->locks[threadedTcpSocket::BufferSize].unlock();
+    return size;
+}
+AddressAndPort threadedTcpSocket::peerAddr(){
+    this->locks[threadedTcpSocket::AddrAndPort].lockForRead();
+    AddressAndPort r=this->_addrPort;
+    this->locks[threadedTcpSocket::AddrAndPort].unlock();
+    return r;
+}
+void threadedTcpSocket::to(const AddressAndPort &to){
+    this->locks[threadedTcpSocket::AddrAndPort].lockForWrite();
+        this->_addrPort=to;
+    this->locks[threadedTcpSocket::AddrAndPort].unlock();
+}
+
+int threadedTcpSocket::socketDescriptor(){
+    int desc;
+    this->locks[threadedTcpSocket::Descriptor].lockForRead();
+        desc=this->_descriptor;
+    this->locks[threadedTcpSocket::Descriptor].unlock();
+    return desc;
+}
+
+void threadedTcpSocket::senderName(const QString &name){
+    this->locks[threadedTcpSocket::SenderName].lockForWrite();
+        this->_senderName=name;
+    this->locks[threadedTcpSocket::SenderName].unlock();
+}
+void threadedTcpSocket::buffersize(const quint64 size){
+    this->locks[threadedTcpSocket::BufferSize].lockForWrite();;
+        this->_buffersize=size;
+    this->locks[threadedTcpSocket::BufferSize].unlock();
+}
+void threadedTcpSocket::socketDescriptor(const int descriptor){
+    this->locks[threadedTcpSocket::Descriptor].lockForWrite();
+        this->_descriptor=descriptor;
+    this->locks[threadedTcpSocket::Descriptor].unlock();
+}
+QIODevice::OpenMode threadedTcpSocket::readWriteMode(){
+    QIODevice::OpenMode mode;
+    this->locks[threadedTcpSocket::RWMode].lockForRead();
+        mode=this->open_mode;
+    this->locks[threadedTcpSocket::RWMode].unlock();
+    return mode;
+}
+void threadedTcpSocket::readWriteMode(const QIODevice::OpenMode openMode){
+    this->locks[threadedTcpSocket::RWMode].lockForWrite();
+        this->open_mode=openMode;
+    this->locks[threadedTcpSocket::RWMode].unlock();
+}
+header threadedTcpSocket::head_data(){
+    this->locks[threadedTcpSocket::HeaderData].lockForRead();
+        header head=this->_header;
+    this->locks[threadedTcpSocket::HeaderData].unlock();
+    return head;
 }
 
-void tcpSocket::read_data(){
-    while(this->bytesAvailable()>0){
+void threadedTcpSocket::run(){
 #ifdef DEBUG
-        qDebug()<<"Server Event Mode:"<<this->event<<"Server Available bytes:"<<this->bytesAvailable();
+    qDebug()<<"threadedTcpSocket has been created and running.";
 #endif
-        switch(this->event){
-        case tcpSocket::headsize:               this->size_event();            break;
-        case tcpSocket::header_receive:  this->header_event();         break;
-        case tcpSocket::msg:             this->msg_event();         break;
-        case tcpSocket::file:            this->file_event();        break;
-        }
-    }
-}
-void tcpSocket::size_event(){
-    if(this->bytesAvailable()<2) return;
-    char size_buf[2];
-    this->read(size_buf,sizeof(size_buf));
-    memcpy(&this->header_size,size_buf,
-           (sizeof(quint16)>sizeof(size_buf))?sizeof(quint16):sizeof(size_buf)
-           );
-    this->event=tcpSocket::header_receive;
-}
-void tcpSocket::header_event(){
-    if(this->bytesAvailable()<this->header_size) return;
-    else{
-        QByteArray data=this->read(this->header_size);
-        QDataStream datastream(data);
-        datastream>>this->head_data;
-        if(this->head_data==structures::header()){
-            this->setErrorString(tr("The header is empty."));
-            emit this->error(QAbstractSocket::UnknownSocketError);
-            this->disconnectFromHost();
-            return;
-        }
-        if(!this->head_data.fileName().isEmpty()){
-            this->where_to_save=(emit this->file_pending());
-            if(this->where_to_save.isEmpty()){
-                this->write(QByteArray(1,0x00));
+    this->locks[threadedTcpSocket::BufferSize].lockForRead();
+    this->locks[threadedTcpSocket::SenderName].lockForRead();
+    tcpSocket *socket=
+            (this->mode==threadedTcpSocket::Client)?
+            new tcpSocket(this->_senderName,this->_buffersize):
+            new tcpSocket(this->_buffersize);
+    this->locks[threadedTcpSocket::BufferSize].unlock();
+    this->locks[threadedTcpSocket::SenderName].unlock();
+    /*Common signals*/
+    connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),
+            SLOT(error_occured(QAbstractSocket::SocketError)),
+            Qt::BlockingQueuedConnection);
+    connect(socket,SIGNAL(connected()),SLOT(host_connected()),Qt::BlockingQueuedConnection);
+    connect(socket,SIGNAL(connected()),SIGNAL(connected()));
+    connect(socket,SIGNAL(disconnected()),SIGNAL(disconnected()));
+    connect(socket,SIGNAL(disconnected()),SLOT(host_disconnected()),
+            Qt::BlockingQueuedConnection);
+    connect(socket,SIGNAL(hostFound()),SIGNAL(hostFound()));
+    connect(socket,SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*)),
+            SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*)));
+    connect(socket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+            SIGNAL(stateChanged(QAbstractSocket::SocketState)));
 
-                this->setErrorString(tr("The filename is empty."));
-                emit this->error(QAbstractSocket::UnknownSocketError);
+    int descriptor;
+    this->locks[threadedTcpSocket::Mode].lockForRead();
+    switch(this->mode){
+    case threadedTcpSocket::Client:
+        connect(socket,SIGNAL(sentData()),SIGNAL(sentData()));
+        connect(socket,SIGNAL(sentData()),SLOT(quit()));
+        connect(socket,SIGNAL(file_header_sent()),SIGNAL(file_header_sent()));
+        connect(socket,SIGNAL(sending_file_progress(quint64)),SIGNAL(sending_file_progress(quint64)));
+        this->locks[threadedTcpSocket::AddrAndPort].lockForRead();
+            socket->connectToHost(this->_addrPort.first,this->_addrPort.second);
+        this->locks[threadedTcpSocket::AddrAndPort].unlock();
+        break;
+    case threadedTcpSocket::Session:
+        this->locks[threadedTcpSocket::Descriptor].lockForRead();
+            descriptor=this->_descriptor;
+        this->locks[threadedTcpSocket::Descriptor].unlock();
+        connect(socket,SIGNAL(msg_received(const QString &)),SIGNAL(msg_received(const QString &)));
+        connect(socket,SIGNAL(msg_received(const QString &)),SLOT(quit()));
 
-                this->disconnectFromHost();
-                return;
-            }
+        connect(socket,SIGNAL(file_receive_progress(const quint64)),SIGNAL(file_receive_progress(const quint64)));
+        connect(socket,SIGNAL(file_saved()),SIGNAL(file_saved()));
+        connect(socket,SIGNAL(file_saved()),SLOT(quit()));
+        connect(socket,SIGNAL(header_received()),SLOT(header_received()));
+        if(!socket->setSocketDescriptor(descriptor)){
+            this->_error=socket->errorString();
+            emit this->error(socket->error());
         }
+        this->_addrPort.first=socket->peerAddress();
+        this->_addrPort.second=socket->peerPort();
+        break;
     }
-    if(this->head_data.fileName().isEmpty()) this->event=tcpSocket::msg;
-    else this->event=tcpSocket::file;
-}
-void tcpSocket::msg_event(){
-    if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
-    quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
-    read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
-    QByteArray msg;
-    for(quint64 count=0;count<read_count;count++){
-        if(this->check_canceled_then_abort())return;
-        msg+=this->read(this->buffer_size);
-    }
-    if(this->check_canceled_then_abort())return;
-    msg+=this->read(final_readsize);
-
-    rmd6 generator;
-    if(this->head_data.ripemd160()==generator.compute_hash(msg))
-        emit this->msg_received(QString::fromUtf8(msg.data()));
-    else{
-        this->setErrorString(tr("The data has been broken."));
-        emit this->error(QAbstractSocket::UnknownSocketError);
-    }
-    this->disconnectFromHost();
-}
-void tcpSocket::file_event(){
-    if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
-    quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
-    read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
-    streamopen:
-    if(this->where_to_save.isEmpty()){
-        this->setErrorString(tr("The filename is empty."));
-        emit this->error(QAbstractSocket::UnknownSocketError);
-        this->disconnectFromHost();
+    this->locks[threadedTcpSocket::Mode].unlock();
+    if(this->exec()==0){
+        socket->disconnectFromHost();
         return;
     }
-    QFile file(this->where_to_save,this);
-    if(!file.open(QIODevice::Truncate|QIODevice::WriteOnly)){
-        this->where_to_save=emit this->fileStream_openFailed(file.error(),file.errorString());
-        goto streamopen;
-    }
-    for(quint64 count=0;count<read_count&&!this->check_canceled_then_abort();count++){
-        if(this->check_canceled_then_abort())return;
-        file.write(this->read(this->buffer_size));
-        emit this->file_receive_progress(file.pos());
-    }
-    if(this->check_canceled_then_abort())return;
-    file.write(this->read(final_readsize));
-    emit this->file_receive_progress(file.pos());
-    file.close();
-
-    rmd6 generator;
-    if(this->head_data.ripemd160()==generator.compute_hash(file))
-        emit this->file_saved();
-    else{
-        this->setErrorString(tr("The file has been broken."));
-        emit this->error(QAbstractSocket::UnknownSocketError);
-    }
-    this->disconnectFromHost();
+    //Cleanup
+    socket->abort();
 }
-
-bool tcpSocket::check_canceled_then_abort(){
-    if(this->canceled){
-        this->setErrorString(tr("The process has been canceled by user."));
-        emit this->error(QAbstractSocket::UnknownSocketError);
-        this->abort();
-        return true;
+void threadedTcpSocket::host_connected(){
+    tcpSocket *socket=qobject_cast<tcpSocket *>(this->sender());
+#ifdef DEBUG
+    qDebug()<<"Client:"<<socket->peerAddress().toString()<<"has been connected properly.";
+#endif
+    this->locks[threadedTcpSocket::Msg].lockForRead();
+        bool r=this->_msg.isNull();
+    this->locks[threadedTcpSocket::Msg].unlock();
+    if(r){
+        this->locks[threadedTcpSocket::File].lockForRead();
+        (*socket)<<this->_file;
+        this->locks[threadedTcpSocket::File].unlock();
+    }else{
+        this->locks[threadedTcpSocket::Msg].lockForRead();
+        (*socket)<<this->_msg;
+        this->locks[threadedTcpSocket::Msg].unlock();
     }
-    return false;
 }
-void tcpSocket::disconnectFromHostImplementation(){
-    this->canceled=true;
-    QTcpSocket::disconnectFromHost();
+void threadedTcpSocket::host_disconnected(){
+    tcpSocket *socket=qobject_cast<tcpSocket *>(this->sender());
+    socket->close();
+#ifdef DEBUG
+    qDebug()<<"Socket("<<((this->mode==threadedTcpSocket::Session)?"Session":"Client")<<"):Connection closed successful.";
+#endif
+    socket->deleteLater();
 }
-tcpSocket &tcpSocket::operator<<(const QString &msg){
-    if(this->state()!=QAbstractSocket::ConnectedState) return (*this);
-    this->head_data=header(this->senderName,msg);
-    QByteArray tmp_buffer;
-    QDataStream datastream(&tmp_buffer,QIODevice::WriteOnly);
-    datastream<<this->head_data;
-    quint16 size=(quint16)tmp_buffer.size();
-    this->write((char*)&size,sizeof(size)/sizeof(char));
-    if(!this->flush())return (*this);
-    this->write(tmp_buffer);
-    if(!this->flush())return (*this);
-    tmp_buffer.clear();
-    tmp_buffer=msg.toUtf8();
-    QBuffer memoryStream(&tmp_buffer,this);
-    if(!memoryStream.open(QIODevice::ReadOnly)){
-        this->setErrorString(tr("Memory Stream couldn't open."));
-        emit this->error(QAbstractSocket::UnknownSocketError);
-        return (*this);
-    }
-    while(this->write(memoryStream.read(this->buffer_size))>0)
-        if(!this->flush())return (*this);
-    memoryStream.close();
 
-    emit this->sentData();
-    return (*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;
-    QDataStream datastream(tmp_buffer);
-    quint16 size=(quint16)tmp_buffer.size();
-    datastream<<this->head_data;
-    this->write((char*)&size,sizeof(size)/sizeof(char));
-    if(!this->flush())return (*this);
-    this->write(tmp_buffer);
-    if(!this->flush())return (*this);
-    tmp_buffer.clear();
-    emit this->file_header_sent();
-    if(!file.open(QIODevice::ReadOnly)){
-        this->setErrorString(tr("The file stream couldn't open."));
-        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);
+void threadedTcpSocket::error_occured(const QAbstractSocket::SocketError error){
+    tcpSocket *socket=(tcpSocket*)this->sender();
+    this->locks[threadedTcpSocket::Error].lockForWrite();
+        this->_error=socket->errorString();
+    this->locks[threadedTcpSocket::Error].unlock();
+    this->exit(1);
+    emit this->error(error);
+}
+QString threadedTcpSocket::errorString(){
+    this->locks[threadedTcpSocket::Error].lockForRead();
+        QString str=this->_error;
+    this->locks[threadedTcpSocket::Error].unlock();
+    return str;
 }
-void tcpSocket::cancel(){this->canceled=true;}
-QString tcpSocket::path_to_save() const{return this->where_to_save;}
-header tcpSocket::header_data() const{return this->head_data;}
index 986caa7..0cedf03 100644 (file)
@@ -6,7 +6,8 @@
 #include "../definition.h"
 #include "../ported_rmd6/rmd6.h"
 
-#define default_bandwidth 0x400
+const quint64 default_bandwidth = 0x400;
+using namespace structures;
 namespace network{
     class tcpSocket;
     class threadedTcpSocket;
@@ -16,14 +17,88 @@ namespace network{
     public:
         tcpServer(quint64 buffersize=default_bandwidth,QObject *parent=NULL);
     signals:
-        bool pending(const tcpSocket &) const;
-        bool pending(const threadedTcpSocket &) const;
-        void socket_error(const tcpSocket &) const;
+        bool pending(threadedTcpSocket &) const;
+        void socket_error(const threadedTcpSocket &) const;
     protected:
         void incomingConnection(int handle);
     private:
         quint64 buffersize;
     };
+
+    class threadedTcpSocket:public QThread{
+        Q_OBJECT
+    public:
+        //This constructor is for server. it works as a session.
+        threadedTcpSocket(const quint64 buffersize=default_bandwidth,QObject *parent=NULL);
+        //This constructor is for client. it works as a client.
+        threadedTcpSocket(const AddressAndPort &,const QString &senderName,const quint64 buffersize=default_buffer_size,QObject *parent=NULL);
+        /*
+            To access these member, accessing critical sections must be needed.
+            Hence, these member uses QReadWriteLock to lock them; Making constant functions is not possible.
+         */
+        quint64 buffersize();
+        QString senderName();
+        AddressAndPort peerAddr();
+        header head_data();
+        int socketDescriptor();
+        void socketDescriptor(const int);
+        void buffersize(const quint64);
+        void senderName(const QString &);
+        void readWriteMode(const QIODevice::OpenMode);
+        void to(const AddressAndPort &);
+        QIODevice::OpenMode readWriteMode();
+        QString errorString();
+        threadedTcpSocket &operator<<(const QString &);
+        threadedTcpSocket &operator<<(const QFileInfo &);
+    private:
+        enum Mode{Session,Client} mode;
+        enum lockID{
+            Mode        =0,
+            BufferSize  =1,
+            SenderName  =2,
+            Msg         =3,
+            File        =4,
+            Descriptor  =5,
+            RWMode      =6,
+            Error       =7,
+            AddrAndPort =8,
+            HeaderData  =9
+        };
+        void run();
+        QIODevice::OpenMode open_mode;
+        QReadWriteLock locks[10];
+        int _descriptor;
+        quint64 _buffersize;
+        QString _senderName,_msg,_error;
+        QFileInfo _file;
+        AddressAndPort _addrPort;
+        header _header;
+    private slots:
+        void header_received();
+        void error_occured(const QAbstractSocket::SocketError);
+        void host_connected();
+        void host_disconnected();
+    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 connected();
+        void disconnected();
+        void error(const QAbstractSocket::SocketError);
+        void hostFound();
+        void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator *);
+        void stateChanged(QAbstractSocket::SocketState);
+    };
+
     class tcpSocket:public QTcpSocket{
         Q_OBJECT
     public:
@@ -33,37 +108,62 @@ namespace network{
         tcpSocket(const QString &senderName,const quint64 buffersize=default_buffer_size,QObject *parent=NULL);
         QString path_to_save() const;
         structures::header header_data() const;
-        //Calling operator<<(QFile), the specified file stream will be copied.
+
         tcpSocket &operator<<(const QString &),
                   &operator<<(const QFileInfo &);
     signals:
         QString file_pending() const;
         QString fileStream_openFailed(const QFile::FileError &,const QString &) const;
 
+        void header_received() 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);
-    private slots:
-        void read_data();
-        void cancel();
+        void sentData() const;
+        void file_header_sent() const;
+        void sending_file_progress(const quint64 pos) const;
     protected:
         void disconnectFromHostImplementation();
     private:
-        enum mode{headsize,header_receive,msg,file} event;
+        enum section {
+            Size,
+            Header,
+            Msg,
+            File,
+            End
+        } event;
+
+        enum Flag {accepted=0,refused=1};
         void size_event();
         void header_event();
         void msg_event();
         void file_event();
         bool check_canceled_then_abort();
+
+        void client_move_section();
+        bool client_process_event();
+        bool client_flush();
+        bool client_send_size();
+        bool client_send_header();
+        bool client_send_msg();
+        bool client_send_file();
+
         //The size of header needs to be larger than 0, and smaller than or equal to 0xFFFF.
         quint16 header_size,buffer_size,timeout_time;
         structures::header head_data;
         bool canceled;
         QString where_to_save, senderName;
+        //These classes are only used for client to store serialized header data.
+        QByteArray tmp_buffer,msg;
+        QFileInfo src_file;
+    private slots:
+        void read_data();
+        void move_next_section(const qint64);
+        void send_flag(const Flag flag);
+        void cancel();
+
+        void client_receive_flag();
     };
 }
index 5e23b35..e00b8c0 100644 (file)
@@ -3,10 +3,10 @@ Readme
 This document is written about what this software is, the warnings, and how to build.
 
 What this software?
-This software will provide simple P2P(like bittorrent) messenger.
+This software will provide very very simple P2P messenger.
 
 Warnings:
-Please don't build and/or use this version unless you have knowledge about computer; It could do unsafe behavior because it is under development.
+Please don't build and/or use this version unless you have knowledge about computer; It could do unsafe behavior because it is still under development.
 
 How to build:
 Before building, please read warnings section million times.
index 4a55f72..e7ea2d6 100644 (file)
@@ -3,9 +3,9 @@
 using namespace structures;
 using namespace enc_hash;
 header::header():rmd6_hash(5){}
-header::header(const QString &senderName,const QString &msg): sendername(senderName),data_size(msg.size()){
+header::header(const QString &senderName,const QByteArray &msg): sendername(senderName),data_size(msg.size()){
     rmd6 gen;
-    this->rmd6_hash=gen.compute_hash(msg.toUtf8());
+    this->rmd6_hash=gen.compute_hash(msg);
 }
 header::header(const QString &senderName,const QFileInfo &fileinfo):
         filename(fileinfo.completeBaseName()),sendername(senderName),
@@ -24,6 +24,12 @@ QVector<quint32> header::ripemd160()const {return this->rmd6_hash;}
 void header::senderName(const QString &sendername){this->sendername=sendername;}
 void header::fileName(const QString &filename){this->filename=filename;}
 void header::datasize(const quint64 size){this->data_size=size;}
+void header::operator=(const header &other){
+    this->senderName(other.senderName());
+    this->fileName(other.fileName());
+    this->datasize(other.datasize());
+    this->rmd6_hash=other.ripemd160();
+}
 bool header::operator==(const header &head) const{
     return (this->sendername==head.senderName()&&
             this->filename==head.fileName()&&
index c84e7a1..2e145ba 100644 (file)
@@ -5,13 +5,14 @@ namespace structures{
     public:
         header();
         header(const QString &senderName,const QFileInfo &fileinfo);
-        header(const QString &senderName,const QString &msg);
+        header(const QString &senderName,const QByteArray &msg);
         QString fileName()const,
         senderName()const;
         quint64 datasize()const;
         QVector<quint32> ripemd160() const;
         bool operator==(const header &) const;
         bool operator!=(const header &) const;
+        void operator=(const header &);
         friend QDataStream &operator<<(QDataStream &out,const header &value){
             out<<value.data_size<<value.rmd6_hash<<value.sendername<<value.filename;
             return out;
index 5296e89..4f39955 100644 (file)
@@ -53,7 +53,8 @@ mainWindow::mainWindow(){
     connect(this->sendTextEditor,SIGNAL(invalidLink(const QString &)),SLOT(invalidLink(const QString &)));
     connect(this->sendTextEditor,SIGNAL(sendTriggered()),this->sendButton,SLOT(click()));
 
-    connect(this->mainServer,SIGNAL(pending(const tcpSocket &)),SLOT(tcpserver_pending(const tcpSocket &)));
+    connect(this->mainServer,SIGNAL(pending(threadedTcpSocket &)),
+            SLOT(tcpserver_pending(threadedTcpSocket &)));
 }
 mainWindow::~mainWindow(){}
 void mainWindow::closeEvent(QCloseEvent *event){
@@ -63,7 +64,7 @@ void mainWindow::closeEvent(QCloseEvent *event){
 }
 void mainWindow::showEvent(QShowEvent *event){
     if(rev==0)
-        this->status->showMessage("<font color=\"#ff0000\">Don't forget almost all features are not implemented!</font>",default_status_interval);
+        this->status->showMessage("Don't forget almost all features are not implemented!",default_status_interval);
     event->accept();
 }
 
@@ -74,27 +75,20 @@ void mainWindow::on_sendButton_clicked(){
 #pragma omp parallel for
 #endif
     for(int index=0;index<addressList.size();index++){
-        tcpSocket *client=new tcpSocket(this->setting.name(),default_buffer_size,this);
-        connect(client,SIGNAL(connected()),SLOT(tcpclient_connected()));
+        threadedTcpSocket *client=new threadedTcpSocket(
+                addressList[index],this->setting.name(),default_buffer_size,this);
         connect(client,SIGNAL(error(const QAbstractSocket::SocketError &)),SLOT(tcpclient_error(const QAbstractSocket::SocketError &)));
         connect(client,SIGNAL(sentData()),SLOT(sentData()));
-        client->connectToHost(addressList[index].first,addressList[index].second);
+        (*client)<<this->sendTextEditor->html();
     }
 }
 void mainWindow::tcpclient_error(const QAbstractSocket::SocketError &error){
     Q_UNUSED(error);
-    tcpSocket *client=qobject_cast<tcpSocket *>(this->sender());
+    threadedTcpSocket *client=qobject_cast<threadedTcpSocket *>(this->sender());
 #ifdef DEBUG
     qDebug()<<"Error:"<<client->errorString();
 #endif
-    client->close();
-}
-
-void mainWindow::tcpclient_connected(){
-    tcpSocket *client=qobject_cast<tcpSocket *>(this->sender());
-    (*client)<<this->sendTextEditor->html();
-    client->disconnectFromHost();
-    client->close();
+    client->exit(1);
 }
 
 void mainWindow::on_sendFileAction_triggered(){
@@ -260,7 +254,7 @@ void mainWindow::openConfig(const QString &file){
 void mainWindow::openMember(const QString &file){
      /*
       Does QFileDialog have a bug??
-      If you select file by double clicking, fileSelected signal will be emitted twice.
+      Selecting file by double clicking, fileSelected signal will be emitted twice.
       */
     if(this->sender()!=NULL&&this->sender()==this->beforesender) return;
     this->beforesender=this->sender();
@@ -292,12 +286,12 @@ void mainWindow::selectedLink(const QUrl &link){
 }
 settings mainWindow::app_setting() const{return this->setting;}
 
-//Implementations for main server.
-bool mainWindow::tcpserver_pending(const tcpSocket &socket){
+//Main server
+bool mainWindow::tcpserver_pending(threadedTcpSocket &socket){
 #ifdef DEBUG
-    qDebug()<<"Pending:"<<socket.peerAddress().toString()<<" Port:"<<socket.peerPort();
+    qDebug()<<"Pending:"<<socket.peerAddr().first.toString()<<" Port:"<<socket.peerAddr().second;
 #endif
-    if(this->memberList->isInMember(AddressAndPort(socket.peerAddress(),0),true)<0) return false;
+    if(this->memberList->isInMember(socket.peerAddr(),true)<0) return false;
     connect(&socket,
             SIGNAL(msg_received(const QString &)),
             SLOT(tcpserver_msg_received(const QString &)));
@@ -307,16 +301,18 @@ bool mainWindow::tcpserver_pending(const tcpSocket &socket){
 }
 void mainWindow::tcpserver_error(const QAbstractSocket::SocketError &error){
     Q_UNUSED(error);
-    tcpSocket *sender=qobject_cast<tcpSocket *>(this->sender());
+    threadedTcpSocket *sender=qobject_cast<threadedTcpSocket *>(this->sender());
 #ifdef DEBUG
     qDebug()<<"Receive aborted:"<<sender->errorString();
 #endif
-    sender->close();
+    sender->exit(1);
 }
 
 void mainWindow::tcpserver_msg_received(const QString &msg){
-    tcpSocket *sender=qobject_cast<tcpSocket *>(this->sender());
-    this->receiveText->append(sender->header_data().senderName()+"("+this->memberList->name(AddressAndPort(sender->peerAddress(),0),true)+", "+sender->peerAddress().toString()+")"+tr(" says:"));
+    threadedTcpSocket *sender=qobject_cast<threadedTcpSocket *>(this->sender());
+    this->receiveText->append(sender->head_data().senderName()+
+                              "("+this->memberList->name(AddressAndPort(sender->peerAddr().first,0),true)+", "+sender->peerAddr().first.toString()+")"+tr(" says:"));
     this->receiveText->append(msg);
     this->receiveText->append("<br />");
+    sender->quit();
 }
index 7b71e04..e774f86 100644 (file)
@@ -45,11 +45,10 @@ private slots:
     void invalidLink(const QString &);
     void selectedLink(const QUrl &);
     //These functions are for tcpclient.
-    void tcpclient_connected();
     void tcpclient_error(const QAbstractSocket::SocketError &error);
     void sentData();
     //These functions are for tcpserver.
-    bool tcpserver_pending(const tcpSocket &);
+    bool tcpserver_pending(threadedTcpSocket &);
     void tcpserver_msg_received(const QString &);
     void tcpserver_error(const QAbstractSocket::SocketError &);
 public slots: