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:
parent
43cea7b40b
commit
be17d51c3f
@ -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)) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user