1
0
Fork 0

Oliver Schroeder:

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.
This commit is contained in:
ehofman 2005-09-18 12:37:18 +00:00
parent dcbc6369ac
commit 7311d05c87
7 changed files with 506 additions and 177 deletions

View 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

View file

@ -36,61 +36,55 @@
******************************************************************/
#include <simgear/compiler.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include "tiny_xdr.hpp"
#include <plib/sg.h>
// 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! */
// 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
/** 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];
} 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

View 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]);
}
@ -295,30 +302,31 @@ 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;
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

View file

@ -210,18 +210,11 @@ 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) {
if (! m_bInitialised) {
return;
}
// Read the receive socket and process any data
do {
@ -231,60 +224,115 @@ void FGMultiplayRxMgr::ProcessData(void) {
// packet waiting to be processed.
iBytes = mDataRxSocket->recv(sMsg, MAX_PACKET_SIZE, 0);
// Data received
if (iBytes > 0) {
if (iBytes >= (int)sizeof(MsgHdr)) {
// 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;
PlayerAddress.s_addr = MsgHdr->lReplyAddress;
sIpAddress = inet_ntoa(PlayerAddress);
iPort = MsgHdr->iReplyPort;
sCallsign = MsgHdr->sCallsign;
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) {
if (m_sCallsign == MsgHdr->sCallsign) {
return;
}
// 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" );
}
ProcessChatMsg ((char*) & sMsg);
break;
case POS_DATA_ID:
if (MsgHdr->iMsgLen == sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
PosMsg = (T_PositionMsg *)(sMsg + sizeof(T_MsgHdr));
sModelName = PosMsg->sModel;
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.
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);
m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
bActivePlayer = true;
}
}
}
if (bActivePlayer) {
// nothing more to do
return;
}
// 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 );
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, iPort, sCallsign, sModelName, false);
m_Player[iPlayerCnt]->SetPosition(PosMsg->PlayerOrientation, PosMsg->PlayerPosition);
m_Player[iPlayerCnt]->Open(sIpAddress, MsgHdr->iReplyPort,
MsgHdr->sCallsign, PosMsg->sModel, false);
m_Player[iPlayerCnt]->SetPosition(Orientation, Position);
bActivePlayer = true;
}
iPlayerCnt++;
@ -293,40 +341,30 @@ void FGMultiplayRxMgr::ProcessData(void) {
// 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." );
SG_LOG( SG_NETWORK, SG_ALERT,
"FGMultiplayRxMgr::MP_ProcessData - Unable to add new player ("
<< MsgHdr->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);
}
}
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

View file

@ -30,10 +30,6 @@
#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
*/

View file

@ -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);
}

View file

@ -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