/** \file ServerCatchcopy.cpp \brief Define the server of catchcopy \author alpha_one_x86*/ #include "ServerCatchcopy.h" #include "VariablesCatchcopy.h" #include "ExtraSocketCatchcopy.h" #include #include #include #include #include std::string stringimplode2(const std::vector& elems, const std::string &delim) { std::string newString; for (std::vector::const_iterator ii = elems.begin(); ii != elems.cend(); ++ii) { newString += (*ii); if ( ii + 1 != elems.end() ) { newString += delim; } } return newString; } ServerCatchcopy::ServerCatchcopy() { name="Default avanced copier"; idNextClient=0; error_string="Unknown error"; connect(&server, &QLocalServer::newConnection, this, &ServerCatchcopy::newConnection); } ServerCatchcopy::~ServerCatchcopy() { close(); } bool ServerCatchcopy::isListening() const { return server.isListening(); } void ServerCatchcopy::setName(const std::string & name) { this->name=name; } std::string ServerCatchcopy::getName() const { return name; } /// \brief to get a client list std::vector ServerCatchcopy::clientsList() const { std::vector clients; int index=0; int size=clientList.size(); while(indexdisconnectFromServer(); index++; } server.close(); if(!server.removeServer(QString::fromStdString(pathSocket))) { error_string="Unable to remove the old server"; emit error(error_string); } } } const std::string ServerCatchcopy::errorStringServer() const { return server.errorString().toStdString(); } const std::string ServerCatchcopy::errorString() const { return error_string; } /// \brief New connexion void ServerCatchcopy::newConnection() { while(server.hasPendingConnections()) { QLocalSocket *clientSocket = server.nextPendingConnection(); if(clientSocket!=NULL) { do { idNextClient++; if(idNextClient>2000000000) idNextClient=0; } while(clientIdFound(idNextClient)); Client newClient; newClient.id = idNextClient; newClient.socket = clientSocket; newClient.haveData = false; newClient.firstProtocolReplied = false; newClient.detectTimeOut = new QTimer(this); newClient.detectTimeOut->setSingleShot(true); newClient.detectTimeOut->setInterval(CATCHCOPY_COMMUNICATION_TIMEOUT); newClient.name="Unknown"; connect(newClient.socket, static_cast(&QLocalSocket::error), this, &ServerCatchcopy::connectionError,Qt::QueuedConnection); connect(newClient.socket, &QIODevice::readyRead, this, &ServerCatchcopy::readyRead,Qt::QueuedConnection); connect(newClient.socket, &QLocalSocket::disconnected, this, &ServerCatchcopy::disconnected,Qt::QueuedConnection); connect(newClient.detectTimeOut,&QTimer::timeout, this, &ServerCatchcopy::checkTimeOut,Qt::QueuedConnection); clientList << newClient; emit connectedClient(newClient.id); } } } bool ServerCatchcopy::clientIdFound(const uint32_t &id) const { int index=0; while(index(QObject::sender()); if(socket==NULL) { qWarning() << "Unlocated client socket!"; return; } int index=0; while(indexdisconnectFromServer(); } return; } index++; } } void ServerCatchcopy::disconnected() { QLocalSocket *socket=qobject_cast(QObject::sender()); if(socket==NULL) { qWarning() << "Unlocated client socket!"; return; } int index=0; while(indexdisconnectFromServer();//already disconnected delete clientList.at(index).detectTimeOut; clientList.at(index).socket->deleteLater(); clientList.removeAt(index); emit disconnectedClient(id); return; } index++; } qWarning() << "Unlocated client!"; } void ServerCatchcopy::disconnectClient(const uint32_t &id) { int index=0; while(indexdisconnectFromServer(); return; } index++; } qWarning() << "Unlocated client!"; } void ServerCatchcopy::readyRead() { QLocalSocket *socket=qobject_cast(QObject::sender()); if(socket==NULL) { qWarning() << "Unlocated client socket!"; return; } int index=0; while(indexbytesAvailable()>0) { if(!clientList.at(index).haveData) { if(socket->bytesAvailable()<(int)sizeof(int))//ignore because first int is cuted! { /*error_string="Bytes available is not sufficient to do a int"; emit error(error_string); disconnectClient(ClientList.at(index).id);*/ return; } QDataStream in(socket); in.setVersion(QDataStream::Qt_4_4); in >> clientList[index].dataSize; clientList[index].dataSize-=sizeof(int); if(clientList.at(index).dataSize>64*1024*1024) // 64MB { error_string="Reply size is >64MB, seam corrupted"; emit communicationError(error_string); disconnectClient(clientList.at(index).id); return; } if(clientList.at(index).dataSize<(int)(sizeof(int) //orderId + sizeof(uint32_t) //returnCode + sizeof(uint32_t) //string list size )) { error_string="Reply size is too small to have correct code"; emit communicationError(error_string); disconnectClient(clientList.at(index).id); return; } clientList[index].haveData=true; } if(clientList.at(index).dataSize<(clientList.at(index).data.size()+socket->bytesAvailable())) clientList[index].data.append(socket->read(clientList.at(index).dataSize-clientList.at(index).data.size())); else clientList[index].data.append(socket->readAll()); if(clientList.at(index).dataSize==(uint32_t)clientList.at(index).data.size()) { if(!checkDataIntegrity(clientList.at(index).data)) { emit communicationError("Data integrity wrong: "+QString(clientList.at(index).data.toHex()).toStdString()); clientList[index].data.clear(); clientList[index].haveData=false; qWarning() << "Data integrity wrong"; return; } std::vector returnList; QStringList returnListQt; uint32_t orderId; QDataStream in(clientList.at(index).data); in.setVersion(QDataStream::Qt_4_4); in >> orderId; in >> returnListQt; { int index=0; while(indexstart(); else clientList.at(index).detectTimeOut->stop(); return; } index++; } emit error("Unallocated client!"); qWarning() << "Unallocated client!"; } bool ServerCatchcopy::checkDataIntegrity(const QByteArray &data) { uint32_t orderId; qint32 listSize; QDataStream in(data); in.setVersion(QDataStream::Qt_4_4); in >> orderId; in >> listSize; if(listSize>65535) { emit error("List size is wrong"); qWarning() << "List size is wrong"; return false; } int index=0; while(index> stringSize; if(stringSize>65535) { emit error("String size is wrong"); return false; } if(stringSize>(in.device()->size()-in.device()->pos())) { emit error(QStringLiteral("String size is greater than the data: %1>(%2-%3)").arg(stringSize).arg(in.device()->size()).arg(in.device()->pos()).toStdString()); return false; } in.device()->seek(in.device()->pos()+stringSize); index++; } if(in.device()->size()!=in.device()->pos()) { emit error("Remaining data after string list parsing"); return false; } return true; } void ServerCatchcopy::parseInput(const uint32_t &client,const uint32_t &orderId,const std::vector &returnList) { const ServerCatchcopy::inputReturnType returnVal=parseInputCurrentProtocol(client,orderId,returnList); switch(returnVal) { case Ok: emit newQuery(client,orderId,returnList); break; case Replied: break; case ExtensionWrong: //protocolExtensionSupported(client,orderId,false); break; case WrongArgument: incorrectArgument(client,orderId); break; case WrongArgumentListSize: incorrectArgumentListSize(client,orderId); break; case UnknowOrder: emit error("Unknown query: "+std::to_string(returnVal)+", with client: "+std::to_string(client)+", orderId: "+std::to_string(orderId)+", returnList: "+stringimplode2(returnList,", ")); qWarning() << "Unknown query"; unknowOrder(client,orderId); break; } } ServerCatchcopy::inputReturnType ServerCatchcopy::parseInputCurrentProtocol(const uint32_t &client,const uint32_t &orderId,const std::vector &returnList) { if(returnList.size()==0) return WrongArgumentListSize; //if is supported std::string firstArgument=returnList.front(); if(firstArgument=="protocol") { if(returnList.size()!=2) return WrongArgumentListSize; emit askProtocolCompatibility(client,orderId,returnList.back()); return Ok; } else if(firstArgument=="protocol extension") { if(returnList.size()>3 || returnList.size()<2) return WrongArgumentListSize; return ExtensionWrong; } else if(firstArgument=="client") { if(returnList.size()!=2) return WrongArgumentListSize; int index=0; int size=clientList.size(); while(index sourceList=returnList; sourceList.erase(sourceList.cbegin()); sourceList.pop_back(); emitNewCopy(client,orderId,sourceList,returnList.back()); return Ok; } else if(firstArgument=="cp-?") { if(returnList.size()<2) return WrongArgumentListSize; std::vector sourceList=returnList; sourceList.erase(sourceList.cbegin()); emitNewCopyWithoutDestination(client,orderId,sourceList); return Ok; } else if(firstArgument=="mv") { if(returnList.size()<3) return WrongArgumentListSize; std::vector sourceList=returnList; sourceList.erase(sourceList.cbegin()); sourceList.pop_back(); emitNewMove(client,orderId,sourceList,returnList.back()); return Ok; } else if(firstArgument=="mv-?") { if(returnList.size()<2) return WrongArgumentListSize; std::vector sourceList=returnList; sourceList.erase(sourceList.cbegin()); emitNewMoveWithoutDestination(client,orderId,sourceList); return Ok; } else //if is not supported return UnknowOrder; } void ServerCatchcopy::emitNewCopyWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector &sources) { LinkGlobalToLocalClient newAssociation; newAssociation.idClient=client; newAssociation.orderId=orderId; newAssociation.globalOrderId=incrementOrderId(); LinkGlobalToLocalClientList << newAssociation; emit newCopyWithoutDestination(newAssociation.globalOrderId,sources); } void ServerCatchcopy::emitNewCopy(const uint32_t &client,const uint32_t &orderId,const std::vector &sources,const std::string &destination) { LinkGlobalToLocalClient newAssociation; newAssociation.idClient=client; newAssociation.orderId=orderId; newAssociation.globalOrderId=incrementOrderId(); LinkGlobalToLocalClientList << newAssociation; emit newCopy(newAssociation.globalOrderId,sources,destination); } void ServerCatchcopy::emitNewMoveWithoutDestination(const uint32_t &client,const uint32_t &orderId,const std::vector &sources) { LinkGlobalToLocalClient newAssociation; newAssociation.idClient=client; newAssociation.orderId=orderId; newAssociation.globalOrderId=incrementOrderId(); LinkGlobalToLocalClientList << newAssociation; emit newMoveWithoutDestination(newAssociation.globalOrderId,sources); } void ServerCatchcopy::emitNewMove(const uint32_t &client,const uint32_t &orderId,const std::vector &sources,const std::string &destination) { LinkGlobalToLocalClient newAssociation; newAssociation.idClient=client; newAssociation.orderId=orderId; newAssociation.globalOrderId=incrementOrderId(); LinkGlobalToLocalClientList << newAssociation; emit newMove(newAssociation.globalOrderId,sources,destination); } void ServerCatchcopy::copyFinished(const uint32_t &globalOrderId,const bool &withError) { int index=0; while(index returnList; returnList.push_back(returnString); reply(client,orderId,returnCode,returnList); } void ServerCatchcopy::reply(const uint32_t &client,const uint32_t &orderId,const uint32_t &returnCode,const std::vector &returnList) { int index=0; while(indexisValid() && clientList.at(index).socket->state()==QLocalSocket::ConnectedState) { if(!clientList.at(index).queryNoReplied.contains(orderId)) { qWarning() << "Reply to missing query or previously replied"; return; } clientList[index].queryNoReplied.removeOne(orderId); //cut string list and send it as block of 32KB QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_4); out << int(0); out << orderId; out << returnCode; QStringList returnListQt; { unsigned int index=0; while(indexseek(0); out << block.size(); do { QByteArray blockToSend; int byteWriten; blockToSend=block.left(32*1024);//32KB block.remove(0,blockToSend.size()); byteWriten = clientList[index].socket->write(blockToSend); if(!clientList[index].socket->isValid()) { error_string="Socket is not valid"; emit error(error_string); return; } if(clientList[index].socket->error()!=QLocalSocket::UnknownSocketError && clientList[index].socket->error()!=QLocalSocket::PeerClosedError) { error_string="Error with socket: "+clientList[index].socket->errorString().toStdString(); emit error(error_string); return; } if(blockToSend.size()!=byteWriten) { error_string="All the bytes have not be written"; emit error(error_string); return; } } while(block.size()); } else { error_string="Socket is not valid or not connected"; emit error(error_string); } return; } index++; } qWarning() << "Client id not found:" << client; } void ServerCatchcopy::protocolSupported(const uint32_t &client,const uint32_t &orderId,const bool &value) { if(value) reply(client,orderId,1000,"protocol supported"); else reply(client,orderId,5003,"protocol not supported"); } void ServerCatchcopy::incorrectArgumentListSize(const uint32_t &client,const uint32_t &orderId) { reply(client,orderId,5000,"incorrect argument list size"); } void ServerCatchcopy::incorrectArgument(const uint32_t &client,const uint32_t &orderId) { reply(client,orderId,5001,"incorrect argument"); } void ServerCatchcopy::clientRegistered(const uint32_t &client,const uint32_t &orderId) { reply(client,orderId,1003,"client registered"); } void ServerCatchcopy::serverName(const uint32_t &client,const uint32_t &orderId,const std::string &name) { reply(client,orderId,1004,name); } void ServerCatchcopy::copyFinished(const uint32_t &client,const uint32_t &orderId,const bool &withError) { if(!withError) reply(client,orderId,1005,"finished"); else reply(client,orderId,1006,"finished with error(s)"); } void ServerCatchcopy::copyCanceled(const uint32_t &client,const uint32_t &orderId) { reply(client,orderId,1007,"canceled"); } void ServerCatchcopy::unknowOrder(const uint32_t &client,const uint32_t &orderId) { reply(client,orderId,5002,"unknown order"); } void ServerCatchcopy::checkTimeOut() { QTimer *timer=qobject_cast(QObject::sender()); if(timer==NULL) { qWarning() << "Unallocated client timer!"; return; } int index=0; while(indexstop(); if(clientList.at(index).haveData) { error_string="The client is too long to send the next part of the reply: "+QString(clientList.at(index).data.toHex()).toStdString(); clientList[index].haveData=false; clientList[index].data.clear(); clientList.at(index).socket->disconnectFromServer(); emit error(error_string); } return; } index++; } } uint32_t ServerCatchcopy::incrementOrderId() { do { nextOrderId++; if(nextOrderId>2000000) nextOrderId=0; } while(orderList.contains(nextOrderId)); return nextOrderId; }