diff --git a/src/MultiPlayer/Makefile.am b/src/MultiPlayer/Makefile.am index a7b5a3e3e..9057a991c 100644 --- a/src/MultiPlayer/Makefile.am +++ b/src/MultiPlayer/Makefile.am @@ -1,6 +1,6 @@ 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 diff --git a/src/MultiPlayer/mpmessages.hxx b/src/MultiPlayer/mpmessages.hxx index 8340897ae..65d00011a 100644 --- a/src/MultiPlayer/mpmessages.hxx +++ b/src/MultiPlayer/mpmessages.hxx @@ -36,61 +36,55 @@ ******************************************************************/ #include - -#ifdef HAVE_STDINT_H -# include -#endif +#include "tiny_xdr.hpp" #include +// magic value for messages +const uint32_t MSG_MAGIC = 0x46474653; // "FGFS" +// protocoll version +const uint32_t PROTO_VER = 0x00010001; // 1.1 + // 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 { +#define CHAT_MSG_ID 1 +#define UNUSABLE_POS_DATA_ID 2 +#define POS_DATA_ID 3 - /** Message identifier, multiple of 8! */ - uint32_t MsgId; +// 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 - /** 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]; - -} T_MsgHdr; - -#define MAX_CHAT_MSG_LEN 48 -/** Chat message */ -typedef struct { - - /** Text of chat message */ - char sText[MAX_CHAT_MSG_LEN]; - -} T_ChatMsg; - -/* should be a multiple of 8! */ -#define MAX_MODEL_NAME_LEN 48 /** Aircraft position message */ -typedef struct { +typedef xdr_data2_t xdrPosition[3]; +typedef xdr_data_t xdrOrientation[4]; - /** Name of the aircraft model */ - char sModel[MAX_MODEL_NAME_LEN]; +// 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 +}; - /** Position data for the aircraft */ - sgdVec3 PlayerPosition; - sgQuat PlayerOrientation; - -} T_PositionMsg; +// 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 diff --git a/src/MultiPlayer/mpplayer.cxx b/src/MultiPlayer/mpplayer.cxx index 8a97280a3..45fad4b90 100644 --- a/src/MultiPlayer/mpplayer.cxx +++ b/src/MultiPlayer/mpplayer.cxx @@ -105,6 +105,8 @@ bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCal 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) { @@ -169,7 +171,6 @@ void MPPlayer::Close(void) { void MPPlayer::SetPosition(const sgQuat PlayerOrientation, const sgdVec3 PlayerPosition) { - // Save the position matrix and update time if (m_bInitialised) { sgdCopyVec3(m_ModelPosition, PlayerPosition); @@ -178,7 +179,6 @@ void MPPlayer::SetPosition(const sgQuat PlayerOrientation, m_bUpdated = true; } - } @@ -281,10 +281,17 @@ void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) { 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]); } @@ -294,31 +301,32 @@ void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) { ******************************************************************/ 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 diff --git a/src/MultiPlayer/multiplayrxmgr.cxx b/src/MultiPlayer/multiplayrxmgr.cxx index 95e65646f..2129e9c52 100644 --- a/src/MultiPlayer/multiplayrxmgr.cxx +++ b/src/MultiPlayer/multiplayrxmgr.cxx @@ -210,123 +210,161 @@ void FGMultiplayRxMgr::ProcessData(void) { 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 - 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 - 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"); - } - } - - } while (iBytes > 0); - + 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 + 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 + 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; + } + + 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 diff --git a/src/MultiPlayer/multiplayrxmgr.hxx b/src/MultiPlayer/multiplayrxmgr.hxx index 5127eaaae..5e836eb93 100644 --- a/src/MultiPlayer/multiplayrxmgr.hxx +++ b/src/MultiPlayer/multiplayrxmgr.hxx @@ -30,10 +30,6 @@ #include "mpplayer.hxx" #include "mpmessages.hxx" -#ifdef HAVE_CONFIG_H -# include -#endif - #include STL_STRING SG_USING_STD(string); @@ -71,6 +67,8 @@ public: /** 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 */ diff --git a/src/MultiPlayer/tiny_xdr.cpp b/src/MultiPlayer/tiny_xdr.cpp new file mode 100644 index 000000000..d1182af85 --- /dev/null +++ b/src/MultiPlayer/tiny_xdr.cpp @@ -0,0 +1,163 @@ +////////////////////////////////////////////////////////////////////// +// +// 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 + +#include "tiny_xdr.hpp" + +/* XDR 8bit integers */ +xdr_data_t +XDR_encode_int8 ( int8_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +xdr_data_t +XDR_encode_uint8 ( uint8_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +int8_t +XDR_decode_int8 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + +uint8_t +XDR_decode_uint8 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + +/* XDR 16bit integers */ +xdr_data_t +XDR_encode_int16 ( int16_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +xdr_data_t +XDR_encode_uint16 ( uint16_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +int16_t +XDR_decode_int16 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + +uint16_t +XDR_decode_uint16 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + + +/* XDR 32bit integers */ +xdr_data_t +XDR_encode_int32 ( int32_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +xdr_data_t +XDR_encode_uint32 ( uint32_t n_Val ) +{ + return (SWAP32(static_cast (n_Val))); +} + +int32_t +XDR_decode_int32 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + +uint32_t +XDR_decode_uint32 ( xdr_data_t n_Val ) +{ + return (static_cast (SWAP32(n_Val))); +} + + +/* XDR 64bit integers */ +xdr_data2_t +XDR_encode_int64 ( int64_t n_Val ) +{ + return (SWAP64(static_cast (n_Val))); +} + +xdr_data2_t +XDR_encode_uint64 ( uint64_t n_Val ) +{ + return (SWAP64(static_cast (n_Val))); +} + +int64_t +XDR_decode_int64 ( xdr_data2_t n_Val ) +{ + return (static_cast (SWAP64(n_Val))); +} + +uint64_t +XDR_decode_uint64 ( xdr_data2_t n_Val ) +{ + return (static_cast (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); +} + + diff --git a/src/MultiPlayer/tiny_xdr.hpp b/src/MultiPlayer/tiny_xdr.hpp new file mode 100644 index 000000000..62e8d9a6e --- /dev/null +++ b/src/MultiPlayer/tiny_xdr.hpp @@ -0,0 +1,128 @@ +////////////////////////////////////////////////////////////////////// +// +// 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 +#endif + +#include +#if defined HAVE_STDINT_H +# include +#endif + +#include + +////////////////////////////////////////////////////////////////////// +// +// 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