Commit df5d3811 authored by Jan Včelák's avatar Jan Včelák 🚀

Improve endianess handling in wire, fix comments and tests

refs #1558
parent 9b14a150
......@@ -49,6 +49,7 @@ src/libknot/util/utils.h
src/libknot/util/utils.c
src/libknot/util/descriptor.h
src/libknot/util/descriptor.c
src/libknot/util/endian.h
src/libknot/zone/zonedb.h
src/libknot/zone/zonedb.c
src/libknot/zone/node.h
......@@ -225,6 +226,8 @@ src/tests/libknot/libknot/query_tests.c
src/tests/libknot/libknot/query_tests.h
src/tests/libknot/libknot/nsec3_tests.c
src/tests/libknot/libknot/nsec3_tests.h
src/tests/libknot/wire_tests.c
src/tests/libknot/wire_tests.h
src/tests/libknot/realdata/unittests_libknot_realdata.c
src/tests/libknot/realdata/libknot/packet_tests_realdata.c
src/tests/libknot/realdata/libknot/packet_tests_realdata.h
......
......@@ -172,6 +172,7 @@ libknot_la_SOURCES = \
libknot/util/tolower.c \
libknot/util/descriptor.h \
libknot/util/wire.h \
libknot/util/endian.h \
libknot/packet/query.c \
libknot/packet/response.c \
libknot/packet/packet.c \
......
/* Copyright (C) 2013 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _KNOT_ENDIAN_H
#define _KNOT_ENDIAN_H
#if defined(__linux__)
# include <endian.h>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
#endif
#endif /* _KNOT_ENDIAN_H_ */
......@@ -27,10 +27,10 @@
#ifndef _KNOT_UTILS_H_
#define _KNOT_UTILS_H_
#include "util/endian.h"
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <arpa/inet.h>
/*!
* \brief A general purpose lookup table.
......@@ -90,11 +90,11 @@ size_t knot_strlcpy(char *dst, const char *src, size_t size);
*
* \param pos Data to read the 2 bytes from.
*
* \return The 2 bytes read, in inverse endian.
* \return The 2 bytes read, in host byte order.
*/
static inline uint16_t knot_wire_read_u16(const uint8_t *pos)
{
return ntohs(*(uint16_t *)pos);
return be16toh(*(uint16_t *)pos);
}
/*!
......@@ -102,11 +102,11 @@ static inline uint16_t knot_wire_read_u16(const uint8_t *pos)
*
* \param pos Data to read the 4 bytes from.
*
* \return The 4 bytes read, in inverse endian.
* \return The 4 bytes read, in host byte order.
*/
static inline uint32_t knot_wire_read_u32(const uint8_t *pos)
{
return ntohl(*(uint32_t *)pos);
return be32toh(*(uint32_t *)pos);
}
/*!
......@@ -114,69 +114,97 @@ static inline uint32_t knot_wire_read_u32(const uint8_t *pos)
*
* \param pos Data to read the 6 bytes from.
*
* \return The 6 bytes read, in inverse endian.
* \return The 6 bytes read, in host byte order.
*/
static inline uint64_t knot_wire_read_u48(const uint8_t *pos)
{
uint64_t input = 0;
uint64_t swapped;
memcpy((void *)&input, (void *)pos, 6);
swapped = be64toh(input);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return ((uint64_t)ntohl(*(uint32_t *)pos)) << 16 |
((uint64_t)ntohs(*(uint16_t *)(pos + 4)));
return swapped >> 16;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return ((uint64_t)(*(uint32_t *)pos)) |
((uint64_t)(*(uint16_t *)(pos + 4))) << 32;
return swapped;
#else
#error Unsupported byte order.
#endif
}
/*!
* \brief Read 8 bytes from the wireformat data.
*
* \param pos Data to read the 8 bytes from.
*
* \return The 8 bytes read, in host byte order.
*/
static inline uint64_t knot_wire_read_u64(const uint8_t *pos)
{
return be64toh(*(uint64_t *)pos);
}
/*!
* \brief Writes 2 bytes in wireformat.
*
* The endian of the data is inverted.
* The data are stored in network byte order (big endian).
*
* \param pos Position where to put the 2 bytes.
* \param data Data to put.
*/
static inline void knot_wire_write_u16(uint8_t *pos, uint16_t data)
{
*(uint16_t *)pos = htons(data);
*(uint16_t *)pos = htobe16(data);
}
/*!
* \brief Writes 4 bytes in wireformat.
*
* The endian of the data is inverted.
* The data are stored in network byte order (big endian).
*
* \param pos Position where to put the 4 bytes.
* \param data Data to put.
*/
static inline void knot_wire_write_u32(uint8_t *pos, uint32_t data)
{
*(uint32_t *)pos = htonl(data);
*(uint32_t *)pos = htobe32(data);
}
/*!
* \brief Writes 6 bytes in wireformat.
*
* The endian of the data is inverted.
* The data are stored in network byte order (big endian).
*
* \param pos Position where to put the 4 bytes.
* \param data Data to put.
*/
static inline void knot_wire_write_u48(uint8_t *pos, uint64_t data)
{
uint8_t *dataptr = (void *)&data;
uint64_t swapped = htobe64(data);
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
*(uint32_t *)(pos + 2) = htonl(*(uint32_t *)dataptr);
*(uint16_t *)pos = htons(*(uint16_t *)(dataptr + 4));
memcpy((void *)pos, ((void *)&swapped) + 2, 6);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
*(uint32_t *)pos = *(uint32_t *)dataptr;
*(uint16_t *)(pos + 4) = *(uint16_t *)(dataptr + 4);
memcpy((void *)pos, (void *)&swapped, 6);
#else
#error Unsupported byte order.
#endif
}
/*!
* \brief Writes 8 bytes in wireformat.
*
* The data are stored in network byte order (big endian).
*
* \param pos Position where to put the 8 bytes.
* \param data Data to put.
*/
static inline void knot_wire_write_u64(uint8_t *pos, uint64_t data)
{
*(uint64_t *)pos = htobe64(data);
}
/*!
* \brief Linear congruential generator.
*
......
......@@ -28,13 +28,15 @@ unit_api wire_tests_api = {
static int wire_tests_count(int argc, char *argv[])
{
return 6;
return 8;
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define ENDIAN_MATCH(expression, match_little, match_big) ((expression) == (match_little))
#define ENDIAN_MATCH(expression, match_little, match_big) \
((expression) == (match_little))
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define ENDIAN_MATCH(expression, match_little, match_big) ((expression) == (match_big))
#define ENDIAN_MATCH(expression, match_little, match_big) \
((expression) == (match_big))
#else
#error Unsupported byte order.
#endif
......@@ -44,7 +46,8 @@ static int wire_tests_run(int argc, char *argv[])
// 1. - 16-bit read
{
uint16_t data = 0xAABB;
ok(ENDIAN_MATCH(knot_wire_read_u16((uint8_t *)&data), 0xBBAA, 0xAABB), "16-bit read");
ok(ENDIAN_MATCH(knot_wire_read_u16((uint8_t *)&data),
0xBBAA, 0xAABB), "16-bit read");
}
// 2. - 16-bit read
......@@ -52,13 +55,15 @@ static int wire_tests_run(int argc, char *argv[])
uint16_t data_in = 0xAABB;
uint64_t data_out = 0xFF0000;
knot_wire_write_u16((uint8_t *)&data_out, data_in);
ok(ENDIAN_MATCH(data_out, 0xFFBBAA, 0xFFAABB), "16-bit write");
ok(ENDIAN_MATCH(data_out,
0xFFBBAA, 0xFFAABB), "16-bit write");
}
// 3. - 32-bit read
{
uint32_t data = 0xAABBCCDD;
ok(ENDIAN_MATCH(knot_wire_read_u32((uint8_t *)&data), 0xDDCCBBAA, 0xAABBCCDD), "32-bit read");
ok(ENDIAN_MATCH(knot_wire_read_u32((uint8_t *)&data),
0xDDCCBBAA, 0xAABBCCDD), "32-bit read");
}
// 4. - 32-bit write
......@@ -66,22 +71,41 @@ static int wire_tests_run(int argc, char *argv[])
uint32_t data_in = 0xAABBCCDD;
uint64_t data_out = 0xFF00000000;
knot_wire_write_u32((uint8_t *)&data_out, data_in);
ok(ENDIAN_MATCH(data_out, 0xFFDDCCBBAA, 0xFFAABBCCDD), "32-bit write");
ok(ENDIAN_MATCH(data_out,
0xFFDDCCBBAA, 0xFFAABBCCDD), "32-bit write");
}
// 5. - 48-bit read
{
uint64_t data = 0xAABBCCDDEEFF;
ok(ENDIAN_MATCH(knot_wire_read_u48((uint8_t *)&data), 0xFFEEDDCCBBAA, 0xAABBCCDDEEFF), "48-bit read");
uint64_t data = 0x81AABBCCDDEEFF;
ok(ENDIAN_MATCH(knot_wire_read_u48((uint8_t *)&data),
0xFFEEDDCCBBAA, 0xAABBCCDDEEFF), "48-bit read");
}
// 6. - 48-bit write
{
uint64_t data_in = 0xAABBCCDDEEFF;
uint64_t data_in = 0x81AABBCCDDEEFF;
uint64_t data_out = 0xDD000000000000;
knot_wire_write_u48((uint8_t *)&data_out, data_in);
ok(ENDIAN_MATCH(data_out, 0xDDFFEEDDCCBBAA, 0xDDAABBCCDDEEFF), "48-bit write");
ok(ENDIAN_MATCH(data_out,
0xDDFFEEDDCCBBAA, 0xDDAABBCCDDEEFF), "48-bit write");
}
// 7. - 64-bit read
{
uint64_t data = 0x8899AABBCCDDEEFF;
ok(ENDIAN_MATCH(knot_wire_read_u64((uint8_t *)&data),
0xFFEEDDCCBBAA9988, 0x8899AABBCCDDEEFF), "64-bit read");
}
// 8. - 64-bit write
{
uint64_t data_in = 0x8899AABBCCDDEEFF;
uint64_t data_out = 0x0;
knot_wire_write_u64((uint8_t *)&data_out, data_in);
ok(ENDIAN_MATCH(data_out,
0xFFEEDDCCBBAA9988, 0x8899AABBCCDDEEFF), "64-bit write");
}
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment