noinst_LIBRARIES = libMultiPlayer.a
-libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx
+libMultiPlayer_a_SOURCES = multiplayrxmgr.cxx multiplayrxmgr.hxx multiplaytxmgr.cxx multiplaytxmgr.hxx mpplayer.cxx mpplayer.hxx mpmessages.hxx tiny_xdr.cpp tiny_xdr.hpp
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
******************************************************************/
#include <simgear/compiler.h>
-
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
+#include "tiny_xdr.hpp"
#include <plib/sg.h>
-// Message identifiers
-#define CHAT_MSG_ID 1
-#define UNUSABLE_POS_DATA_ID 2
-#define POS_DATA_ID 3
-/* should be a multiple of 8! */
-#define MAX_CALLSIGN_LEN 8
-/** Header for use with all messages sent */
-typedef struct {
-
- /** Message identifier, multiple of 8! */
- uint32_t MsgId;
-
- /** Length of the message inclusive of this header */
- uint32_t iMsgLen;
-
- /** IP address for reply to message (player's receiver address) */
- uint32_t lReplyAddress;
-
- /** Port for replies (player's receiver port) */
- uint32_t iReplyPort;
-
- /** Callsign used by the player */
- char sCallsign[MAX_CALLSIGN_LEN];
+// magic value for messages
+const uint32_t MSG_MAGIC = 0x46474653; // "FGFS"
+// protocoll version
+const uint32_t PROTO_VER = 0x00010001; // 1.1
-} T_MsgHdr;
-
-#define MAX_CHAT_MSG_LEN 48
-/** Chat message */
-typedef struct {
-
- /** Text of chat message */
- char sText[MAX_CHAT_MSG_LEN];
+// Message identifiers
+#define CHAT_MSG_ID 1
+#define UNUSABLE_POS_DATA_ID 2
+#define POS_DATA_ID 3
-} T_ChatMsg;
+// XDR demands 4 byte alignment, but some compilers use8 byte alignment
+// so it's safe to let the overall size of a netmork message be a
+// multiple of 8!
+#define MAX_CALLSIGN_LEN 8
+#define MAX_CHAT_MSG_LEN 48
+#define MAX_MODEL_NAME_LEN 48
-/* should be a multiple of 8! */
-#define MAX_MODEL_NAME_LEN 48
/** Aircraft position message */
-typedef struct {
-
- /** Name of the aircraft model */
- char sModel[MAX_MODEL_NAME_LEN];
-
- /** Position data for the aircraft */
- sgdVec3 PlayerPosition;
- sgQuat PlayerOrientation;
-
-} T_PositionMsg;
-
+typedef xdr_data2_t xdrPosition[3];
+typedef xdr_data_t xdrOrientation[4];
+
+// Header for use with all messages sent
+class T_MsgHdr {
+public:
+ xdr_data_t Magic; // Magic Value
+ xdr_data_t Version; // Protocoll version
+ xdr_data_t MsgId; // Message identifier
+ xdr_data_t iMsgLen; // absolue length of message
+ xdr_data_t lReplyAddress; // (player's receiver address
+ xdr_data_t iReplyPort; // player's receiver port
+ char sCallsign[MAX_CALLSIGN_LEN]; // Callsign used by the player
+};
+
+// Chat message
+class T_ChatMsg {
+public:
+ char sText[MAX_CHAT_MSG_LEN]; // Text of chat message
+};
+
+// Position message
+class T_PositionMsg {
+public:
+ char sModel[MAX_MODEL_NAME_LEN]; // Name of the aircraft model
+ xdrPosition PlayerPosition; // players position
+ xdrOrientation PlayerOrientation; // players orientation
+};
#endif
m_sCallsign = sCallsign;
m_sModelName = sModelName;
m_bLocalPlayer = bLocalPlayer;
+ SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_sCallsign
+ << " using '" << m_sModelName << "'" );
// If the player is remote then load the model
if (!bLocalPlayer) {
void MPPlayer::SetPosition(const sgQuat PlayerOrientation,
const sgdVec3 PlayerPosition) {
-
// Save the position matrix and update time
if (m_bInitialised) {
sgdCopyVec3(m_ModelPosition, PlayerPosition);
m_bUpdated = true;
}
-
}
strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
+ /*
sgdCopyVec3(PosMsg->PlayerPosition, m_ModelPosition);
sgCopyQuat(PosMsg->PlayerOrientation, m_ModelOrientation);
-
-
+ */
+ PosMsg->PlayerPosition[0] = XDR_encode_double (m_ModelPosition[0]);
+ PosMsg->PlayerPosition[1] = XDR_encode_double (m_ModelPosition[1]);
+ PosMsg->PlayerPosition[2] = XDR_encode_double (m_ModelPosition[2]);
+ PosMsg->PlayerOrientation[0] = XDR_encode_float (m_ModelOrientation[0]);
+ PosMsg->PlayerOrientation[1] = XDR_encode_float (m_ModelOrientation[1]);
+ PosMsg->PlayerOrientation[2] = XDR_encode_float (m_ModelOrientation[2]);
+ PosMsg->PlayerOrientation[3] = XDR_encode_float (m_ModelOrientation[3]);
}
******************************************************************/
void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
- struct in_addr address;
-
- MsgHdr->MsgId = iMsgId;
+ struct in_addr address;
+ uint32_t len;
switch (iMsgId) {
case CHAT_MSG_ID:
- MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
+ len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
break;
case POS_DATA_ID:
- MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
+ len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
break;
default:
- MsgHdr->iMsgLen = sizeof(T_MsgHdr);
+ len = sizeof(T_MsgHdr);
break;
}
-
- address.s_addr = inet_addr( m_PlayerAddress.getHost() );
- MsgHdr->lReplyAddress = address.s_addr;
-
- MsgHdr->iReplyPort = m_PlayerAddress.getPort();
+ MsgHdr->Magic = XDR_encode_uint32 (MSG_MAGIC);
+ MsgHdr->Version = XDR_encode_uint32 (PROTO_VER);
+ MsgHdr->MsgId = XDR_encode_uint32 (iMsgId);
+ MsgHdr->iMsgLen = XDR_encode_uint32 (len);
+ // inet_addr returns address in network byte order
+ // no need to encode it
+ MsgHdr->lReplyAddress = inet_addr( m_PlayerAddress.getHost() );
+ MsgHdr->iReplyPort = XDR_encode_uint32 (m_PlayerAddress.getPort());
strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
-
}
#endif // FG_MPLAYER_AS
char sMsg[MAX_PACKET_SIZE]; // Buffer for received message
int iBytes; // Bytes received
T_MsgHdr *MsgHdr; // Pointer to header in received data
- T_ChatMsg *ChatMsg; // Pointer to chat message in received data
+
+
+ if (! m_bInitialised) {
+ return;
+ }
+
+ // Read the receive socket and process any data
+ do {
+
+ // Although the recv call asks for MAX_PACKET_SIZE of data,
+ // the number of bytes returned will only be that of the next
+ // packet waiting to be processed.
+ iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
+
+ // no Data received
+ if (iBytes <= 0) {
+ if (errno != EAGAIN) {
+ perror("FGMultiplayRxMgr::MP_ProcessData");
+ }
+ return;
+ }
+ if (iBytes <= (int)sizeof(MsgHdr)) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - received message with insufficient data" );
+ return;
+ }
+ // Read header
+ MsgHdr = (T_MsgHdr *)sMsg;
+ MsgHdr->Magic = XDR_decode_uint32 (MsgHdr->Magic);
+ MsgHdr->Version = XDR_decode_uint32 (MsgHdr->Version);
+ MsgHdr->MsgId = XDR_decode_uint32 (MsgHdr->MsgId);
+ MsgHdr->iMsgLen = XDR_decode_uint32 (MsgHdr->iMsgLen);
+ MsgHdr->iReplyPort = XDR_decode_uint32 (MsgHdr->iReplyPort);
+ if (MsgHdr->Magic != MSG_MAGIC) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - message has invalid magic number!" );
+ }
+ if (MsgHdr->Version != PROTO_VER) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - message has invalid protocoll number!" );
+ }
+
+ // Process the player data unless we generated it
+ if (m_sCallsign == MsgHdr->sCallsign) {
+ return;
+ }
+
+ // Process messages
+ switch(MsgHdr->MsgId) {
+ case CHAT_MSG_ID:
+ ProcessChatMsg ((char*) & sMsg);
+ break;
+
+ case POS_DATA_ID:
+ ProcessPosMsg ((char*) & sMsg);
+ break;
+
+ default:
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - Unknown message Id received: "
+ << MsgHdr->MsgId );
+ break;
+ } // switch
+ } while (iBytes > 0);
+
+}
+
+void FGMultiplayRxMgr::ProcessPosMsg ( const char *Msg ) {
+
T_PositionMsg *PosMsg; // Pointer to position message in received data
- char *sIpAddress; // Address information from header
- char *sModelName; // Model that the remote player is using
- char *sCallsign; // Callsign of the remote player
- struct in_addr PlayerAddress; // Used for converting the player's address into dot notation
+ T_MsgHdr *MsgHdr; // Pointer to header in received data
int iPlayerCnt; // Count of players in player array
bool bActivePlayer = false; // The state of the player that sent the data
- int iPort; // Port that the remote player receives on
-
-
- if (m_bInitialised) {
-
- // Read the receive socket and process any data
- do {
-
- // Although the recv call asks for MAX_PACKET_SIZE of data,
- // the number of bytes returned will only be that of the next
- // packet waiting to be processed.
- iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
-
- // Data received
- if (iBytes > 0) {
- if (iBytes >= (int)sizeof(MsgHdr)) {
-
- // Read header
- MsgHdr = (T_MsgHdr *)sMsg;
- PlayerAddress.s_addr = MsgHdr->lReplyAddress;
- sIpAddress = inet_ntoa(PlayerAddress);
- iPort = MsgHdr->iReplyPort;
- sCallsign = MsgHdr->sCallsign;
-
- // Process the player data unless we generated it
- if (m_sCallsign != MsgHdr->sCallsign) {
-
-
- // Process messages
- switch(MsgHdr->MsgId) {
- case CHAT_MSG_ID:
- if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_ChatMsg)) {
- ChatMsg = (T_ChatMsg *)(sMsg + sizeof(T_MsgHdr));
- SG_LOG( SG_NETWORK, SG_BULK, "Chat [" << MsgHdr->sCallsign << "]" << " " << ChatMsg->sText );
- } else {
- SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Chat message received with insufficient data" );
- }
- break;
-
- case POS_DATA_ID:
- if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
- PosMsg = (T_PositionMsg *)(sMsg + sizeof(T_MsgHdr));
- sModelName = PosMsg->sModel;
-
- // Check if the player is already in the game by using the Callsign.
- bActivePlayer = false;
- for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
- if (m_Player[iPlayerCnt] != NULL) {
- if (m_Player[iPlayerCnt]->CompareCallsign(MsgHdr->sCallsign)) {
-
- // Player found. Update the data for the player.
- m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerOrientation, PosMsg->PlayerPosition);
- bActivePlayer = true;
-
- }
- }
- }
-
- // Player not active, so add as new player
- if (!bActivePlayer) {
- iPlayerCnt = 0;
- do {
- if (m_Player[iPlayerCnt] == NULL) {
- SG_LOG( SG_NETWORK, SG_INFO, "FGMultiplayRxMgr::ProcessRxData - Add new player. IP: " << sIpAddress << ", Call: " << sCallsign << ", model: " << sModelName );
- m_Player[iPlayerCnt] = new MPPlayer;
- m_Player[iPlayerCnt]->Open(sIpAddress, iPort, sCallsign, sModelName, false);
- m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerOrientation, PosMsg->PlayerPosition);
- bActivePlayer = true;
- }
- iPlayerCnt++;
- } while (iPlayerCnt < MAX_PLAYERS && !bActivePlayer);
-
- // Check if the player was added
- if (!bActivePlayer) {
- if (iPlayerCnt == MAX_PLAYERS) {
- SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Unable to add new player (" << sCallsign << "). Too many players." );
- }
- }
- }
-
- } else {
- SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Position message received with insufficient data" );
- }
- break;
-
- default:
- SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayRxMgr::MP_ProcessData - Unknown message Id received: " << MsgHdr->MsgId );
- break;
-
-
- }
- }
- }
-
-
- // Error or no data
- } else if (iBytes == -1) {
- if (errno != EAGAIN) {
- perror("FGMultiplayRxMgr::MP_ProcessData");
- }
- }
+ sgQuat Orientation;
+ sgdVec3 Position;
+ char *sIpAddress; // Address information from header
+ struct in_addr PlayerAddress; // Used for converting the player's address into dot notation
+
+ MsgHdr = (T_MsgHdr *)Msg;
+ if (MsgHdr->iMsgLen != sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - Position message received with insufficient data" );
+ return;
+ }
- } while (iBytes > 0);
+ PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
+ Position[0] = XDR_decode_double (PosMsg->PlayerPosition[0]);
+ Position[1] = XDR_decode_double (PosMsg->PlayerPosition[1]);
+ Position[2] = XDR_decode_double (PosMsg->PlayerPosition[2]);
+ Orientation[0] = XDR_decode_float (PosMsg->PlayerOrientation[0]);
+ Orientation[1] = XDR_decode_float (PosMsg->PlayerOrientation[1]);
+ Orientation[2] = XDR_decode_float (PosMsg->PlayerOrientation[2]);
+ Orientation[3] = XDR_decode_float (PosMsg->PlayerOrientation[3]);
+ // Check if the player is already in the game by using the Callsign.
+ for (iPlayerCnt = 0; iPlayerCnt < MAX_PLAYERS; iPlayerCnt++) {
+ if (m_Player[iPlayerCnt] != NULL) {
+ if (m_Player[iPlayerCnt]->CompareCallsign(MsgHdr->sCallsign)) {
+ // Player found. Update the data for the player.
+ m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
+ bActivePlayer = true;
+ }
+ }
}
+ if (bActivePlayer) {
+ // nothing more to do
+ return;
+ }
+ // Player not active, so add as new player
+ iPlayerCnt = 0;
+ do {
+ if (m_Player[iPlayerCnt] == NULL) {
+ PlayerAddress.s_addr = MsgHdr->lReplyAddress; // which is unecoded
+ sIpAddress = inet_ntoa(PlayerAddress);
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::ProcessRxData - Add new player. IP: " << sIpAddress
+ << ", Call: " << MsgHdr->sCallsign
+ << ", model: " << PosMsg->sModel);
+ m_Player[iPlayerCnt] = new MPPlayer;
+ m_Player[iPlayerCnt]->Open(sIpAddress, MsgHdr->iReplyPort,
+ MsgHdr->sCallsign, PosMsg->sModel, false);
+ m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
+ bActivePlayer = true;
+ }
+ iPlayerCnt++;
+ } while (iPlayerCnt < MAX_PLAYERS && !bActivePlayer);
+
+ // Check if the player was added
+ if (!bActivePlayer) {
+ if (iPlayerCnt == MAX_PLAYERS) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - Unable to add new player ("
+ << MsgHdr->sCallsign
+ << "). Too many players." );
+ }
+ }
}
+void FGMultiplayRxMgr::ProcessChatMsg ( const char *Msg ) {
+
+ T_ChatMsg *ChatMsg; // Pointer to chat message in received data
+ T_MsgHdr *MsgHdr; // Pointer to header in received data
+
+ MsgHdr = (T_MsgHdr *)Msg;
+ if (MsgHdr->iMsgLen != sizeof(T_MsgHdr) + sizeof(T_ChatMsg)) {
+ SG_LOG( SG_NETWORK, SG_ALERT,
+ "FGMultiplayRxMgr::MP_ProcessData - Chat message received with insufficient data" );
+ return;
+ }
+
+ ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
+ SG_LOG( SG_NETWORK, SG_BULK, "Chat [" << MsgHdr->sCallsign << "]" << " " << ChatMsg->sText );
+}
/******************************************************************
* Name: Update
#include "mpplayer.hxx"
#include "mpmessages.hxx"
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include STL_STRING
SG_USING_STD(string);
/** Initiates processing of any data waiting at the rx socket.
*/
void ProcessData(void);
+ void ProcessPosMsg ( const char *Msg );
+ void ProcessChatMsg ( const char *Msg );
/** Updates the model positions for the players
*/
--- /dev/null
+//////////////////////////////////////////////////////////////////////
+//
+// Tiny XDR implementation for flightgear
+// written by Oliver Schroeder
+// released to the puiblic domain
+//
+// This implementation is not complete, but implements
+// everything we need.
+//
+// For further reading on XDR read RFC 1832.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include <plib/ul.h>
+
+#include "tiny_xdr.hpp"
+
+/* XDR 8bit integers */
+xdr_data_t
+XDR_encode_int8 ( int8_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+xdr_data_t
+XDR_encode_uint8 ( uint8_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+int8_t
+XDR_decode_int8 ( xdr_data_t n_Val )
+{
+ return (static_cast<int8_t> (SWAP32(n_Val)));
+}
+
+uint8_t
+XDR_decode_uint8 ( xdr_data_t n_Val )
+{
+ return (static_cast<uint8_t> (SWAP32(n_Val)));
+}
+
+/* XDR 16bit integers */
+xdr_data_t
+XDR_encode_int16 ( int16_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+xdr_data_t
+XDR_encode_uint16 ( uint16_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+int16_t
+XDR_decode_int16 ( xdr_data_t n_Val )
+{
+ return (static_cast<int16_t> (SWAP32(n_Val)));
+}
+
+uint16_t
+XDR_decode_uint16 ( xdr_data_t n_Val )
+{
+ return (static_cast<uint16_t> (SWAP32(n_Val)));
+}
+
+
+/* XDR 32bit integers */
+xdr_data_t
+XDR_encode_int32 ( int32_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+xdr_data_t
+XDR_encode_uint32 ( uint32_t n_Val )
+{
+ return (SWAP32(static_cast<xdr_data_t> (n_Val)));
+}
+
+int32_t
+XDR_decode_int32 ( xdr_data_t n_Val )
+{
+ return (static_cast<int32_t> (SWAP32(n_Val)));
+}
+
+uint32_t
+XDR_decode_uint32 ( xdr_data_t n_Val )
+{
+ return (static_cast<uint32_t> (SWAP32(n_Val)));
+}
+
+
+/* XDR 64bit integers */
+xdr_data2_t
+XDR_encode_int64 ( int64_t n_Val )
+{
+ return (SWAP64(static_cast<xdr_data2_t> (n_Val)));
+}
+
+xdr_data2_t
+XDR_encode_uint64 ( uint64_t n_Val )
+{
+ return (SWAP64(static_cast<xdr_data2_t> (n_Val)));
+}
+
+int64_t
+XDR_decode_int64 ( xdr_data2_t n_Val )
+{
+ return (static_cast<int64_t> (SWAP64(n_Val)));
+}
+
+uint64_t
+XDR_decode_uint64 ( xdr_data2_t n_Val )
+{
+ return (static_cast<uint64_t> (SWAP64(n_Val)));
+}
+
+
+/* float */
+xdr_data_t
+XDR_encode_float ( float f_Val )
+{
+ xdr_data_t* tmp;
+
+ tmp = (xdr_data_t*) &f_Val;
+ return (XDR_encode_int32 (*tmp));
+}
+
+float
+XDR_decode_float ( xdr_data_t f_Val )
+{
+ float* tmp;
+ xdr_data_t dummy;
+
+ dummy = XDR_decode_int32 (f_Val);
+ tmp = (float*) &dummy;
+ return (*tmp);
+}
+
+/* double */
+xdr_data2_t
+XDR_encode_double ( double d_Val )
+{
+ xdr_data2_t* tmp;
+
+ tmp = (xdr_data2_t*) &d_Val;
+ return (XDR_encode_int64 (*tmp));
+}
+
+double
+XDR_decode_double ( xdr_data2_t d_Val )
+{
+ double* tmp;
+ xdr_data2_t dummy;
+
+ dummy = XDR_decode_int64 (d_Val);
+ tmp = (double*) &dummy;
+ return (*tmp);
+}
+
+
--- /dev/null
+//////////////////////////////////////////////////////////////////////
+//
+// Tiny XDR implementation for flightgear
+// written by Oliver Schroeder
+// released to the puiblic domain
+//
+// This implementation is not complete, but implements
+// everything we need.
+//
+// For further reading on XDR read RFC 1832.
+//
+// NEW
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TINY_XDR_HEADER
+#define TINY_XDR_HEADER
+
+#if defined HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+#if defined HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#include <plib/ul.h>
+
+//////////////////////////////////////////////////////////////////////
+//
+// There are many sick systems out there:
+//
+// check for sizeof(float) and sizeof(double)
+// if sizeof(float) != 4 this code must be patched
+// if sizeof(double) != 8 this code must be patched
+//
+// Those are comments I fetched out of glibc source:
+// - s390 is big-endian
+// - Sparc is big-endian, but v9 supports endian conversion
+// on loads/stores and GCC supports such a mode. Be prepared.
+// - The MIPS architecture has selectable endianness.
+// - x86_64 is little-endian.
+// - CRIS is little-endian.
+// - m68k is big-endian.
+// - Alpha is little-endian.
+// - PowerPC can be little or big endian.
+// - SH is bi-endian but with a big-endian FPU.
+// - hppa1.1 big-endian.
+// - ARM is (usually) little-endian but with a big-endian FPU.
+//
+//////////////////////////////////////////////////////////////////////
+inline uint32_t bswap_32(unsigned int b) {
+ unsigned x = b;
+ ulEndianSwap(&x);
+ return x;
+}
+
+inline uint64_t bswap_64(unsigned long long b) {
+ uint64_t x = b;
+ x = ((x >> 32) & 0x00000000FFFFFFFFLL) | ((x << 32) & 0xFFFFFFFF00000000LL);
+ x = ((x >> 16) & 0x0000FFFF0000FFFFLL) | ((x << 16) & 0xFFFF0000FFFF0000LL);
+ x = ((x >> 8) & 0x00FF00FF00FF00FFLL) | ((x << 8) & 0xFF00FF00FF00FF00LL);
+ return x;
+}
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define SWAP32(arg) arg
+# define SWAP64(arg) arg
+# define LOW 0
+# define HIGH 1
+#else
+# define SWAP32(arg) bswap_32(arg)
+# define SWAP64(arg) bswap_64(arg)
+# define LOW 1
+# define HIGH 0
+#endif
+
+#define XDR_BYTES_PER_UNIT 4
+
+typedef uint32_t xdr_data_t; /* 4 Bytes */
+typedef uint64_t xdr_data2_t; /* 8 Bytes */
+
+/* XDR 8bit integers */
+xdr_data_t XDR_encode_int8 ( int8_t n_Val );
+xdr_data_t XDR_encode_uint8 ( uint8_t n_Val );
+int8_t XDR_decode_int8 ( xdr_data_t n_Val );
+uint8_t XDR_decode_uint8 ( xdr_data_t n_Val );
+
+/* XDR 16bit integers */
+xdr_data_t XDR_encode_int16 ( int16_t n_Val );
+xdr_data_t XDR_encode_uint16 ( uint16_t n_Val );
+int16_t XDR_decode_int16 ( xdr_data_t n_Val );
+uint16_t XDR_decode_uint16 ( xdr_data_t n_Val );
+
+/* XDR 32bit integers */
+xdr_data_t XDR_encode_int32 ( int32_t n_Val );
+xdr_data_t XDR_encode_uint32 ( const uint32_t n_Val );
+int32_t XDR_decode_int32 ( xdr_data_t n_Val );
+uint32_t XDR_decode_uint32 ( const xdr_data_t n_Val );
+
+/* XDR 64bit integers */
+xdr_data2_t XDR_encode_int64 ( int64_t n_Val );
+xdr_data2_t XDR_encode_uint64 ( uint64_t n_Val );
+int64_t XDR_decode_int64 ( xdr_data2_t n_Val );
+uint64_t XDR_decode_uint64 ( xdr_data2_t n_Val );
+
+//////////////////////////////////////////////////
+//
+// FIXME: #1 these funtions must be fixed for
+// none IEEE-encoding architecturs
+// (eg. vax, big suns etc)
+// FIXME: #2 some compilers return 'double'
+// regardless of return-type 'float'
+// this must be fixed, too
+// FIXME: #3 some machines may need to use a
+// different endianess for floats!
+//
+//////////////////////////////////////////////////
+/* float */
+xdr_data_t XDR_encode_float ( float f_Val );
+float XDR_decode_float ( xdr_data_t f_Val );
+
+/* double */
+xdr_data2_t XDR_encode_double ( double d_Val );
+double XDR_decode_double ( xdr_data2_t d_Val );
+
+#endif