mirror of https://github.com/SeanOMik/libki.git
protocol: Give exceptions their own error codes
This commit is contained in:
parent
a00f9b5003
commit
6d02bfe06a
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../util/Serializable.h"
|
#include "../../util/Serializable.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../util/Serializable.h"
|
#include "../../util/Serializable.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,19 +8,57 @@ namespace protocol
|
||||||
class runtime_error : public std::runtime_error
|
class runtime_error : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
runtime_error(std::string message) : std::runtime_error(message) { }
|
explicit runtime_error(std::string message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class parse_error : public runtime_error
|
class parse_error : public runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
parse_error(std::string message) : runtime_error(message) { }
|
enum code
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
INVALID_XML_DATA,
|
||||||
|
INVALID_HEADER_DATA,
|
||||||
|
INSUFFICIENT_MESSAGE_DATA,
|
||||||
|
INVALID_MESSAGE_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit parse_error(std::string message, code error = code::NONE)
|
||||||
|
: runtime_error(message)
|
||||||
|
{
|
||||||
|
m_code = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
code get_error_code() const { return m_code; }
|
||||||
|
private:
|
||||||
|
code m_code;
|
||||||
};
|
};
|
||||||
|
|
||||||
class value_error : public runtime_error
|
class value_error : public runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
value_error(std::string message) : runtime_error(message) { }
|
enum code
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
MISSING_FILE,
|
||||||
|
OVERWRITES_LOOKUP,
|
||||||
|
EXCEEDS_LIMIT,
|
||||||
|
|
||||||
|
DML_INVALID_SERVICE,
|
||||||
|
DML_INVALID_PROTOCOL_TYPE,
|
||||||
|
DML_INVALID_MESSAGE_TYPE,
|
||||||
|
DML_INVALID_MESSAGE_NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit value_error(std::string message, code error = code::NONE)
|
||||||
|
: runtime_error(message)
|
||||||
|
{
|
||||||
|
m_code = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
code get_error_code() const { return m_code; }
|
||||||
|
private:
|
||||||
|
code m_code;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,12 @@ namespace net
|
||||||
{
|
{
|
||||||
enum class InvalidDMLMessageErrorCode
|
enum class InvalidDMLMessageErrorCode
|
||||||
{
|
{
|
||||||
|
NONE,
|
||||||
|
UNKNOWN,
|
||||||
|
INVALID_HEADER_DATA,
|
||||||
INVALID_MESSAGE_DATA,
|
INVALID_MESSAGE_DATA,
|
||||||
|
INVALID_SERVICE,
|
||||||
|
INVALID_MESSAGE_TYPE,
|
||||||
INSUFFICIENT_ACCESS
|
INSUFFICIENT_ACCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "../../util/Serializable.h"
|
#include "../../util/Serializable.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace control
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading ClientKeepAlive payload: " << e.what();
|
oss << "Error reading ClientKeepAlive payload: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_session_id = session_id->get_value();
|
m_session_id = session_id->get_value();
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace control
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading ServerKeepAlive payload: " << e.what();
|
oss << "Error reading ServerKeepAlive payload: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_timestamp = timestamp->get_value();
|
m_timestamp = timestamp->get_value();
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace control
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading SessionAccept payload: " << e.what();
|
oss << "Error reading SessionAccept payload: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_timestamp = timestamp->get_value();
|
m_timestamp = timestamp->get_value();
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace control
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading SessionOffer payload: " << e.what();
|
oss << "Error reading SessionOffer payload: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_session_id = session_id->get_value();
|
m_session_id = session_id->get_value();
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace dml
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading DML message payload: " << e.what();
|
oss << "Error reading DML message payload: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,9 +140,11 @@ namespace dml
|
||||||
{
|
{
|
||||||
// Check for mismatches between the header and template
|
// Check for mismatches between the header and template
|
||||||
if (m_header.get_service_id() != m_template->get_service_id())
|
if (m_header.get_service_id() != m_template->get_service_id())
|
||||||
throw value_error("ServiceID mismatch between MessageHeader and assigned template.");
|
throw value_error("ServiceID mismatch between MessageHeader and assigned template.",
|
||||||
|
value_error::DML_INVALID_SERVICE);
|
||||||
if (m_header.get_type() != m_template->get_type())
|
if (m_header.get_type() != m_template->get_type())
|
||||||
throw value_error("Message Type mismatch between MessageHeader and assigned template.");
|
throw value_error("Message Type mismatch between MessageHeader and assigned template.",
|
||||||
|
value_error::DML_INVALID_MESSAGE_TYPE);
|
||||||
|
|
||||||
// Read the payload into the record
|
// Read the payload into the record
|
||||||
m_record->read_from(istream);
|
m_record->read_from(istream);
|
||||||
|
@ -155,7 +157,8 @@ namespace dml
|
||||||
m_raw_data.resize(size);
|
m_raw_data.resize(size);
|
||||||
istream.read(m_raw_data.data(), size);
|
istream.read(m_raw_data.data(), size);
|
||||||
if (istream.fail())
|
if (istream.fail())
|
||||||
throw parse_error("Not enough data was available to read DML message payload.");
|
throw parse_error("Not enough data was available to read DML message payload.",
|
||||||
|
parse_error::INSUFFICIENT_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace dml
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Error reading MessageHeader: " << e.what();
|
oss << "Error reading MessageHeader: " << e.what();
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_HEADER_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_service_id = service_id->get_value();
|
m_service_id = service_id->get_value();
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace dml
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Could not open file: " << filepath;
|
oss << "Could not open file: " << filepath;
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::MISSING_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load contents into memory
|
// Load contents into memory
|
||||||
|
@ -52,7 +52,7 @@ namespace dml
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Failed to parse: " << filepath;
|
oss << "Failed to parse: " << filepath;
|
||||||
throw parse_error(oss.str());
|
throw parse_error(oss.str(), parse_error::INVALID_XML_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's safe to allocate the module we're working on now
|
// It's safe to allocate the module we're working on now
|
||||||
|
@ -118,8 +118,8 @@ namespace dml
|
||||||
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Message Module has already been loaded with Service ID ";
|
oss << "Message Module has already been loaded with Service ID ";
|
||||||
oss << message_module->get_service_id();
|
oss << (uint16_t)message_module->get_service_id();
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::OVERWRITES_LOOKUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_protocol_type_map.count(message_module->get_protocol_type()) == 1)
|
if (m_protocol_type_map.count(message_module->get_protocol_type()) == 1)
|
||||||
|
@ -130,7 +130,7 @@ namespace dml
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Message Module has already been loaded with Protocol Type ";
|
oss << "Message Module has already been loaded with Protocol Type ";
|
||||||
oss << message_module->get_protocol_type();
|
oss << message_module->get_protocol_type();
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::OVERWRITES_LOOKUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add it to our maps
|
// Add it to our maps
|
||||||
|
@ -162,8 +162,8 @@ namespace dml
|
||||||
if (!message_module)
|
if (!message_module)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No service exists with id: " << service_id;
|
oss << "No service exists with id: " << (uint16_t)service_id;
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_module->create_message(message_type);
|
return message_module->create_message(message_type);
|
||||||
|
@ -175,8 +175,8 @@ namespace dml
|
||||||
if (!message_module)
|
if (!message_module)
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No service exists with id: " << service_id;
|
oss << "No service exists with id: " << (uint16_t)service_id;
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_module->create_message(message_name);
|
return message_module->create_message(message_name);
|
||||||
|
@ -189,7 +189,7 @@ namespace dml
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No service exists with protocol type: " << protocol_type;
|
oss << "No service exists with protocol type: " << protocol_type;
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_PROTOCOL_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_module->create_message(message_type);
|
return message_module->create_message(message_type);
|
||||||
|
@ -202,7 +202,7 @@ namespace dml
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No service exists with protocol type: " << protocol_type;
|
oss << "No service exists with protocol type: " << protocol_type;
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_PROTOCOL_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_module->create_message(message_name);
|
return message_module->create_message(message_name);
|
||||||
|
@ -212,28 +212,35 @@ namespace dml
|
||||||
{
|
{
|
||||||
// Read the message header
|
// Read the message header
|
||||||
MessageHeader header;
|
MessageHeader header;
|
||||||
try
|
header.read_from(istream);
|
||||||
{
|
|
||||||
header.read_from(istream);
|
|
||||||
}
|
|
||||||
catch (parse_error &e)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the message module that uses the specified service id
|
// Get the message module that uses the specified service id
|
||||||
auto *message_module = get_module(header.get_service_id());
|
auto *message_module = get_module(header.get_service_id());
|
||||||
if (!message_module)
|
if (!message_module)
|
||||||
return nullptr;
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "No service exists with id: " << (uint16_t)header.get_service_id();
|
||||||
|
throw value_error(oss.str(), value_error::DML_INVALID_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the message template for this message type
|
// Get the message template for this message type
|
||||||
auto *message_template = message_module->get_message_template(header.get_type());
|
auto *message_template = message_module->get_message_template(header.get_type());
|
||||||
if (!message_template)
|
if (!message_template)
|
||||||
return nullptr;
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "No message exists with type: " << (uint16_t)header.get_service_id();
|
||||||
|
oss << "(service=" << message_module->get_protocol_type() << ")";
|
||||||
|
throw value_error(oss.str(), value_error::DML_INVALID_MESSAGE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that the size specified is enough to read this message
|
// Make sure that the size specified is enough to read this message
|
||||||
if (header.get_message_size() < message_template->get_record().get_size())
|
if (header.get_message_size() < message_template->get_record().get_size())
|
||||||
return nullptr;
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "No message exists with type: " << (uint16_t)header.get_service_id();
|
||||||
|
oss << "(service=" << message_module->get_protocol_type() << ")";
|
||||||
|
throw value_error(oss.str(), value_error::DML_INVALID_MESSAGE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new Message from the template
|
// Create a new Message from the template
|
||||||
auto *message = new Message(message_template);
|
auto *message = new Message(message_template);
|
||||||
|
@ -244,7 +251,7 @@ namespace dml
|
||||||
catch (ki::dml::parse_error &e)
|
catch (ki::dml::parse_error &e)
|
||||||
{
|
{
|
||||||
delete message;
|
delete message;
|
||||||
return nullptr;
|
throw parse_error("Failed to read DML message payload.", parse_error::INVALID_MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ namespace dml
|
||||||
|
|
||||||
// Make sure we haven't overflowed
|
// Make sure we haven't overflowed
|
||||||
if (message_type == 0)
|
if (message_type == 0)
|
||||||
throw value_error("Module has more than 254 messages.");
|
throw value_error("Module has more than 254 messages.", value_error::EXCEEDS_LIMIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ namespace dml
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No message exists with type: " << message_type;
|
oss << "No message exists with type: " << message_type;
|
||||||
oss << "(service=" << m_protocol_type << ")";
|
oss << "(service=" << m_protocol_type << ")";
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_MESSAGE_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_template->create_message();
|
return message_template->create_message();
|
||||||
|
@ -161,7 +161,7 @@ namespace dml
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "No message exists with name: " << message_name;
|
oss << "No message exists with name: " << message_name;
|
||||||
oss << "(service=" << m_protocol_type << ")";
|
oss << "(service=" << m_protocol_type << ")";
|
||||||
throw value_error(oss.str());
|
throw value_error(oss.str(), value_error::DML_INVALID_MESSAGE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message_template->create_message();
|
return message_template->create_message();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "ki/protocol/net/DMLSession.h"
|
#include "ki/protocol/net/DMLSession.h"
|
||||||
|
#include "ki/protocol/exception.h"
|
||||||
|
|
||||||
namespace ki
|
namespace ki
|
||||||
{
|
{
|
||||||
|
@ -22,10 +23,45 @@ namespace net
|
||||||
void DMLSession::on_application_message(const PacketHeader& header)
|
void DMLSession::on_application_message(const PacketHeader& header)
|
||||||
{
|
{
|
||||||
// Attempt to create a Message instance from the data in the stream
|
// Attempt to create a Message instance from the data in the stream
|
||||||
const auto *message = m_manager.message_from_binary(m_data_stream);
|
auto error_code = InvalidDMLMessageErrorCode::NONE;
|
||||||
|
const dml::Message *message = nullptr;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
message = m_manager.message_from_binary(m_data_stream);
|
||||||
|
}
|
||||||
|
catch (parse_error &e)
|
||||||
|
{
|
||||||
|
switch (e.get_error_code())
|
||||||
|
{
|
||||||
|
case parse_error::INVALID_HEADER_DATA:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::INVALID_HEADER_DATA;
|
||||||
|
break;
|
||||||
|
case parse_error::INSUFFICIENT_MESSAGE_DATA:
|
||||||
|
case parse_error::INVALID_MESSAGE_DATA:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::INVALID_MESSAGE_DATA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (value_error &e)
|
||||||
|
{
|
||||||
|
switch (e.get_error_code())
|
||||||
|
{
|
||||||
|
case value_error::DML_INVALID_SERVICE:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::INVALID_SERVICE;
|
||||||
|
break;
|
||||||
|
case value_error::DML_INVALID_MESSAGE_TYPE:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::INVALID_MESSAGE_TYPE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_code = InvalidDMLMessageErrorCode::UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
{
|
{
|
||||||
on_invalid_message(InvalidDMLMessageErrorCode::INVALID_MESSAGE_DATA);
|
on_invalid_message(error_code);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,13 +46,16 @@ namespace net
|
||||||
{
|
{
|
||||||
m_control = istream.get() >= 1;
|
m_control = istream.get() >= 1;
|
||||||
if (istream.fail())
|
if (istream.fail())
|
||||||
throw parse_error("Not enough data was available to read packet header. (m_control)");
|
throw parse_error("Not enough data was available to read packet header. (m_control)",
|
||||||
|
parse_error::INVALID_HEADER_DATA);
|
||||||
m_opcode = istream.get();
|
m_opcode = istream.get();
|
||||||
if (istream.fail())
|
if (istream.fail())
|
||||||
throw parse_error("Not enough data was available to read packet header. (m_opcode)");
|
throw parse_error("Not enough data was available to read packet header. (m_opcode)",
|
||||||
|
parse_error::INVALID_HEADER_DATA);
|
||||||
istream.ignore(2);
|
istream.ignore(2);
|
||||||
if (istream.eof())
|
if (istream.eof())
|
||||||
throw parse_error("Not enough data was available to read packet header. (ignored bytes)");
|
throw parse_error("Not enough data was available to read packet header. (ignored bytes)",
|
||||||
|
parse_error::INVALID_HEADER_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PacketHeader::get_size() const
|
size_t PacketHeader::get_size() const
|
||||||
|
|
Loading…
Reference in New Issue