# HG changeset patch # User Mike Becker # Date 1787477907 -7200 # Node ID 39aa77b7188b4414d39fe53e0d662e9c00bf8963 # Parent 04c65336777f06b871447d354b1ce5e052ee54d2 fix missing byte-order conversion in ntoh_move() and change protocol byte order to little-endian relates to #976 diff -r 04c65336777f -r 39aa77b7188b PROTOCOL.md --- a/PROTOCOL.md Sat Aug 22 16:22:05 2026 +0200 +++ b/PROTOCOL.md Sun Aug 23 11:38:27 2026 +0200 @@ -29,8 +29,8 @@ The datatypes used in the message payloads are as follows: * BYTE — a single byte -* WORD — two bytes integer (big-endian) -* DWORD — four bytes integer (big-endian) +* WORD — two bytes integer (little-endian) +* DWORD — four bytes integer (little-endian) * MOVE — a data structure describing a move, consisting of * a DWORD for the elapsed move time in seconds * a DWORD for additional elapsed move time in microseconds @@ -41,6 +41,10 @@ * a BYTE index for the row the piece was moved to * a BYTE describing the selected piece for promotion (otherwise zero) +Note carefully that the byte order used by this protocol is little-endian while +the standard network byte order would be big-endian. But since the vast majority +of processors use little-endian nowadays, this protocol uses little-endian, too. + The following table shows the possible values for the BYTEs describing a piece. | Piece | Value (Hex) | diff -r 04c65336777f -r 39aa77b7188b src/main.c --- a/src/main.c Sat Aug 22 16:22:05 2026 +0200 +++ b/src/main.c Sun Aug 23 11:38:27 2026 +0200 @@ -498,8 +498,8 @@ static NetMove hton_move(const Move *move) { return (NetMove) { - .mtime_sec = htonl(move->movetime / 1000000ull), - .mtime_usec = htonl(move->movetime % 1000000ull), + .mtime_sec = net_htonl(move->movetime / 1000000ull), + .mtime_usec = net_htonl(move->movetime % 1000000ull), .piece = move->piece, .fromfile = move->fromfile, .fromrow = move->fromrow, .tofile = move->tofile, .torow = move->torow, @@ -511,7 +511,8 @@ return (Move) { .string = {0}, /* calculated before applying the move */ .timestamp = {0}, /* planned to be removed */ - .movetime = (uint64_t)move->mtime_sec * 1000000ull + move->mtime_usec, + .movetime = (uint64_t)net_ntohl(move->mtime_sec) + * 1000000ull + net_ntohl(move->mtime_usec), .piece = move->piece, .fromfile = move->fromfile, .fromrow = move->fromrow, .tofile = move->tofile, .torow = move->torow, @@ -646,7 +647,7 @@ if (code == NETCODE_DECLINE_MOVE) { uint32_t reason; net_recieve_data(opponent, &reason, sizeof(uint32_t)); - reason = ntohl(reason); + reason = net_ntohl(reason); eval_move_failed_msg(reason); } else if (code == NETCODE_ACCEPT || code == NETCODE_CHECK @@ -831,7 +832,7 @@ return 0; } } else { - uint32_t reason = htonl(code); + uint32_t reason = net_htonl(code); net_send_data(opponent, NETCODE_DECLINE_MOVE, &reason, sizeof(uint32_t)); } @@ -1081,7 +1082,7 @@ char *pgndata = malloc(pgndata_size); memcpy(pgndata, &(gamestate->info), sizeof(GameInfo)); unsigned offset = sizeof(GameInfo); - uint16_t mcn = htons(mc); + uint16_t mcn = net_htons(mc); memcpy(pgndata+offset, &mcn, 2); offset += 2; for (unsigned i = 0 ; i < mc ; i++) { @@ -1183,7 +1184,7 @@ net_recieve_data(server.fd, &(gamestate->info), sizeof(GameInfo)); uint16_t mc; net_recieve_data(server.fd, &mc, sizeof(mc)); - mc = ntohs(mc); + mc = net_ntohs(mc); char *movedata = malloc(mc * NETMOVE_LEN); net_recieve_data(server.fd, movedata, mc*NETMOVE_LEN); unsigned offset = 0; diff -r 04c65336777f -r 39aa77b7188b src/network.c --- a/src/network.c Sat Aug 22 16:22:05 2026 +0200 +++ b/src/network.c Sun Aug 23 11:38:27 2026 +0200 @@ -33,6 +33,7 @@ #include #include #include +#include #include "network.h" int net_create_tcp(Server *server, short port) { diff -r 04c65336777f -r 39aa77b7188b src/network.h --- a/src/network.h Sat Aug 22 16:22:05 2026 +0200 +++ b/src/network.h Sun Aug 23 11:38:27 2026 +0200 @@ -31,7 +31,7 @@ #define TCHESS_NETWORK_H #include -#include +#include #ifdef __cplusplus extern "C" { @@ -99,6 +99,54 @@ uint8_t net_recieve_code_async(int socket); void net_recieve_data(int socket, void *data, size_t len); + +/* Functions that convert WORD and DWORD values to terminal-chess + * network protocol byte order. + * + * Note: due to the vast majority of processors using little-endian, + * the network byte order of terminal-chess is little-endian, too. + * While the standard network byte order is big-endian for historic reasons. + */ + +static inline uint16_t net_htons(uint16_t s) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return s; +#else +#if !defined(__BYTE_ORDER__) + const uint16_t endian_test = 1; + if (*(const uint8_t *)&endian_test) { + return s; + } +#endif + return (uint16_t)((s >> 8) | (s << 8)); +#endif +} + +static inline uint16_t net_ntohs(uint16_t s) { + return net_htons(s); +} + +static inline uint32_t net_ntohl(uint32_t l) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return l; +#else +#if !defined(__BYTE_ORDER__) + const uint16_t endian_test = 1; + if (*(const uint8_t *)&endian_test) { + return l; + } +#endif + return ((l & 0x000000FFu) << 24) + | ((l & 0x0000FF00u) << 8) + | ((l & 0x00FF0000u) >> 8) + | ((l & 0xFF000000u) >> 24); +#endif +} + +static inline uint32_t net_htonl(uint32_t l) { + return net_ntohl(l); +} + #ifdef __cplusplus } #endif