toxcore/testing/hstox/binary_decode.c
iphydf d4be41a3ad
Use new encoding of Maybe in msgpack results.
The new encoding is `0` for `Nothing` and `[1, x]` for `Just x`.
2017-06-03 23:32:46 +00:00

275 lines
6.7 KiB
C

#define _BSD_SOURCE
#include "methods.h"
#include "byteswap.h"
#include "packet_kinds.h"
#include "../../toxcore/DHT.h"
static void decode_bytestring(msgpack_object_bin args, msgpack_packer *res,
int64_t min_length)
{
SUCCESS {
if (args.size < sizeof(uint64_t))
{
// Not enough space to even fit the size.
msgpack_pack_uint8(res, 0);
return;
}
uint64_t tmp;
memcpy(&tmp, args.ptr, sizeof(uint64_t));
int64_t length = be64toh(tmp);
// TODO(iphydf): Get rid of this case if/when
// https://github.com/kolmodin/binary/issues/127 is fixed. This is a
// workaround for a Haskell library bug. Our implementation here without
// the special case for negative length, and instead interpreting the
// length as unsigned integer, was correct.
if (length < 0)
{
length = 0;
}
if (args.size >= sizeof(uint64_t) && args.size == length + sizeof(uint64_t))
{
if (length < min_length) {
// CipherTexts need at least a MAC.
msgpack_pack_uint8(res, 0);
return;
}
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, 1);
msgpack_pack_bin(res, args.size - sizeof(uint64_t));
msgpack_pack_bin_body(res, args.ptr + sizeof(uint64_t), args.size - sizeof(uint64_t));
} else {
msgpack_pack_uint8(res, 0);
}
}
}
METHOD(bin, Binary_decode, CipherText)
{
decode_bytestring(args, res, CRYPTO_MAC_SIZE);
return 0;
}
METHOD(bin, Binary_decode, DhtPacket)
{
return pending;
}
METHOD(bin, Binary_decode, DhtRequestPacket)
{
return pending;
}
METHOD(bin, Binary_decode, HostAddress)
{
return pending;
}
METHOD(bin, Binary_decode, Word64)
{
return pending;
}
METHOD(bin, Binary_decode, Key_PublicKey)
{
return pending;
}
METHOD(bin, Binary_decode, KeyPair)
{
SUCCESS {
if (args.size != 64)
{
msgpack_pack_uint8(res, 0);
} else {
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, 1);
msgpack_pack_array(res, 2);
msgpack_pack_bin(res, 32);
msgpack_pack_bin_body(res, args.ptr, 32);
msgpack_pack_bin(res, 32);
msgpack_pack_bin_body(res, args.ptr + 32, 32);
}
}
return 0;
}
METHOD(bin, Binary_decode, NodeInfo)
{
uint16_t data_processed;
Node_format node;
int len = unpack_nodes(&node, 1, &data_processed, (uint8_t const *)args.ptr, args.size, 1);
bool ip6_node = node.ip_port.ip.family == AF_INET6 || node.ip_port.ip.family == TCP_INET6;
bool tcp = node.ip_port.ip.family == TCP_INET || node.ip_port.ip.family == TCP_INET6;
uint16_t port = ntohs(node.ip_port.port);
uint32_t ip4 = ntohl(node.ip_port.ip.ip4.uint32);
uint32_t ip6_0 = ntohl(node.ip_port.ip.ip6.uint32[0]);
uint32_t ip6_1 = ntohl(node.ip_port.ip.ip6.uint32[1]);
uint32_t ip6_2 = ntohl(node.ip_port.ip.ip6.uint32[2]);
uint32_t ip6_3 = ntohl(node.ip_port.ip.ip6.uint32[3]);
SUCCESS {
if (len > 0 && data_processed > 0 && data_processed == args.size)
{
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, 1);
msgpack_pack_array(res, 3);
msgpack_pack_uint8(res, tcp);
msgpack_pack_array(res, 2);
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, ip6_node);
if (ip6_node) {
msgpack_pack_array(res, 4);
msgpack_pack_uint32(res, ip6_0);
msgpack_pack_uint32(res, ip6_1);
msgpack_pack_uint32(res, ip6_2);
msgpack_pack_uint32(res, ip6_3);
} else {
msgpack_pack_uint32(res, ip4);
}
msgpack_pack_uint16(res, port);
msgpack_pack_bin(res, CRYPTO_PUBLIC_KEY_SIZE);
msgpack_pack_bin_body(res, &node.public_key, CRYPTO_PUBLIC_KEY_SIZE);
} else {
msgpack_pack_uint8(res, 0);
}
}
return 0;
}
METHOD(bin, Binary_decode, NodesRequest)
{
return pending;
}
METHOD(bin, Binary_decode, NodesResponse)
{
return pending;
}
METHOD(bin, Binary_decode, Packet_Word64)
{
return pending;
}
METHOD(bin, Binary_decode, PacketKind)
{
SUCCESS {
if (args.size != 1)
{
msgpack_pack_uint8(res, 0);
} else {
uint8_t kind = args.ptr[0];
size_t i;
for (i = 0; i < sizeof packet_kinds / sizeof *packet_kinds; i++)
{
if (packet_kinds[i] == kind) {
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, 1);
msgpack_pack_fix_uint8(res, i);
return 0;
}
}
// Packet kind not found => error.
msgpack_pack_uint8(res, 0);
}
}
return 0;
}
METHOD(bin, Binary_decode, PingPacket)
{
return pending;
}
METHOD(bin, Binary_decode, PlainText)
{
decode_bytestring(args, res, 0);
return 0;
}
METHOD(bin, Binary_decode, PortNumber)
{
SUCCESS {
if (args.size == 2)
{
uint16_t tmp;
memcpy(&tmp, args.ptr, 2);
uint16_t port = ntohs(tmp);
msgpack_pack_array(res, 2);
msgpack_pack_uint8(res, 1);
msgpack_pack_uint16(res, port);
} else {
msgpack_pack_uint8(res, 0);
}
}
return 0;
}
METHOD(bin, Binary_decode, RpcPacket_Word64)
{
return pending;
}
METHOD(bin, Binary_decode, SocketAddress)
{
return pending;
}
METHOD(bin, Binary_decode, TransportProtocol)
{
return pending;
}
METHOD(array, Binary, decode)
{
CHECK_SIZE(args, 2);
CHECK_TYPE(args.ptr[0], MSGPACK_OBJECT_STR);
CHECK_TYPE(args.ptr[1], MSGPACK_OBJECT_BIN);
msgpack_object_str type = args.ptr[0].via.str;
#define DISPATCH(TYPE) \
if (type.size == sizeof #TYPE - 1 && method_cmp(type.ptr, #TYPE, type.size) == 0) \
return Binary_decode_##TYPE(args.ptr[1].via.bin, res)
DISPATCH(CipherText);
DISPATCH(DhtPacket);
DISPATCH(DhtRequestPacket);
DISPATCH(HostAddress);
DISPATCH(Word64);
DISPATCH(Key_PublicKey);
DISPATCH(KeyPair);
DISPATCH(NodeInfo);
DISPATCH(NodesRequest);
DISPATCH(NodesResponse);
DISPATCH(Packet_Word64);
DISPATCH(PacketKind);
DISPATCH(PingPacket);
DISPATCH(PlainText);
DISPATCH(PortNumber);
DISPATCH(RpcPacket_Word64);
DISPATCH(SocketAddress);
DISPATCH(TransportProtocol);
#undef DISPATCH
return unimplemented;
}