diff --git a/src/io/pidatatransfer.cpp b/src/io/pidatatransfer.cpp index 2aabb616..97a596fb 100644 --- a/src/io/pidatatransfer.cpp +++ b/src/io/pidatatransfer.cpp @@ -1,374 +1,24 @@ #include "pidatatransfer.h" -const uint PIBaseTransfer::signature = 0x54444950; -PIBaseTransfer::PIBaseTransfer(): crc(standardCRC_16()) { - header.sig = signature; - header.session_id = 0; - packet_header_size = sizeof(PacketHeader); - part_header_size = sizeof(Part) + sizeof(PIByteArray); - is_sending = is_receiving = false; - break_ = true; - bytes_all = bytes_cur = 0; - timeout_ = 1.; - setPacketSize(4096); - srand(PISystemTime::current().toMilliseconds()); -} - - -PIBaseTransfer::~PIBaseTransfer() { - break_ = true; - session.clear(); - replies.clear(); -} - - -void PIBaseTransfer::stopSend() { - if (!is_sending) return; - break_ = true; -} - - -void PIBaseTransfer::stopReceive() { - if (!is_receiving) return; - break_ = true; - finish_receive(false); -} - - -void PIBaseTransfer::received(PIByteArray& data) { - if (data.size() < sizeof(PacketHeader)) return; - PacketHeader h; - memcpy(&h, data.data(), sizeof(PacketHeader)); - PacketType pt = (PacketType)h.type; -// piCoutObj << "receive" << h.session_id << h.type << h.id; - switch (pt) { - case pt_Unknown: - break; - case pt_Data: - if (h.session_id != header.session_id || !is_receiving) { - sendBreak(h.session_id); - return; - } else { - uint rcrc = h.crc; - uint ccrc = crc.calculate(data.data(sizeof(PacketHeader)), data.size_s() - sizeof(PacketHeader)); - if (rcrc != ccrc) { - header.id = h.id; - sendReply(pt_ReplyInvalid); - } else { - data >> h; - processData(h.id, data); - } - } - break; - case pt_ReplySuccess: - case pt_ReplyInvalid: - if (h.session_id != header.session_id) return; - if (is_sending) { - if (h.id >= 0 && h.id < replies.size()) - replies[h.id] = pt; - } - if (is_receiving && h.id == 0) { - if (checkSession() == 0 && pt == pt_ReplySuccess) finish_receive(true); - } - break; - case pt_Break: - break_ = true; - if (is_receiving) { - stopReceive(); - return; - } - if (is_sending) { - stopSend(); - return; - } - break; - case pt_Start: - if (is_sending) { - sendBreak(h.session_id); - return; - } - if (header.session_id != h.session_id && is_receiving) { - sendBreak(h.session_id); - return; - } - if (data.size() == sizeof(StartRequest) + sizeof(PacketHeader)) { - StartRequest sr; - memcpy(&sr, data.data(sizeof(PacketHeader)), sizeof(StartRequest)); - bytes_all = sr.size; - header.session_id = h.session_id; - header.id = 0; - state_string = "start request"; - session.clear(); - replies.clear(); - session.resize(sr.packets); - replies.resize(sr.packets + 1); - replies.fill(pt_Unknown); - is_receiving = true; - break_ = false; - state_string = "receiving"; - replies[0] = pt_ReplySuccess; - sendReply(pt_ReplySuccess); - } - break; - default: - break; - } -} - - -bool PIBaseTransfer::send_process() { - break_ = false; - is_sending = true; - startSend(); - replies.resize(session.size() + 1); - replies.fill(pt_Unknown); +PIByteArray PIDataTransfer::buildPacket(Part fi) { PIByteArray ba; - if (!getStartRequest()) return finish_send(false); - for (int i = 0; i < session.size_s(); i++) { - ba = build_packet(i); - sendRequest(ba); - if (break_) return finish_send(false); - } -// piCoutObj << "correct errors"; - PITimeMeasurer tm; - int prev_chk = 0; - while (tm.elapsed_s() < timeout_) { - int chk = checkSession(); - if (chk != prev_chk) tm.reset(); - if (chk == 0) return finish_send(true); - if (chk > 0) { - ba = buildPacket(chk - 1); - sendRequest(ba); - } -// if (chk == -1) return finish_send(false); - if (break_) return finish_send(false); - prev_chk = chk; - piMSleep(1); - } - return finish_send(false); + ba.resize(fi.size); + memcpy(ba.data(), data_.data(fi.start), fi.size); + return ba; } -int PIBaseTransfer::checkSession() { - int miss = 0; - for (int i = 1; i < replies.size_s(); i++) { - if (replies[i] != pt_ReplySuccess) miss++; - if (replies[i] == pt_ReplyInvalid) return i; - } - for (int i = 1; i < replies.size_s(); i++) { - if (replies[i] != pt_ReplySuccess) return i; - } - if (miss > 0) { - piCoutObj << "missing" << miss << "packets"; - return -miss; - } else return 0; +void PIDataTransfer::receivePart(Part fi, PIByteArray ba, PIByteArray pheader) { + if (data_.size() < fi.start + fi.size) data_.resize(fi.start + fi.size); + memcpy(data_.data(fi.start), ba.data(), ba.size_s()); } -void PIBaseTransfer::buildSession(PIVector parts) { - state_string = "calculating files... "; - session.clear(); - header.session_id = rand(); - bytes_all = 0; - Part fi; - int fi_index, fi_prts; - PIVector lfi; - int min_size = packet_header_size + part_header_size; - int cur_size = min_size; - for (int i = 0; i < parts.size_s(); i++) { - state_string = "calculating files... " + PIString::fromNumber(i) + " of " + PIString::fromNumber(parts.size()); - fi.id = parts[i].id; - bytes_all += fi.size; -// fi.size = fi.entry.size; - fi.start = 0; - int rest = parts[i].size - (packet_size - cur_size); -// piCout << i << fi.entry << rest; - if (rest <= 0) { - fi.size = parts[i].size; - lfi << fi; - cur_size += fi.size + part_header_size; - } else { - fi.size = parts[i].size - rest; - fi_index = 1; - fi_prts = 1 + 1 + piMaxi(1, rest / (packet_size - min_size)); -// piCout << fi_prts; - lfi << fi; - session << lfi; - lfi.clear(); - cur_size = min_size; - llong fs = fi.size; - for (int j = 1; j < fi_prts; j++) { - fi_index++; - fi.start = fs; - fi.size = piMin(parts[i].size - fs, packet_size - min_size); - lfi << fi; - cur_size += fi.size + part_header_size; - if (fi_index != fi_prts) { - session << lfi; - lfi.clear(); - cur_size = min_size; - fs += fi.size; - } - } - } - if (packet_size - cur_size < min_size) { - session << lfi; - lfi.clear(); - cur_size = min_size; - } - } - if (cur_size > min_size) session << lfi; +bool PIDataTransfer::send(const PIByteArray& ba) { + data_ = ba; + buildSession(PIVector() << Part(0, data_.size())); + return send_process(); } -void PIBaseTransfer::sendBreak(int session_id) { - uint psid = header.session_id; - header.session_id = session_id; - sendReply(pt_Break); - header.session_id = psid; -} - - -void PIBaseTransfer::sendReply(PacketType reply) { - header.type = reply; - PIByteArray ba; - ba << header; - sendRequest(ba); -} - - -bool PIBaseTransfer::getStartRequest() { - PITimeMeasurer tm; - header.type = pt_Start; - header.id = 0; - PIByteArray ba; - ba << header; - ba << (uint)session.size() << bytes_all; - state_string = "send request"; - for (int i = 0; i < 3; i++) { - tm.reset(); - sendRequest(ba); - while (tm.elapsed_s() < timeout_) { - if (break_) return false; - //piCoutObj << send_replyes[0]; - if (replies[0] == pt_ReplySuccess) { - state_string = "send permited!"; - return true; - } - piMSleep(10); - } - } - return false; -} - - -void PIBaseTransfer::processData(int id, PIByteArray & data) { -// piCoutObj << "received packet" << id << ", size" << data.size(); - if (id < 1 || id > replies.size_s()) return; - if (!session[id - 1].isEmpty()) { - header.id = id; - replies[id] = pt_ReplySuccess; - sendReply(pt_ReplySuccess); - if (checkSession() == 0) state_string = "receive ok"; - return; - } - Part fi; - PIByteArray ba, pheader; - pheader.resize(packet_header_size - sizeof(PacketHeader)); - if (!pheader.isEmpty()) { - memcpy(pheader.data(), data.data(), pheader.size()); - data.remove(0, pheader.size_s()); - } - while (!data.isEmpty()) { - ba.clear(); - data >> fi; - if (fi.size > 0) data >> ba; -// fi.fsize = ba.size(); - bytes_cur += fi.size; -// piCoutObj << "recv" << fi; - session[id - 1] << fi; - state_string = "receiving..."; - receivePart(fi, ba, pheader); - } - header.id = id; - replies[id] = pt_ReplySuccess; - if (checkSession() == 0) state_string = "receive ok"; - sendReply(pt_ReplySuccess); -} - - -PIByteArray PIBaseTransfer::build_packet(int id) { - PIByteArray ret; - PIByteArray ba; - header.id = id + 1; - header.type = pt_Data; - //piCoutObj << "Packet" << header.id; - //piCoutObj << "session id" << header.session_id; - ret << header; - ret << buildPacket(id); - /*for (int i = 0; i < session[id].size_s(); i++) { - EntryInfo fi = session[id][i]; -// piCoutObj << "send" << fi; - bytes_total_cur += fi.fsize; - ret << fi; - if (fi.entry.size > 0) { - PIString path = dir.absolutePath() + dir.separator + fi.entry.path; - if (work_file.path() != path || !work_file.isOpened()) { - if (!work_file.open(path, PIIODevice::ReadOnly)) { - break_ = true; - state_string = "ERROR! while open file " + fi.entry.path; - piCoutObj << state_string; - return ret; - } - } - work_file.seek(fi.fstart); - ba.resize(fi.fsize); - int rs = work_file.read(ba.data(), ba.size()); - if (rs != fi.fsize) { - break_ = true; - state_string = "ERROR! while read file " + fi.entry.path + " (must " + PIString::fromNumber(fi.fsize) + ", but read " + PIString::fromNumber(rs) + ")"; - piCoutObj << state_string; - return ret; - } - ret << ba; - } - } - EntryInfo cfile = session[id].back(); - state_string = "sending: " + cfile.entry.path; - bytes_file_all = cfile.entry.size; - bytes_file_cur = cfile.fstart; - uint scrc = crc.calculate(ret); - ret << scrc;*/ - //piCoutObj << "packet" << header.id << "send crc" << scrc; - return ret; -} - - -bool PIBaseTransfer::finish_send(bool ok) { - if (ok) state_string = "send done"; - else state_string = "send failed"; -// piCoutObj << state_string << PIString::readableSize(bytes_total_all); - is_sending = false; - bytes_all = bytes_cur = 0; - header.id = 0; - if (!ok) sendBreak(header.session_id); - else sendReply(pt_ReplySuccess); - finishSend(ok); - return ok; -} - - -void PIBaseTransfer::finish_receive(bool ok) { - if (ok) state_string = "receive done"; - else state_string = "receive failed"; -// piCoutObj << state_string << PIString::readableSize(bytes_total_all); - is_receiving = false; - bytes_all = bytes_cur = 0; - if (!ok) sendBreak(header.session_id); - finishReceive(ok); -} -PIByteArray PIDataTransfer::buildPacket(int id) { - ; -} - diff --git a/src/io/pidatatransfer.h b/src/io/pidatatransfer.h index a56f619f..1ec8cffd 100644 --- a/src/io/pidatatransfer.h +++ b/src/io/pidatatransfer.h @@ -1,103 +1,7 @@ #ifndef PIDATATRANSFER_H #define PIDATATRANSFER_H -#include "picrc.h" -#include "pitimer.h" - -class PIBaseTransfer : public PIObject -{ - PIOBJECT(PIBaseTransfer) -public: - PIBaseTransfer(); - ~PIBaseTransfer(); - - struct PacketHeader { - uint sig; - int type; // PacketType - uint session_id; - uint id; - uint crc; - bool check_sig() {return (sig == signature);} - }; - - struct Part { - Part(uint id_ = 0, ullong size_ = 0, ullong start_ = 0) : id(id_), size(size_), start(start_) {} - uint id; - ullong size; - ullong start; - }; - - virtual void stopSend(); - virtual void stopReceive(); - - virtual bool isSending() const {return is_sending;} - virtual bool isReceiving() const {return is_receiving;} - - void setPacketSize(int size) {packet_size = size;} - int packetSize() const {return packet_size;} - - void setTimeout(double sec) {timeout_ = sec;} - double timeout() const {return timeout_;} - - const PIString & stateString() const {return state_string;} - llong bytesAll() const {return bytes_all;} - llong bytesCur() const {return bytes_cur;} - const PIString * stateString_ptr() const {return &state_string;} - const llong * bytesAll_ptr() const {return &bytes_all;} - const llong * bytesCur_ptr() const {return &bytes_cur;} - - EVENT(startReceive) - EVENT1(finishReceive, bool, ok) - EVENT(startSend) - EVENT1(finishSend, bool, ok) - EVENT1(sendRequest, PIByteArray &, data) - EVENT_HANDLER1(void, received, PIByteArray &, data); - -protected: - uint packet_header_size, part_header_size; - bool break_, is_sending, is_receiving; - PIString state_string; - llong bytes_all, bytes_cur; - - void buildSession(PIVector parts); - virtual PIByteArray buildPacket(int id) = 0; - virtual void receivePart(Part fi, PIByteArray ba, PIByteArray header) = 0; - -private: - - enum PacketType {pt_Unknown, pt_Data, pt_ReplySuccess, pt_ReplyInvalid, pt_Break, pt_Start}; - - struct StartRequest { - uint packets; - ullong size; - }; - - - static const uint signature; - int packet_size; - double timeout_; - PIVector > session; - PIVector replies; - PacketHeader header; - CRC_16 crc; - - void processData(int id, PIByteArray &data); - PIByteArray build_packet(int id); - int checkSession(); - bool send_process(); - void sendBreak(int session_id); - void sendReply(PacketType reply); - bool getStartRequest(); - bool finish_send(bool ok); - void finish_receive(bool ok); -}; - -inline PIByteArray & operator <<(PIByteArray & s, const PIBaseTransfer::PacketHeader & v) {s << v.sig << v.type << v.session_id << v.id; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIBaseTransfer::PacketHeader & v) {s >> v.sig >> v.type >> v.session_id >> v.id; return s;} - -inline PIByteArray & operator <<(PIByteArray & s, const PIBaseTransfer::Part & v) {s << v.id << v.size << v.start; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIBaseTransfer::Part & v) {s >> v.id >> v.size >> v.start; return s;} - +#include "pibasetransfer.h" class PIDataTransfer : public PIBaseTransfer { @@ -105,11 +9,14 @@ class PIDataTransfer : public PIBaseTransfer public: PIDataTransfer() {;} ~PIDataTransfer() {;} - virtual PIByteArray buildPacket(int id); - virtual void receivePart(Part fi, PIByteArray ba, PIByteArray header) {;} - + + bool send(const PIByteArray &ba); + const PIByteArray &data() {return data_;} + private: - PIByteArray data; + virtual PIByteArray buildPacket(Part p); + virtual void receivePart(PIBaseTransfer::Part fi, PIByteArray ba, PIByteArray pheader); + PIByteArray data_; }; diff --git a/src/io/pidir.cpp b/src/io/pidir.cpp index a809e33a..01beb2d9 100755 --- a/src/io/pidir.cpp +++ b/src/io/pidir.cpp @@ -1,7 +1,7 @@ /* PIP - Platform Independent Primitives Directory - Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com + Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -185,6 +185,7 @@ bool PIDir::make(bool withParents) { break; }; } + return true; } else if (makeDir(d.path_)) return true; return false; @@ -217,13 +218,8 @@ PIVector PIDir::entries() { # else const_cast(p.data()), 0 # endif - , 0, -# ifdef MAC_OS - alphasort); -# else - versionsort); -# endif - for (int i = 0; i < cnt; ++i) { + , 0, versionsort); + for (int i = 0; i < cnt; ++i) { l << PIFile::fileInfo(dp + PIString(list[i]->d_name)); delete list[i]; } diff --git a/src/io/pidir.h b/src/io/pidir.h index 410fc742..a5f3ced4 100755 --- a/src/io/pidir.h +++ b/src/io/pidir.h @@ -4,7 +4,7 @@ /* PIP - Platform Independent Primitives Directory - Copyright (C) 2015 Ivan Pelipenko peri4ko@gmail.com + Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/io/pifiletransfer.cpp b/src/io/pifiletransfer.cpp index 8cb77f3f..2b09be95 100644 --- a/src/io/pifiletransfer.cpp +++ b/src/io/pifiletransfer.cpp @@ -2,480 +2,246 @@ const char PIFileTransfer::sign[] = {'P', 'F', 'T'}; -PIFileTransfer::PIFileTransfer(): crc(standardCRC_16()) { +PIFileTransfer::PIFileTransfer() { for (uint i = 0; i < sizeof(sign); i++) - header.sig[i] = sign[i]; - header.version = PIFILETRANSFER_VERSION; - header.session_id = 0; + pftheader.sig[i] = sign[i]; + pftheader.version = __PIFILETRANSFER_VERSION; + pftheader.session_id = 0; + pftheader.step = pft_None; dir = PIDir::current(); - fileinfo_size = sizeof(EntryInfo) + sizeof(FilePart) + 100; - min_packet_size = sizeof(PacketHeader) + sizeof(uint) + fileinfo_size; is_sending = is_receiving = false; - bytes_file_all = bytes_file_cur = bytes_total_all = bytes_total_cur = 0; - timeout_ = 1.; - setPacketSize(4096); - srand(PISystemTime::current().toMilliseconds()); + bytes_file_all = bytes_file_cur = 0; +// CONNECT(void, this, sendStarted, this, send_started); + CONNECT(void, this, receiveStarted, this, receive_started); + CONNECT1(void, bool, this, sendFinished, this, send_finished); + CONNECT1(void, bool, this, receiveFinished, this, receive_finished); } PIFileTransfer::~PIFileTransfer() { break_ = true; - session.clear(); - replies.clear(); + files_.clear(); + work_file.close(); } bool PIFileTransfer::send(const PIString & file) { - PIVector ce = dir.entries(); - PIFile::FileInfo e; - e.path = ""; - for (int i = 0; i < ce.size_s(); i++) { - if (ce[i].path == file) e = ce[i]; - } - if (e.path != "") return sendFiles(PIVector() << e); - return false; + return send(PIVector() << PIFile::fileInfo(file)); } bool PIFileTransfer::send(PIVector entries) { PIVector allEntries; - PIVector ce; - PISet names; for (int i = 0; i < entries.size_s(); i++) { - ce.clear(); + allEntries << entries[i]; if (entries[i].isDir()) - ce = PIDir::allEntries(dir.absolutePath() + dir.separator + entries[i].path); - for (int k = 0; k < ce.size_s(); k++) ce[k].path = entries[i].path + dir.separator + ce[k].path; - ce.push_front(entries[i]); - for (int j = 0; j < ce.size_s(); j++) { - if (names.contains(ce[j].path)) continue; - allEntries << ce[j]; - //piCout << ce[j].path; - names << ce[j].path; - } + allEntries << PIDir::allEntries(dir.absolutePath() + dir.separator + entries[i].path); } return sendFiles(allEntries); } -void PIFileTransfer::stopSend() { - if (!is_sending) return; - break_ = true; -} - - -void PIFileTransfer::stopReceive() { - if (!is_receiving) return; - break_ = true; - finish_receive(false); -} - - -void PIFileTransfer::received(PIByteArray & ba) { - if (ba.size() < sizeof(PacketHeader)) return; - PacketHeader h; - memcpy(&h, ba.data(), sizeof(PacketHeader)); - PacketType pt = (PacketType)h.type; -// piCoutObj << "receive" << h.session_id << h.type << h.id; - switch (pt) { - case pt_Data: - if (h.session_id != header.session_id || !is_receiving) { - sendBreak(h.session_id); - return; - } else { - uint rcrc = *(uint *)(ba.data(ba.size_s() - sizeof(uint))); - uint ccrc = crc.calculate(ba.data(), ba.size_s() - sizeof(uint)); - if (rcrc != ccrc) { - header.id = h.id; - sendReply(Invalid); - } else { - ba >> h; - ba.resize(ba.size_s() - sizeof(uint)); - processData(h.id, ba); - } - } - break; - case pt_Reply: - if (h.session_id != header.session_id) return; - ba >> h; - if (ba.size() == sizeof(int)) { - int rci; - ba >> rci; - ReplyCode rc = (ReplyCode)rci; -// piCoutObj << "reply received" << rci; - if (rc == Break) { - break_ = true; - if (is_receiving) { - stopReceive(); - return; - } - if (is_sending) { - stopSend(); - return; - } - } - if (is_sending) { - if (h.id >= 0 && h.id < replies.size()) - replies[h.id] = rc; - } - if (is_receiving && h.id == 0) { - if (checkSession() == 0) finish_receive(true); - } - } - break; - case pt_SendRequest: - if (is_sending) { - sendBreak(h.session_id); - return; - } - if (header.session_id != h.session_id && is_receiving) { - sendBreak(h.session_id); - return; - } - ba >> h; - if (ba.size() != sizeof(uint) + sizeof(llong)) return; - uint pcts; - ba >> pcts; - bytes_file_all = pcts; - ba >> bytes_total_all; - header.session_id = h.session_id; - header.id = 0; - bool ok = true; - state_string = "receive request"; - receiveRequest(&ok); - if (ok) { - session.clear(); - replies.clear(); - session.resize(pcts); - replies.resize(pcts + 1); - replies.fill(Unknown); - is_receiving = true; - state_string = "receiving"; - replies[0] = Success; - sendReply(Success); - } else { - sendReply(Invalid); - state_string = "wait user permit"; - } - break; +bool PIFileTransfer::sendFiles(const PIVector &files) { + files_ = files; + PIStringList names; +// piCoutObj << "prepare to send" << files_.size() << "files"; + for(int i=0; i() << Part(0, desc.size())); + if (!send_process()) return false; + pftheader.step = pft_Data; + PIVector pts; + for (int i=0; i files) { -// piCoutObj << "prepare to send" << files.size() << "files"; - break_ = false; - is_sending = true; - buildSession(files); - replies.resize(session.size() + 1); - replies.fill(Unknown); - work_file.setPath(""); - startSend(); - bytes_file_all = bytes_file_cur = 0; - PIByteArray ba; - if (!getSendRequest()) return finish_send(false); - for (int i = 0; i < session.size_s(); i++) { - ba = buildPacket(i); - sendRequest(ba); - if (break_) return finish_send(false); - } -// piCoutObj << "correct errors"; - PITimeMeasurer tm; - int prev_chk = 0; - while (tm.elapsed_s() < timeout_) { - int chk = checkSession(); - if (chk != prev_chk) tm.reset(); - if (chk == 0) return finish_send(true); - if (chk > 0) { - ba = buildPacket(chk - 1); - sendRequest(ba); - } -// if (chk == -1) return finish_send(false); - if (break_) return finish_send(false); - prev_chk = chk; - piMSleep(1); - } - return finish_send(false);; -} - - -int PIFileTransfer::checkSession() { - int miss = 0; - for (int i = 1; i < replies.size_s(); i++) { - if ((ReplyCode)replies[i] != Success) miss++; - if ((ReplyCode)replies[i] == Invalid) return i; - } - for (int i = 1; i < replies.size_s(); i++) { - if ((ReplyCode)replies[i] == Unknown) return i; - } - if (miss > 0) { - piCoutObj << "missing" << miss << "packets"; - return -miss; - } else return 0; -} - - -void PIFileTransfer::buildSession(PIVector files) { - state_string = "calculating files..."; - session.clear(); - header.session_id = rand(); - bytes_file_cur = 0; - bytes_file_all = files.size(); - bytes_total_all = bytes_total_cur = 0; -// PIMap sizes; -// for (int i=0; i indexes = sizes.values(); - EntryInfo fi; - PIVector lfi; - int cur_size = min_packet_size; - for (int i = 0; i < files.size_s(); i++) { - bytes_file_cur = i; - fi.entry = files[i]; - bytes_total_all += fi.entry.size; -// fi.size = fi.entry.size; - fi.fstart = 0; - fi.part_index = 1; - int rest = fi.entry.size - (max_packet_size - cur_size); -// piCout << i << fi.entry << rest; - if (rest <= 0) { - fi.parts = 1; - fi.fsize = fi.entry.size; - lfi << fi; - cur_size += fi.fsize + fileinfo_size; - } else { - fi.fsize = fi.entry.size - rest; - fi.parts = 1 + 1 + piMaxi(1, rest / (max_packet_size - min_packet_size)); -// piCout << fi.parts; - lfi << fi; - session << lfi; - lfi.clear(); - cur_size = min_packet_size; - llong fs = fi.fsize; - for (uint j = 1; j < fi.parts; j++) { - fi.part_index++; - fi.fstart = fs; - fi.fsize = piMinll(fi.entry.size - fs, max_packet_size - min_packet_size); - lfi << fi; - cur_size += fi.fsize + sizeof(FilePart); - if (fi.part_index != fi.parts) { - session << lfi; - lfi.clear(); - cur_size = min_packet_size; - fs += fi.fsize; - } - } - } - if (max_packet_size - cur_size < min_packet_size) { - session << lfi; - lfi.clear(); - cur_size = min_packet_size; - } - } - if (cur_size > min_packet_size) session << lfi; -} - - -void PIFileTransfer::sendBreak(int session_id) { - uint psid = header.session_id; - header.session_id = session_id; - sendReply(Break); - header.session_id = psid; -} - - -void PIFileTransfer::sendReply(PIFileTransfer::ReplyCode reply) { -// if (is_send_result) header.type = pt_SendResult; -// else - header.type = pt_Reply; - PIByteArray ba; - ba << header << (int)reply; - sendRequest(ba); -} - - -bool PIFileTransfer::getSendRequest() { - PITimeMeasurer tm; - header.type = pt_SendRequest; - header.id = 0; - PIByteArray ba; - ba << header; - ba << (uint)session.size() << bytes_total_all; - state_string = "send request"; - for (int i = 0; i < 3; i++) { - tm.reset(); - sendRequest(ba); - while (tm.elapsed_s() < timeout_) { - if (break_) return false; - //piCoutObj << send_replyes[0]; - if (replies[0] == Success) { - state_string = "send permited!"; - return true; - } - if (replies[0] == Invalid) { - state_string = "waiting for permit"; - tm.reset(); - } - piMSleep(10); - } - } - return false; -} - - -void PIFileTransfer::processData(int id, PIByteArray & data) { -// piCoutObj << "received packet" << id << ", size" << data.size(); - if (id < 1 || id > replies.size_s()) return; - if (!session[id - 1].isEmpty()) { - header.id = id; - replies[id] = Success; - sendReply(Success); - if (checkSession() == 0) state_string = "receive ok"; - return; - } - EntryInfo fi; - PIByteArray ba; - while (!data.isEmpty()) { - ba.clear(); - data >> fi; - if (fi.entry.size > 0) data >> ba; - fi.fsize = ba.size(); - bytes_total_cur += fi.fsize; - bytes_file_all = fi.entry.size; - bytes_file_cur = fi.fstart; -// piCoutObj << "recv" << fi; - session[id - 1] << fi; - state_string = "receiving " + fi.entry.path; - PIString path = dir.absolutePath() + dir.separator + fi.entry.path; - if (fi.entry.isDir()) { -// piCoutObj << "make dir" << fi.entry.path; - if (!PIDir::make(path, false)) { - state_string = "ERROR! while create directory " + path; - piCoutObj << state_string; - finish_receive(false); - return; - } - } - if (fi.entry.isFile()) { - if (work_file.path() != path || !work_file.isOpened()) { - work_file.close(); - if (!work_file.open(path, PIIODevice::ReadWrite)) { - state_string = "ERROR! while open file " + path; - piCoutObj << state_string; - finish_receive(false); - return; - } - if (work_file.size() > fi.entry.size) { - piCoutObj << "*** error size" << work_file.size() << fi.entry.size; - work_file.clear(); - work_file.resize(fi.entry.size); - piCoutObj << "*** correct size" << work_file.size() << fi.entry.size; - } - } -// piCoutObj << "write file" << path << work_file.path() << work_file.size() << fi.entry.size << work_file.pos() << fi.fstart << fi.fsize; - if (work_file.size() < fi.fstart) { -// piCoutObj << "error pos size" << work_file.pos() << fi.fstart; - work_file.resize(fi.fstart); -// piCoutObj << "correct pos size" << work_file.pos() << fi.fstart; - } - if (work_file.size() > fi.entry.size) { - piCoutObj << "!!! error size" << work_file.size() << fi.entry.size; - work_file.clear(); - work_file.resize(fi.entry.size); - piCoutObj << "!!! correct size" << work_file.size() << fi.entry.size; - } -// if (fi.fstart != work_file.pos()) piCoutObj << "error pos" << work_file.pos() << fi.fstart; - work_file.seek(fi.fstart); - int rs = work_file.write(ba.data(), ba.size()); - if (rs != fi.fsize) { - state_string = "ERROR! while read file " + fi.entry.path + " (must " + PIString::fromNumber(fi.fsize) + ", but read " + PIString::fromNumber(rs) + ")"; - piCoutObj << state_string; - finish_receive(false); - return; - } - } - } - header.id = id; - replies[id] = Success; - if (checkSession() == 0) state_string = "receive ok"; - sendReply(Success); -} - - -PIByteArray PIFileTransfer::buildPacket(int id) { - PIByteArray ret; - PIByteArray ba; - header.id = id + 1; - header.type = pt_Data; - //piCoutObj << "Packet" << header.id; - //piCoutObj << "session id" << header.session_id; - ret << header; - for (int i = 0; i < session[id].size_s(); i++) { - EntryInfo fi = session[id][i]; -// piCoutObj << "send" << fi; - bytes_total_cur += fi.fsize; - ret << fi; - if (fi.entry.size > 0) { - PIString path = dir.absolutePath() + dir.separator + fi.entry.path; - if (work_file.path() != path || !work_file.isOpened()) { - if (!work_file.open(path, PIIODevice::ReadOnly)) { - break_ = true; - state_string = "ERROR! while open file " + fi.entry.path; - piCoutObj << state_string; - return ret; - } - } - work_file.seek(fi.fstart); - ba.resize(fi.fsize); - int rs = work_file.read(ba.data(), ba.size()); - if (rs != fi.fsize) { - break_ = true; - state_string = "ERROR! while read file " + fi.entry.path + " (must " + PIString::fromNumber(fi.fsize) + ", but read " + PIString::fromNumber(rs) + ")"; - piCoutObj << state_string; - return ret; - } - ret << ba; - } - } - EntryInfo cfile = session[id].back(); - state_string = "sending: " + cfile.entry.path; - bytes_file_all = cfile.entry.size; - bytes_file_cur = cfile.fstart; - uint scrc = crc.calculate(ret); - ret << scrc; - //piCoutObj << "packet" << header.id << "send crc" << scrc; - return ret; -} - - -bool PIFileTransfer::finish_send(bool ok) { - if (ok) state_string = "send done"; - else state_string = "send failed"; -// piCoutObj << state_string << PIString::readableSize(bytes_total_all); - is_sending = false; - work_file.close(); - work_file.setPath(""); - bytes_file_all = bytes_file_cur = 0; - bytes_total_all = bytes_total_cur = 0; - header.id = 0; - if (!ok) sendBreak(header.session_id); - else sendReply(Success); - finishSend(ok); + buildSession(pts); + bool ok = send_process(); return ok; } -void PIFileTransfer::finish_receive(bool ok) { - if (ok) state_string = "receive done"; - else state_string = "receive failed"; -// piCoutObj << state_string << PIString::readableSize(bytes_total_all); - is_receiving = false; - work_file.close(); - work_file.setPath(""); - bytes_file_all = bytes_file_cur = 0; - bytes_total_all = bytes_total_cur = 0; - if (!ok) sendBreak(header.session_id); - finishReceive(ok); + +void PIFileTransfer::processFile(int id, ullong start, PIByteArray & data) { +// piCout << "processFile" << id << files_.size(); + PIFile::FileInfo fi = files_[id-1]; + bytes_file_all = fi.size; + bytes_file_cur = start; + cur_file_string = fi.path; + PIString path = dir.absolutePath() + dir.separator + fi.path; +// piCout << "receive" << path << fi.size << data.size(); + if (fi.isDir()) { +// piCoutObj << "make dir" << fi.entry.path; + if (!PIDir::make(path)) { + cur_file_string = "ERROR! while create directory " + path; + piCoutObj << cur_file_string; + stopReceive(); + return; + } + } + if (fi.isFile()) { + if (work_file.path() != path || !work_file.isOpened()) { + work_file.close(); + if (!work_file.open(path, PIIODevice::ReadWrite)) { + cur_file_string = "ERROR! while open file " + path; + piCoutObj << cur_file_string; + stopReceive(); + return; + } + if (work_file.size() > fi.size) { +// piCoutObj << "error size" << work_file.size() << fi.size; + work_file.clear(); + work_file.resize(fi.size); +// piCoutObj << "correct size" << work_file.size() << fi.size; + } + } +// piCoutObj << "write file" << path << work_file.path() << work_file.size() << fi.entry.size << work_file.pos() << fi.fstart << fi.fsize; + if (work_file.size() < (llong)start) { +// piCoutObj << "error pos size" << work_file.pos() << fi.fstart; + work_file.resize(start); +// piCoutObj << "correct pos size" << work_file.pos() << fi.fstart; + } + if (work_file.size() > fi.size) { + piCoutObj << "****** error size" << work_file.size() << fi.size; + work_file.clear(); + work_file.resize(fi.size); + piCoutObj << "****** correct size" << work_file.size() << fi.size; + } +// if (fi.fstart != work_file.pos()) piCoutObj << "error pos" << work_file.pos() << fi.fstart; + work_file.seek(start); + int rs = work_file.write(data.data(), data.size()); + if (rs != data.size_s()) { + cur_file_string = "ERROR! while write file " + fi.path + " (must " + PIString::fromNumber(data.size()) + ", but write " + PIString::fromNumber(rs) + ")"; + piCoutObj << cur_file_string; + stopReceive(); + return; + } + } } + +PIByteArray PIFileTransfer::buildPacket(Part p) { +// piCoutObj << "Step" << pftheader.step; +// piCoutObj << "session id" << pftheader.session_id; + PIByteArray ba; + switch(pftheader.step) { + case pft_None: + stopSend(); + return PIByteArray(); + case pft_Description: + ba.resize(p.size); + memcpy(ba.data(), desc.data(p.start), p.size); + return ba; + case pft_Data: +// piCout << "send data" << p.id << files_.size(); + PIFile::FileInfo fi = files_[p.id-1]; + if (fi.isFile()) { +// piCout << "send file" << fi.name() << fi.size; + PIString path = dir.absolutePath() + dir.separator + fi.path; + if (work_file.path() != path || !work_file.isOpened()) { + if (!work_file.open(path, PIIODevice::ReadOnly)) { + break_ = true; + cur_file_string = "ERROR! while open file " + fi.path; + piCoutObj << cur_file_string; + stopSend(); + return PIByteArray(); + } + } + work_file.seek(p.start); + ba.resize(p.size); + int rs = work_file.read(ba.data(), ba.size()); + if ((llong)rs != (llong)p.size) { + break_ = true; + cur_file_string = "ERROR! while read file " + fi.path + " (must " + PIString::fromNumber(p.size) + ", but read " + PIString::fromNumber(rs) + ")"; + piCoutObj << cur_file_string; + stopSend(); + return PIByteArray(); + } + } +// if (fi.isDir()) { +// piCout << "create dir" << fi.path; +// dir.make(fi.path); +// } + cur_file_string = fi.path; + bytes_file_all = fi.size; + bytes_file_cur = p.start; + return ba; + } + return PIByteArray(); +} + + +void PIFileTransfer::receivePart(PIBaseTransfer::Part fi, PIByteArray ba, PIByteArray pheader) { + PFTHeader h; +// piCout << pheader.size() << sizeof(PFTHeader); + pheader >> h; +// piCout << h.session_id; + StepType st = (StepType)h.step; + pftheader.step = st; + if (!h.check_sig()) { + cur_file_string = "ERROR File Transfer uncompatable! or invalid version"; + piCoutObj << cur_file_string; + stopReceive(); + return; + } + switch(st) { + case pft_None: + break; + case pft_Description: + pftheader.session_id = h.session_id; + if (desc.size() < fi.start + fi.size) desc.resize(fi.start + fi.size); + memcpy(desc.data(fi.start), ba.data(), ba.size_s()); + break; + case pft_Data: + if (h.session_id == pftheader.session_id) + processFile(fi.id, fi.start, ba); + else stopReceive(); + break; + default: + break; + } +} + + +PIByteArray PIFileTransfer::customHeader() { + PIByteArray ba; + ba << pftheader; + return ba; +} + + +void PIFileTransfer::receive_started() { + if (pftheader.step == pft_None) { + files_.clear(); + receiveFilesStarted(); + } +} + + +void PIFileTransfer::receive_finished(bool ok) { + if (pftheader.step == pft_Description) { + if (ok) desc >> files_; + else { + pftheader.session_id--; + receiveFilesFinished(false); + } + } + if (pftheader.step == pft_Data) receiveFilesFinished(ok); +} + + +void PIFileTransfer::send_finished(bool ok) { + sendFilesFinished(ok); +} + + diff --git a/src/io/pifiletransfer.h b/src/io/pifiletransfer.h index 51eeaaa8..0160de45 100644 --- a/src/io/pifiletransfer.h +++ b/src/io/pifiletransfer.h @@ -2,38 +2,21 @@ #define PIFILETRANSFER_H #include "pidir.h" -#include "picrc.h" +#include "pibasetransfer.h" -#define PIFILETRANSFER_VERSION 1 +#define __PIFILETRANSFER_VERSION 2 -class PIFileTransfer : public PIObject +class PIFileTransfer : public PIBaseTransfer { - PIOBJECT(PIFileTransfer) + PIOBJECT_SUBCLASS(PIFileTransfer, PIBaseTransfer) public: PIFileTransfer(); ~PIFileTransfer(); - enum ReplyCode {Unknown = 0, Success, Invalid, Break}; - enum PacketType {pt_Data = 1, pt_Reply, pt_SendRequest};//, pt_SendResult}; + enum StepType {pft_None, pft_Description, pft_Data}; - struct EntryInfo { - EntryInfo() { - fstart = fsize = 0; - parts = part_index = 0; - } - PIFile::FileInfo entry; - llong fstart; - llong fsize; - uint parts; - uint part_index; - }; - - struct FilePart { - uint index; - PIByteArray data; - }; - - struct PacketHeader { +#pragma pack(push,1) + struct PFTHeader { union { struct { char sig[3]; // PFT @@ -41,93 +24,64 @@ public: }; uint raw_sig; }; - int type; // PacketType - uint session_id; - uint id; + int step; // PacketType + int session_id; bool check_sig() { - if (sig[0] != sign[0] || sig[1] != sign[1] || sig[2] != sign[2] || version != PIFILETRANSFER_VERSION) return false; + if (sig[0] != sign[0] || sig[1] != sign[1] || sig[2] != sign[2] || version != __PIFILETRANSFER_VERSION) return false; return true; } -// uint crc; }; +#pragma pack(pop) - //bool send(const PIFile & file); + bool send(const PIFile & file); bool send(const PIString & file); -// bool send(const PIStringList &files); + bool send(const PIStringList &files); bool send(PIFile::FileInfo entry) {return send(PIVector() << entry);} bool send(PIVector entries); - void stopSend(); - void stopReceive(); - - bool isSending() const {return is_sending;} - bool isReceiving() const {return is_receiving;} - - void setPacketSize(int size) {max_packet_size = size;} - int packetSize() const {return max_packet_size;} - - void setTimeout(double sec) {timeout_ = sec;} - double timeout() const {return timeout_;} - void setDirectory(const PIDir &d) {dir = d;} void setDirectory(const PIString &path) {dir.setDir(path);} PIDir directory() const {return dir;} - const PIString & stateString() const {return state_string;} - llong bytesTotalAll() const {return bytes_total_all;} - llong bytesTotalCur() const {return bytes_total_cur;} + const PIString & curFile() const {return cur_file_string;} llong bytesFileAll() const {return bytes_file_all;} llong bytesFileCur() const {return bytes_file_cur;} - const PIString * stateString_ptr() const {return &state_string;} - const llong * bytesTotalAll_ptr() const {return &bytes_total_all;} - const llong * bytesTotalCur_ptr() const {return &bytes_total_cur;} + const PIString * curFile_ptr() const {return &cur_file_string;} const llong * bytesFileAll_ptr() const {return &bytes_file_all;} const llong * bytesFileCur_ptr() const {return &bytes_file_cur;} - EVENT(startReceive) - EVENT1(receiveRequest, bool *, ok) - EVENT1(finishReceive, bool, ok) - EVENT(startSend) - EVENT1(finishSend, bool, ok) - - EVENT1(sendRequest, PIByteArray &, data) - EVENT_HANDLER1(void, received, PIByteArray &, data); - + EVENT(receiveFilesStarted) + EVENT1(receiveFilesFinished, bool, ok) + EVENT(sendFilesStarted) + EVENT1(sendFilesFinished, bool, ok) + private: static const char sign[]; - int max_packet_size, min_packet_size, fileinfo_size; - bool break_, is_sending, is_receiving; - double timeout_; - - PIVector > session; - PIVector replies; - PIString state_string; - llong bytes_total_all, bytes_total_cur, bytes_file_all, bytes_file_cur; - PacketHeader header; + PIVector files_; + PIString cur_file_string; + llong bytes_file_all, bytes_file_cur; + PFTHeader pftheader; PIDir dir; PIFile work_file; - CRC_16 crc; + PIByteArray desc; - bool sendFiles(PIVector files); - int checkSession(); - void buildSession(PIVector files); - void sendBreak(int session_id); - void sendReply(ReplyCode reply); - bool getSendRequest(); - void processData(int id, PIByteArray &data); - PIByteArray buildPacket(int id); - bool finish_send(bool ok); - void finish_receive(bool ok); + bool sendFiles(const PIVector &files); + void processFile(int id, ullong start, PIByteArray &data); + virtual void receivePart(Part fi, PIByteArray ba, PIByteArray pheader); + virtual PIByteArray buildPacket(Part fi); + virtual PIByteArray customHeader(); +// EVENT_HANDLER(void, send_started); + EVENT_HANDLER(void, receive_started); + EVENT_HANDLER1(void, send_finished, bool, ok); + EVENT_HANDLER1(void, receive_finished, bool, ok); }; -inline PIByteArray & operator <<(PIByteArray & s, const PIFileTransfer::PacketHeader & v) {s << v.raw_sig << v.type << v.session_id << v.id; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIFileTransfer::PacketHeader & v) {s >> v.raw_sig >> v.type >> v.session_id >> v.id; return s;} +inline PIByteArray & operator <<(PIByteArray & s, const PIFileTransfer::PFTHeader & v) {s << v.raw_sig << v.step << v.session_id; return s;} +inline PIByteArray & operator >>(PIByteArray & s, PIFileTransfer::PFTHeader & v) {s >> v.raw_sig >> v.step >> v.session_id; return s;} - -inline PIByteArray & operator <<(PIByteArray & s, const PIFileTransfer::EntryInfo & v) {s << v.entry.path << v.entry.size << v.entry.time_modification << v.entry.time_access << int(v.entry.flags) - << v.entry.id_user << v.entry.id_group << v.fstart; return s;} -inline PIByteArray & operator >>(PIByteArray & s, PIFileTransfer::EntryInfo & v) {s >> v.entry.path >> v.entry.size >> v.entry.time_modification >> v.entry.time_access >> (int&)(v.entry.flags) - >> v.entry.id_user >> v.entry.id_group >> v.fstart; return s;} -inline PICout operator <<(PICout s, const PIFileTransfer::EntryInfo & v) {s.setControl(0, true); s << "FileInfo(\"" << v.entry.path << "\", " << PIString::fromNumber(v.entry.flags, 16) << PIString::readableSize(v.entry.size) << " b | " << PIString::readableSize(v.fsize) << " b)"; s.restoreControl(); return s;} +inline PIByteArray & operator <<(PIByteArray & s, const PIFile::FileInfo & v) {s << v.path << v.size << v.time_access << v.time_modification << + (int)v.flags << v.id_user << v.id_group << v.perm_user.raw << v.perm_group.raw << v.perm_other.raw; return s;} +inline PIByteArray & operator >>(PIByteArray & s, PIFile::FileInfo & v) {s >> v.path >> v.size >> v.time_access >> v.time_modification >> + *(int*)(&(v.flags)) >> v.id_user >> v.id_group >> v.perm_user.raw >> v.perm_group.raw >> v.perm_other.raw; return s;} #endif // PIFILETRANSFER_H