iw5-mod/src/game/demonware/service_server.cpp
2018-12-27 17:28:12 +01:00

201 lines
4.4 KiB
C++

#include <std_include.hpp>
#include "module/dw.hpp"
#include "utils/cryptography.hpp"
namespace demonware
{
std::string unencrypted_reply::get_data()
{
byte_buffer result;
result.set_use_data_types(false);
result.write_int32(static_cast<int>(this->buffer_.size()) + 2);
result.write_bool(false);
result.write_byte(this->get_type());
result.write(this->buffer_);
return result.get_buffer();
}
std::string encrypted_reply::get_data()
{
byte_buffer result;
result.set_use_data_types(false);
byte_buffer enc_buffer;
enc_buffer.set_use_data_types(false);
enc_buffer.write_int32(0xDEADBEEF);
enc_buffer.write_byte(this->get_type());
enc_buffer.write(this->buffer_);
auto data = enc_buffer.get_buffer();
auto size = enc_buffer.size();
size = ~7 & (size + 7); // 8 byte align
data.resize(size);
result.write_int32(static_cast<int>(size) + 5);
result.write_byte(true);
auto seed = 0x13371337;
result.write_int32(seed);
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&seed), 4));
const std::string key(reinterpret_cast<char*>(dw::get_key(true)), 24);
result.write(utils::cryptography::des3::encrypt(data, iv, key));
return result.get_buffer();
}
service_server::service_server(std::string _name) : name_(std::move(_name))
{
this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_);
}
unsigned long service_server::get_address() const
{
return this->address_;
}
int service_server::send(const char* buf, const int len)
{
if (len <= 3) return -1;
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->incoming_queue_.push(std::string(buf, len));
return len;
}
int service_server::recv(char* buf, int len)
{
if (len > 0 && !this->outgoing_queue_.empty())
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
len = std::min(len, static_cast<int>(this->outgoing_queue_.size()));
for (auto i = 0; i < len; ++i)
{
buf[i] = this->outgoing_queue_.front();
this->outgoing_queue_.pop();
}
return len;
}
return SOCKET_ERROR;
}
void service_server::send_reply(reply* data)
{
if (!data) return;
std::lock_guard _(this->mutex_);
this->reply_sent_ = true;
const auto buffer = data->get_data();
for (auto& byte : buffer)
{
this->outgoing_queue_.push(byte);
}
}
void service_server::call_handler(const uint8_t type, const std::string& data)
{
if (this->services_.find(type) != this->services_.end())
{
this->services_[type]->call_service(this, data);
}
else
{
printf("DW: Missing handler of type %d\n", type);
}
}
void service_server::run_frame()
{
if (!this->incoming_queue_.empty())
{
std::lock_guard _(this->mutex_);
const auto packet = this->incoming_queue_.front();
this->incoming_queue_.pop();
this->parse_packet(packet);
}
}
void service_server::parse_packet(const std::string& packet)
{
byte_buffer buffer(packet);
buffer.set_use_data_types(false);
try
{
while (buffer.has_more_data())
{
int size;
buffer.read_int32(&size);
if (size <= 0)
{
const std::string zero("\x00\x00\x00\x00", 4);
raw_reply reply(zero);
this->send_reply(&reply);
return;
}
else if (size == 200) // Connection id
{
byte_buffer bbufer;
bbufer.write_uint64(0x00000000000000FD);
auto reply = this->create_message(4);
reply->send(&bbufer, false);
return;
}
if (buffer.size() < size_t(size)) return;
byte_buffer p_buffer;
p_buffer.set_use_data_types(false);
p_buffer.get_buffer().resize(size);
buffer.read(size, p_buffer.get_buffer().data());
bool enc;
p_buffer.read_bool(&enc);
if (enc)
{
int iv;
p_buffer.read_int32(&iv);
auto iv_hash = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv), 4));
const std::string key(reinterpret_cast<char*>(dw::get_key(false)), 24);
p_buffer = byte_buffer{utils::cryptography::des3::decrypt(p_buffer.get_remaining(), iv_hash, key)};
p_buffer.set_use_data_types(false);
int checksum;
p_buffer.read_int32(&checksum);
}
uint8_t type;
p_buffer.read_byte(&type);
printf("DW: Handling message of type %d (encrypted: %d)\n", type, enc);
this->reply_sent_ = false;
this->call_handler(type, p_buffer.get_remaining());
if (!this->reply_sent_ && type != 7)
{
this->create_reply(type)->send();
}
}
}
catch (...)
{
}
}
}