]> git.mxchange.org Git - flightgear.git/commitdiff
Oliver Schroeder:
authorehofman <ehofman>
Sun, 18 Sep 2005 12:37:18 +0000 (12:37 +0000)
committerehofman <ehofman>
Sun, 18 Sep 2005 12:37:18 +0000 (12:37 +0000)
I have prepared a new patch for multiplayer, which fixes endianess issues with
multiplayer code. It's basically identical to the patch I sent before my
vacation, but contains minor fixes.

Multiplayer should now be working under all unix-like environments and windows
native. The basic trick is to let configure check for endianess of the host
system.

It will not work on system not using configure in the build process (excluding
windows), ie. possibly MACOS. For those system we should provide #ifdefs in
tiny_xdr.hpp.

Erik:
I've updated the patch to use the Plib utils package for endian swapping an
used a preprocessor directive to detect endianess.

src/MultiPlayer/Makefile.am
src/MultiPlayer/mpmessages.hxx
src/MultiPlayer/mpplayer.cxx
src/MultiPlayer/multiplayrxmgr.cxx
src/MultiPlayer/multiplayrxmgr.hxx
src/MultiPlayer/tiny_xdr.cpp [new file with mode: 0644]
src/MultiPlayer/tiny_xdr.hpp [new file with mode: 0644]

index a7b5a3e3e806c90c1ec8ca717c7dfdd1aa45670b..9057a991c4d3239f95e530d9681bc5cc03e5454f 100644 (file)
@@ -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
 
index 8340897aef806f449b8049cc3040ebf94498af1b..65d00011a52fa948970521ee03cb3fdf01803d55 100644 (file)
 ******************************************************************/
 
 #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
 
index 8a97280a3341ce38616910eeacc1ed08bfb5b118..45fad4b90395554867d9d453c7dfb2befb285ee6 100644 (file)
@@ -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
index 95e65646f567f436d780a41349eea4c37fe8e2ee..2129e9c5289a1a115b13a116dca9fd42bc2ee5ef 100644 (file)
@@ -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
+
+
+    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
index 5127eaaae400972ad1dbd7c64edf9d0905288e83..5e836eb9378669ca031408ef5ed2dd2f6266b514 100644 (file)
 #include "mpplayer.hxx"
 #include "mpmessages.hxx"
 
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#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 (file)
index 0000000..d1182af
--- /dev/null
@@ -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 <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);
+}
+
+
diff --git a/src/MultiPlayer/tiny_xdr.hpp b/src/MultiPlayer/tiny_xdr.hpp
new file mode 100644 (file)
index 0000000..62e8d9a
--- /dev/null
@@ -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 <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