Fixed partial stream management

Added proper state managemment
Fixed state posting to peer
Added flushes to ensure data is sent in the proper order
Added permissive mode to error-checks (optional)
Properly implemented full-packet stream interruption
This commit is contained in:
Gabriel Tofvesson 2017-10-07 22:11:37 +02:00
parent 43cea7b40b
commit be17d51c3f
2 changed files with 33 additions and 16 deletions

View File

@ -7,6 +7,7 @@
#include <windows.h> #include <windows.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
namespace IO { namespace IO {
bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) { bool cryptoLevelsAreCompatible(CryptoLevel l1, CryptoLevel l2) {
return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force))); return !(((l1 == CryptoLevel::None) && (l2 == CryptoLevel::Force)) || ((l2 == CryptoLevel::None) && (l1 == CryptoLevel::Force)));
@ -498,10 +499,17 @@ namespace IO {
else return *c; else return *c;
} }
PartialNetworkStream::PartialNetworkStream(NetClient& client, bool noBuffer) : std::ostream(std::_Uninitialized::_Noinit), client(client), buffer(noBuffer?nullptr:new std::vector<char>()){ /* NOP */} PartialNetworkStream::PartialNetworkStream(NetClient& client, bool noBuffer, bool permissive) :
std::ostream(std::_Uninitialized::_Noinit),
client(client),
buffer(noBuffer?nullptr:new std::vector<char>()),
permissive(permissive)
{ /* NOP */}
PartialNetworkStream::~PartialNetworkStream() { PartialNetworkStream::~PartialNetworkStream() {
if (client.isOpen()) { if (client.isOpen() && !stateIs(client, PartialCommState::COMM_FULL)) {
client.write((char*)STREAM_DELIMIT, 8); sendState(PartialCommState::COMM_FULL);
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_FULL);
} }
client.removeValue(STREAM_ATTRIB); // Cleanup client.removeValue(STREAM_ATTRIB); // Cleanup
} }
@ -518,20 +526,26 @@ namespace IO {
} }
void PartialNetworkStream::writeNonPartial(char* message, std::streamsize size) { void PartialNetworkStream::writeNonPartial(char* message, std::streamsize size) {
bool b = stateIs(client, PartialCommState::COMM_PARTIAL); bool b = stateIs(client, PartialCommState::COMM_PARTIAL);
if (b) sendState(PartialCommState::COMM_PAUSE); if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
client.write(message, size); client.write(message, size);
if (b) sendState(PartialCommState::COMM_PARTIAL); if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE));
} }
void PartialNetworkStream::flush() { void PartialNetworkStream::flush() {
check(PartialCommState::COMM_FULL); if(!check(PartialCommState::COMM_FULL)) return; // Check failed in a permissive state
if (buffer->size() == 0) return; if (buffer->size() == 0) return;
bool b = stateIs(client, PartialCommState::COMM_PARTIAL); bool b = stateIs(client, PartialCommState::COMM_PAUSE);
if (b) sendState(PartialCommState::COMM_PARTIAL); // Temporarily set the remote read state to PARTIAL if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE)); // Temporarily set the remote read state to PARTIAL
client.write(&buffer->at(0), buffer->size()); client.write(&buffer->at(0), buffer->size());
if (b) sendState(PartialCommState::COMM_PAUSE); // Set the remote read state back to PAUSE if (b) client.write((char*)&STREAM_PAUSE, sizeof(STREAM_PAUSE)); // Set the remote read state back to PAUSE
buffer->clear(); buffer->clear();
} }
void PartialNetworkStream::check(PartialCommState state) { if(readState(client, STREAM_ATTRIB)==state) throw new std::exception("Stream is not open!"); } bool PartialNetworkStream::check(PartialCommState state) {
if (readState(client, STREAM_ATTRIB) == state) {
if (permissive) return false;
throw new std::exception("Stream is not open!");
}
return true;
}
void PartialNetworkStream::sendState(PartialCommState state) { void PartialNetworkStream::sendState(PartialCommState state) {
switch (getCommState()) { switch (getCommState()) {
case PartialCommState::COMM_PAUSE: case PartialCommState::COMM_PAUSE:
@ -556,18 +570,21 @@ namespace IO {
} }
void PartialNetworkStream::endPartial() { void PartialNetworkStream::endPartial() {
flush();
sendState(PartialCommState::COMM_FULL); sendState(PartialCommState::COMM_FULL);
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_FULL);
} }
void PartialNetworkStream::startPartial() { void PartialNetworkStream::startPartial() {
sendState(PartialCommState::COMM_PARTIAL); sendState(PartialCommState::COMM_PARTIAL);
writeState(client, STREAM_ATTRIB, PartialCommState::COMM_PARTIAL);
} }
PartialCommState PartialNetworkStream::getCommState() { PartialCommState PartialNetworkStream::getCommState() {
return static_cast<PartialCommState>(readState(client, STREAM_ATTRIB)); return static_cast<PartialCommState>(readState(client, STREAM_ATTRIB));
} }
bool PartialNetworkStream::stateIs(NetClient& cli, PartialCommState state) { return readState(cli, STREAM_ATTRIB) == state; } bool PartialNetworkStream::stateIs(NetClient& cli, PartialCommState state) { return readState(cli, STREAM_ATTRIB) == state; }
PartialDataState PartialNetworkStream::accept(NetClient& cli, Packet& pkt) { PartialDataState PartialNetworkStream::accept(NetClient& cli, Packet& pkt) {
bool toggle_partial = pkt.size == sizeof(ulong_64b) && ((*(ulong_64b*)pkt.message) == STREAM_DELIMIT); bool toggle_partial = (pkt.size-1) == sizeof(STREAM_DELIMIT) && ((*(ulong_64b*)pkt.message) == STREAM_DELIMIT);
bool toggle_pause = !toggle_partial && (pkt.size == sizeof(ulong_64b) && ((*(ulong_64b*)pkt.message) == STREAM_PAUSE)); bool toggle_pause = !toggle_partial && ((pkt.size-1) == sizeof(STREAM_PAUSE) && ((*(ulong_64b*)pkt.message) == STREAM_PAUSE));
if (!toggle_partial && !toggle_pause) return PartialDataState::DATA; if (!toggle_partial && !toggle_pause) return PartialDataState::DATA;
else if (toggle_partial) { else if (toggle_partial) {
if (stateIs(cli, PartialCommState::COMM_FULL)) { if (stateIs(cli, PartialCommState::COMM_FULL)) {

View File

@ -157,16 +157,15 @@ namespace IO {
class PartialNetworkStream : public std::ostream{ class PartialNetworkStream : public std::ostream{
protected: protected:
const bool permissive;
bool open; bool open;
std::vector<char>* buffer; std::vector<char>* buffer;
NetClient& client; NetClient& client;
void check(PartialCommState state); bool check(PartialCommState state);
void sendState(PartialCommState state); void sendState(PartialCommState state);
static bool stateIs(NetClient& cli, PartialCommState state);
public: public:
PartialNetworkStream(NetClient&, bool = false); PartialNetworkStream(NetClient&, bool = false, bool = true);
~PartialNetworkStream(); ~PartialNetworkStream();
void endPartial(); void endPartial();
@ -177,6 +176,7 @@ namespace IO {
void flush(); void flush();
static PartialDataState accept(NetClient& cli, Packet& pkt); static PartialDataState accept(NetClient& cli, Packet& pkt);
static bool stateIs(NetClient& cli, PartialCommState state);
}; };
} }