OSDN Git Service

Please ignore this commit.
[greensite/jasmine.git] / network / server.cxx
1 #include "tcpnetwork.h"
2 #include <cstring>
3 #include "../structures/header.h"
4
5 using namespace network;
6 using namespace enc_hash;
7 using namespace structures;
8 using namespace std;
9
10 //Tcp server implementation
11 tcpServer::tcpServer(quint64 buffersize, QObject *parent):QTcpServer(parent){this->buffersize=buffersize;}
12
13 void tcpServer::incomingConnection(int handle){
14     threadedTcpSocket *socket=new threadedTcpSocket(this->buffersize,this);
15     connect(socket,SIGNAL(pending()),SLOT(socket_pending()));
16     socket->socketDescriptor(handle);
17     socket->start();
18     emit this->newConnection();
19 }
20 bool tcpServer::socket_pending(){
21 #ifdef DEBUG
22     server_msg<<"CALL:socket_pending";
23 #endif
24     threadedTcpSocket *socket=qobject_cast<threadedTcpSocket *>(this->sender());
25     if(!emit this->pending(AddressAndPort(socket->peerAddr().first,socket->peerAddr().second))){
26 #ifdef DEBUG
27         server_msg<<"A client accessed, but refused because user didn't accept.";
28 #endif
29         return false;
30     }
31     emit this->socket_accepted(*socket);
32     return true;
33 }
34
35 //Tcp socket implementation
36 tcpSocket::tcpSocket(const quint64 buffersize, QObject *parent):QTcpSocket(parent){
37     this->buffer_size=buffersize;
38     this->canceled=false;
39     this->event=tcpSocket::Size;
40     connect(this,SIGNAL(readyRead()),SLOT(read_data()));
41     connect(this,SIGNAL(bytesWritten(qint64)),SLOT(move_next_section(const qint64)));
42     connect(this,SIGNAL(disconnected()),SLOT(deleteLater()));
43     connect(this,SIGNAL(error(QAbstractSocket::SocketError)),SLOT(error_occured(QAbstractSocket::SocketError)));
44 #ifdef DEBUG
45     server_msg<<"tcpSocket is constructed.";
46     server_msg<<this;
47     server_msg<<"blocked:"<<this->signalsBlocked();
48 #endif
49 }
50 void tcpSocket::read_data(){
51     /*TODO: remove this loop*/
52         while(this->bytesAvailable()>=0){
53 #ifdef DEBUG
54           server_msg<<"server Event Mode:"<<this->event;
55           server_msg<<"server Available bytes:"<<this->bytesAvailable();
56 #endif
57             switch(this->event){
58             case tcpSocket::Size:            this->size_event();                break;
59             case tcpSocket::Header:          this->header_event();              break;
60             case tcpSocket::Msg:             this->msg_event();         break;
61             case tcpSocket::File:            this->file_event();        break;
62             default: this->disconnectFromHost(); return;
63             }
64         }
65 }
66 void tcpSocket::move_next_section(const qint64 size){
67     Q_UNUSED(size);
68     switch(this->event){
69     case tcpSocket::Size: this->event=tcpSocket::Header; break;
70     case tcpSocket::Header:
71         this->event=(this->head_data.fileName().isEmpty()?tcpSocket::Msg:tcpSocket::File);
72         break;
73     default:
74         this->event=tcpSocket::End;
75         break;
76     }
77 }
78 void tcpSocket::send_flag(const Flag flag){
79     QByteArray send_data;
80     send_data.append((int)flag);
81     this->write(send_data);
82     if(!this->flush()){
83         this->setErrorString(tr("Accept signal couldn't be sent."));
84         emit this->error(QAbstractSocket::UnknownSocketError);
85         return;
86     }
87 #ifdef DEBUG
88     server_msg<<"the flag:"<<flag<<" has been sent.";
89 #endif
90 }
91
92 void tcpSocket::size_event(){
93     if(this->bytesAvailable()<2) return;
94     char size_buf[2];
95     this->read(size_buf,sizeof(size_buf));
96     memcpy(&this->header_size,size_buf,
97            (sizeof(quint16)>sizeof(size_buf))?sizeof(quint16):sizeof(size_buf)
98            );
99     //this->send_flag(tcpSocket::accepted);
100     this->move_next_section(0);
101 }
102 void tcpSocket::header_event(){
103     if(this->bytesAvailable()<this->header_size) return;
104     else{
105         QByteArray data=this->read(this->header_size);
106         QDataStream datastream(data);
107         datastream>>this->head_data;
108         if(this->head_data==structures::header()){
109             this->setErrorString(tr("The header is empty."));
110             emit this->error(QAbstractSocket::UnknownSocketError);
111             this->disconnectFromHost();
112             return;
113         }
114         if(!this->head_data.fileName().isEmpty()){
115             this->where_to_save=(emit this->file_pending());
116             if(this->where_to_save.isEmpty()){
117                 this->write(QByteArray(1,0x00));
118
119                 this->setErrorString(tr("The filename is empty."));
120                 emit this->error(QAbstractSocket::UnknownSocketError);
121
122                 this->disconnectFromHost();
123                 return;
124             }
125         }
126         emit this->header_received();
127     }
128     //this->send_flag(tcpSocket::accepted);
129     this->move_next_section(0);
130 }
131 void tcpSocket::msg_event(){
132     if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
133     quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
134     read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
135     QByteArray msg;
136     for(quint64 count=0;count<read_count;count++){
137         if(this->check_canceled())return;
138         msg+=this->read(this->buffer_size);
139     }
140     if(this->check_canceled())return;
141     msg+=this->read(final_readsize);
142
143     rmd6 generator;
144     if(this->head_data.ripemd160()==generator.compute_hash(msg)){
145         emit this->msg_received(QString::fromUtf8(msg.data()));
146     }
147     else{
148 #ifdef DEBUG
149         qDebug()<<"Hash digest error. the received message may be broken or modified.";
150         qDebug()<<"this->head_date.ripemd160():"<<this->head_data.ripemd160();
151         qDebug()<<"RIPEMD160-Hash"<<generator.compute_hash(msg);
152 #endif
153         this->setErrorString(tr("The data has been broken."));
154         emit this->error(QAbstractSocket::UnknownSocketError);
155     }
156     //this->send_flag(tcpSocket::accepted);
157     this->move_next_section(0);
158 }
159 void tcpSocket::file_event(){
160     if((quint64)this->bytesAvailable()<this->header_data().datasize()) return;
161     quint64 final_readsize=this->head_data.datasize()%this->buffer_size,
162     read_count=(this->head_data.datasize()-final_readsize)/this->buffer_size;
163     streamopen:
164     if(this->where_to_save.isEmpty()){
165         this->setErrorString(tr("The filename is empty."));
166         emit this->error(QAbstractSocket::UnknownSocketError);
167         this->disconnectFromHost();
168         return;
169     }
170     QFile file(this->where_to_save,this);
171     if(!file.open(QIODevice::Truncate|QIODevice::WriteOnly)){
172         this->where_to_save=emit this->fileStream_openFailed(file.error(),file.errorString());
173         goto streamopen;
174     }
175     for(quint64 count=0;count<read_count&&!this->check_canceled();count++){
176         if(this->check_canceled())return;
177         file.write(this->read(this->buffer_size));
178         emit this->file_receive_progress(file.pos());
179     }
180     if(this->check_canceled())return;
181     file.write(this->read(final_readsize));
182     emit this->file_receive_progress(file.pos());
183     file.close();
184
185     rmd6 generator;
186     if(this->head_data.ripemd160()==generator.compute_hash(file))
187         emit this->file_saved();
188     else{
189         this->setErrorString(tr("The file has been broken."));
190         emit this->error(QAbstractSocket::UnknownSocketError);
191     }
192     //this->send_flag(tcpSocket::accepted);
193     this->move_next_section(0);
194 }
195 void threadedTcpSocket::header_received(){
196     tcpSocket *socket=qobject_cast<tcpSocket *>(this->sender());
197     this->locks[threadedTcpSocket::HeaderData].lockForWrite();
198         this->_header=socket->header_data();
199     this->locks[threadedTcpSocket::HeaderData].unlock();
200 }
201
202 //Threaded TCP socket (for server) implemantation
203 threadedTcpSocket::threadedTcpSocket(const quint64 buffersize, QObject *parent):QThread(parent){
204     connect(this,SIGNAL(finished()),SLOT(deleteLater()));
205     connect(this,SIGNAL(terminated()),SLOT(deleteLater()));
206     this->locks[threadedTcpSocket::Mode].lockForWrite();
207     this->locks[threadedTcpSocket::BufferSize].lockForWrite();
208     this->locks[threadedTcpSocket::RWMode].lockForWrite();
209         this->mode=threadedTcpSocket::Session;
210         this->_buffersize=buffersize;
211         this->open_mode=QAbstractSocket::ReadWrite;
212     this->locks[threadedTcpSocket::Mode].unlock();
213     this->locks[threadedTcpSocket::BufferSize].unlock();
214     this->locks[threadedTcpSocket::RWMode].unlock();;
215 }