reman3/Rayman_X/cpa/tempgrp/NET/netser.c

6481 lines
285 KiB
C
Raw Permalink Blame History

/********************************************************************************/
/* */
/* NetSer.c */
/* */
/* This file defines the level 2 functions : */
/* general API functions, system message handling */
/* */
/********************************************************************************/
#include "warnings.h"
#if defined(_MSC_VER)
#pragma warning(disable : 4054)
#endif
#ifndef _NO_USE_DEFAULT_NET_FUNCTIONS_
#include <windows.h>
#include <stdlib.h>
#endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/
#include <memory.h>
#include "NetMemCo.h"
#define GLOBALS
#include "PrivNetDef.h"
#undef GLOBALS
#include "PrivNetSer.h"
#include "PrivNetSynch.h"
#include "NetL2Pri.h"
#include "NetL1Pri.h"
#include "NetList2.h"
#include "NetEnd.h"
#include "NET\NetDebug.h"
#include <stdio.h>
#include <errno.h>
#include <direct.h>
/*
------------------------------------------------------------------------------------------
DEFINITION OF INTERNAL CONSTANTS :
------------------------------------------------------------------------------------------
*/
/* this is the unit in which the time delta between machines is expressed */
#define C_ulUniversalLagUnit 1000
/*this is the number of connection requests sent for a single call to ConnectToSession*/
#define REPEAT_COUNT 3
/*
------------------------------------------------------------------------------------------
DEFINITION OF INTERNAL STRUCTURES :
------------------------------------------------------------------------------------------
*/
/* this structure tells for each remote player in the session an estimation*/
/* of the time lag between the timer callback values between us and another machine.*/
/* That is to say, the difference between the returned values of this callback on the*/
/* two machines at the same absolute instant.*/
typedef struct tdstNetTimeDelta_
{
NetLib_tduxPlayerId ulPlayerId;
double dDeltaWithLocal; /* in C_ulTimeDeltaPrecision th of second*/
unsigned long ulLatency; /* in gs_ulLocalTimeScale th of second*/
unsigned long ulScaleOfRecipient;
unsigned short NumberOfRetries;
unsigned short LastRetries;
}tdstNetTimeDelta;
/*
* this structure is the message that is sent back and forth to dertermine the
* connexion parameters between the local machine and the other players
*/
#pragma pack(push)
#pragma pack(1)
typedef struct tdstNetPingMessage_
{
unsigned long ulTimeOfSender;
unsigned long ulTimeOfRecipient;
unsigned long ulScaleOfRecipient;
unsigned short numPing;
}tdstNetPingMessage;
#pragma pack(pop)
/* Used for checking sessions : */
typedef struct _tdstNetTemp
{
unsigned char ucWaitForReply;
NetLib_tduxPlayerId ulPlayerId;
}tdstNetTemp;
typedef struct _tdstMsgInfo
{
NetLib_tdulTimeInfo m_ulSendingTime;/* The time at which the message will be sent*/
tdstNetMessage *m_p_stMessage;
NetLib_tduxPlayerId m_ulPlayerId;
}tdstMsgInfo;
typedef struct _tdstCopyInfo
{
NetLib_tdstPlayerInfo *p_stPlayerInfoArray;
unsigned short uwCurrentPlayerSlot;
}tdstCopyInfo;
typedef NetLib_tdeErrorStatus(_NET_CALLING_CONV_ *tdfn_eNetSysMsgHandle)(tdstNetMessage *,tdeNetProtocol,tduwNetChannel);
typedef NetLib_tdeErrorStatus(_NET_CALLING_CONV_ *tdfn_eNetSysMsgSwapLittleBigEndian)(tdstNetMessage*,tdeNetProtocol,tduwNetChannel);
/*
------------------------------------------------------------------------------------------
DEFINITION OF INTERNAL VARIABLES:
------------------------------------------------------------------------------------------
*/
/* array of functions handling netlib sys messages :*/
static tdfn_eNetSysMsgHandle *gs_pfn_eSysMsgMap;
/* array of functions swaping message from little/big endian to big/little endian*/
static tdfn_eNetSysMsgSwapLittleBigEndian *gs_pfn_eSysMsgSwapMap;
/* sets of function that must be called inside the vNetEngine */
static tdstNetList2 gs_stEngineFunction; /* The list */
static char gs_cIsNetlibInitialised = 0;
static NetLib_tduwMode gs_uwMode;
static short gs_wBroadcastIpx;
/* Informations about the current game : */
static NetLib_tdstSessionInfo gs_stCurrentSession;
/* array of time lags for each player in the session */
static tdstNetTimeDelta *gs_d_stTimeDeltas;
/* do I have to handle calibration replies that arrived ? */
static unsigned char gs_b_ucDeltaCalibrationIsEnabled;
/* Does a listen must be done before accepting a player ?*/
static unsigned char gs_ucAcceptWithoutListening;
/* Informations about a player who want to join the Session*/
static NetLib_tdstPlayerInfo *gs_p_stPreSessionPlayerInfo;
static tdeNetConnectReceptionStatus gs_tdePreSessionPlayerStatus;
static NetLib_tdulTimeInfo gs_tm_ulPreSessionPlayerTimer;
static NetLib_tdulTimeInfo gs_tm_ulPreSessionPlayerMaxWaitingTime;
/* Callback for connection request filter*/
NetLib_tdeErrorStatus (_NET_CALLING_CONV_*g_pfn_ePlayerConnectionRequestFilter)(NetLib_tdstPlayerInfo*,long*);
/* list of sessions :*/
static NetLib_tdstSessionInfo *gs_dstSessions;
static unsigned char *gs_dpucWaitForReply;
static tdeNetListeningMode gs_eListeningMode;
static NetLib_tdulTimeInfo gs_tm_ulGetActiveSessionsFreq;
static NetLib_tdulTimeInfo gs_tm_ulPrevGetActiveSessions;
static NetLib_tduxDescriptionLength gs_uxMaxPlayerInfo;
static unsigned short gs_uwNumberOfSessionsExpected;
static unsigned short gs_c_uwNumberOfSessionsDetected;
/* Callback for session filter */
NetLib_tdeErrorStatus (_NET_CALLING_CONV_*g_pfn_eSessionFilter)(NetLib_tdstSessionInfo*);
/* For connection :*/
static NetLib_tdstSessionInfo *gs_p_stConnectRequestSessionInfo;
static long gs_lConDenyParam;
static tdeNetConnectRequestStatus *gs_d_tdeConnectRequestStatusArray;
/* Callback for disconnection :*/
void (_NET_CALLING_CONV_*g_pfn_vDisconnectCallBack)(NetLib_tduxPlayerId);
/* Pointer to a random function :*/
unsigned long (_NET_CALLING_CONV_*g_pfn_ulNetRandom)(void);
/* Pointer to a timer function : */
NetLib_tdfnulGetTimeInfo g_pfn_ulNetGetTimeInfo;
/* how far goes the timer function in 1 second ? */
unsigned long gs_ulLocalTimeScale;
/* for internet simulation :*/
static tdstNetList2 gs_stPlayerSendingList;
static NetLib_tdulTimeInfo gs_ulInternetDelay;
static NetLib_tdulTimeInfo gs_ulInternetRandom;
static int gs_ArtificialLatency;
/* for handling read receipt :*/
static tdstNetList2 gs_stReadReceiptList;
/*
------------------------------------------------------------------------------------------
INITIALISATION FUNCTIONS :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetBroadcastState
Set the broadcast state.
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_eSetBroadcastState(short BroadcastIpx)
{
gs_wBroadcastIpx=BroadcastIpx;
vLevel1SetBroadcastState(BroadcastIpx);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eInitializeGlobalData
Initialize global variables
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError
NetLib_E_es_NotEnoughMemory if there was not enough memory to complete the function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eInitializeGlobalData(unsigned long ulBufferSize, char* pPointerArea,NetLib_tduwMode uwMode,short BroadcastIpx)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tduxPlayerId ulNewPlayerId;
#if defined(NET_USE_DEBUG)
vDebugClear(Net_C_Debug_NetSer);
/*
vDebugActiv(Net_C_Debug_NetSer);
*/
vDebugS(Net_C_Debug_NetSer,"Netlib - NetSer : Log file");
#endif /* NET_USE_DEBUG */
/* If netlib has already been initialised*/
if(gs_cIsNetlibInitialised) return NetLib_E_es_NoError;
gs_cIsNetlibInitialised = 1;
gs_uwMode=uwMode;
gs_wBroadcastIpx=BroadcastIpx;
/* Gives memory to the netlib :*/
uxInitMalloc(ulBufferSize,pPointerArea);
/* Initialise netlib sys message map*/
if((eErrorReturned = eNetBuildMessageMap())!=NetLib_E_es_NoError)
{
gs_cIsNetlibInitialised = 0;
return eErrorReturned;
}
if((eErrorReturned=eNetBuildMessageSwapLittleBigEndianMap())!=NetLib_E_es_NoError)
{
gs_cIsNetlibInitialised = 0;
return eErrorReturned;
}
if((eErrorReturned = eNetBuildEngineFunctionsList())!=NetLib_E_es_NoError)
{
gs_cIsNetlibInitialised = 0;
return eErrorReturned;
}
/* Callback for disconnection :*/
NetLib_vRegisterDisconnectCallback((NetLib_tdfnvDisconnectCallback)C_pNull);
#ifndef _NO_USE_DEFAULT_NET_FUNCTIONS_
NetLib_vInitializeGetTimeInfoFunction(fn_ulDefaultNetGetTimeInfo,1000);
#else
NetLib_vInitializeGetTimeInfoFunction((NetLib_tdulTimeInfo(_NET_CALLING_CONV_*)(void))C_pNull,0);
#endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/
/* Pointer to a random function :*/
#ifndef _NO_USE_DEFAULT_NET_FUNCTIONS_
srand((unsigned)g_pfn_ulNetGetTimeInfo());
NetLib_vInitializeRandomFunction(fn_ulDefaultNetRandom);
#else
NetLib_vInitializeRandomFunction((NetLib_tdfnulRandom)C_pNull);
#endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/
/* Pointer to a memcpy function :*/
NetLib_vInitializeMemcopyFunction((td_pfn_vNetMemcpy)memcpy);
NetLib_vRegisterFilterSessionCallback((NetLib_tdfneFilterSessionCallback)C_pNull);
NetLib_vRegisterPlayerConnectionRequestFilter((NetLib_tdfnePlayerConnectionRequestFilterCallback)C_pNull);
/* no time deltas allocated yet */
gs_d_stTimeDeltas = (tdstNetTimeDelta *) C_pNull;
/* time delta calibration is not enabled */
gs_b_ucDeltaCalibrationIsEnabled = 0;
/* Initialize level 1 :*/
eErrorReturned = eLevel1GlobalSetup(gs_uwMode,gs_wBroadcastIpx);
/* Informations about the current game : */
gs_stCurrentSession.uxSessionDescriptionLength = 0;
gs_stCurrentSession.pSessionDescriptionData = (tdpPointer)C_pNull;
gs_stCurrentSession.uwMaxNumberOfPlayers = 0;
gs_stCurrentSession.uwNumberOfPlayers = 0;
gs_stCurrentSession.uwIndexOfLocalPlayer = 0;
gs_stCurrentSession.GameOptions=NULL;
/* Allocate one cell in the array for the local player :*/
gs_stCurrentSession.d_stPlayerInfo =(NetLib_tdstPlayerInfo*)pMalloc(sizeof(NetLib_tdstPlayerInfo));
if(gs_stCurrentSession.d_stPlayerInfo /*!= (NetLib_tdstPlayerInfo*)C_pNull*/)
{
gs_stCurrentSession.uwMaxNumberOfPlayers = 1;
gs_stCurrentSession.uwNumberOfPlayers = 1;
/* getting an id : */
if (gs_uwMode==NetLib_Mode_Direct) ulNewPlayerId = ulNetGetNewPlayerId();
else ulNewPlayerId = 0;
vNetSetOwnPlayerId(ulNewPlayerId);
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength = 0;
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].pPlayerDescriptionData = (tdpPointer)C_pNull;
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].m_ucLittleBigEndian = NetLib_ucGetLittleBigEndian();
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].wNewPlayer = 0;
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].Options = NULL;
vNetSetSessionId(ulNewPlayerId);
}
else
{
gs_cIsNetlibInitialised = 0;
vNetSetSessionId(C_uxNetInvalidId);
eErrorReturned = NetLib_E_es_NotEnoughMemory;
}
/* accept without listening ?*/
gs_ucAcceptWithoutListening = NetLib_C_ucListenForAccept;
/* Informations about a player who want to join the Session*/
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo *)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
gs_tm_ulPreSessionPlayerTimer = 0;
gs_tm_ulPreSessionPlayerMaxWaitingTime = 0;
/* list of sessions :*/
gs_dstSessions = (NetLib_tdstSessionInfo *)C_pNull;
gs_eListeningMode = E_Net_LisMod_INVALID;
gs_c_uwNumberOfSessionsDetected = 0;
gs_uwNumberOfSessionsExpected = 0;
gs_tm_ulGetActiveSessionsFreq = 0;
gs_tm_ulPrevGetActiveSessions = 0;
/* For connection :*/
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo *)C_pNull;
gs_d_tdeConnectRequestStatusArray = (tdeNetConnectRequestStatus *)C_pNull;
gs_lConDenyParam= 0;
/* For internet simul :*/
gs_ulInternetDelay=0;
gs_ulInternetRandom=0;
gs_ArtificialLatency=0;
iNetList2Init(&gs_stPlayerSendingList);
/* For read/receipt handling :*/
iNetList2Init(&gs_stReadReceiptList);
vNetLibInitSynchro();
return eErrorReturned;
}
/*
------------------------------------------------------------------------------------------
ADDING NEW PLAYERS:
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eAddNewPlayer
Add a new player
////////////////////////////////////////////////////////////////////////////////
Creation date : October , 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eAddNewPlayer(NetLib_tdstAddPlayerDesc *p_stAddPlayerDesc)
{
NetLib_tdstPlayerInfo *p_stNewPlayerSlot;
NetLib_tdeErrorStatus eErrorReturned;
/* First of all, check if the library has been initialised*/
if(!gs_cIsNetlibInitialised) return NetLib_E_es_NotInitialized;
if (p_stAddPlayerDesc->IsYou)
{
vNetSetOwnPlayerId(p_stAddPlayerDesc->m_tduxPlayerId);
p_stNewPlayerSlot=pstNetGetOwnPlayerSlot();
p_stNewPlayerSlot->wNewPlayer=0;
}
else
{
#ifdef NET_USE_DEBUG
vDebugFormat(Net_C_Debug_NetSer, "AddNewPlayer: remote player %lx", p_stAddPlayerDesc->m_tduxPlayerId);
#endif
/* Get a new slot for the player :*/
p_stNewPlayerSlot = pstNetGetPlayerSlot(C_uxNetInvalidId);
if(!p_stNewPlayerSlot) return NetLib_E_es_AlreadyTooMuchPlayers;
/* The player can be correctly added to the level 2:*/
M_ulNetPlayerIdSlot(p_stNewPlayerSlot) = p_stAddPlayerDesc->m_tduxPlayerId;
p_stNewPlayerSlot->uxPlayerDescriptionLength=0;
p_stNewPlayerSlot->pPlayerDescriptionData=NULL;
if((eErrorReturned = eLevel1AddNewPlayer(p_stAddPlayerDesc->m_tduxPlayerId,&(p_stAddPlayerDesc->m_stL1AddPlayerDesc)))!=NetLib_E_es_NoError)
{
M_ulNetPlayerIdSlot(p_stNewPlayerSlot) = C_uxNetInvalidId;
return eErrorReturned;
}
p_stNewPlayerSlot->m_ucLittleBigEndian = NetLib_ucGetLittleBigEndian();
p_stNewPlayerSlot->wNewPlayer=1;
gs_stCurrentSession.uwNumberOfPlayers++;
}
if (p_stNewPlayerSlot->pPlayerDescriptionData) vFree((tdpPointer)p_stNewPlayerSlot->pPlayerDescriptionData);
p_stNewPlayerSlot->pPlayerDescriptionData=NULL;
p_stNewPlayerSlot->uxPlayerDescriptionLength=p_stAddPlayerDesc->m_uxPlayerDesciptionLength;
/*Alloc a player description if necessary:*/
if ((p_stAddPlayerDesc->m_pPlayerDescriptionData) &&
((p_stNewPlayerSlot->pPlayerDescriptionData=pMalloc(p_stAddPlayerDesc->m_uxPlayerDesciptionLength))!=0))
{
g_pfn_vNetMemcpy(p_stNewPlayerSlot->pPlayerDescriptionData,p_stAddPlayerDesc->m_pPlayerDescriptionData,
p_stAddPlayerDesc->m_uxPlayerDesciptionLength);
}
p_stNewPlayerSlot->JoinType=p_stAddPlayerDesc->JoinType;
if( p_stAddPlayerDesc->Options != C_pNull
&& (p_stNewPlayerSlot->Options=pMalloc(strlen(p_stAddPlayerDesc->Options)+1)) != C_pNull)
strcpy(p_stNewPlayerSlot->Options,p_stAddPlayerDesc->Options);
else
p_stNewPlayerSlot->Options=C_pNull;
#ifdef NET_USE_DEBUG
vDebugFormat(Net_C_Debug_NetSer, "AddNewPlayer: OK for %lx", p_stAddPlayerDesc->m_tduxPlayerId);
#endif
return NetLib_E_es_NoError;
}
/*
------------------------------------------------------------------------------------------
SETTING CALLBACK FUNCTIONS :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vInitializeGetTimeInfoFunction
Initialize a function that can give an information of time...
////////////////////////////////////////////////////////////////////////////////
Input : pfn_ulFunc : a pointer to a functions that returns an unsigned short and takes
no parameter
ulTicksPerSec: number of ticks per second this function returns
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vInitializeGetTimeInfoFunction(NetLib_tdfnulGetTimeInfo pfn_ulFunc, unsigned long ulTicksPerSec)
{
g_pfn_ulNetGetTimeInfo = pfn_ulFunc;
gs_ulLocalTimeScale = ulTicksPerSec;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vInitializeMemcopyFunction(void * (*pfn_vMemcpy)( void *dest, const void *src, size_t count ))
Initialize a memcpy function
////////////////////////////////////////////////////////////////////////////////
Input : pfn_vMemcpy: a pointer to a memcpy function
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vInitializeMemcopyFunction(td_pfn_vNetMemcpy pfn_vMemcpy)
{
g_pfn_vNetMemcpy = pfn_vMemcpy;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vInitializeRandomFunction(unsigned long (*pfn_ulFunc)(void))
Initialize a random function
////////////////////////////////////////////////////////////////////////////////
Input : pfn_ulFunc : a pointer to a functions that returns an unsigned long and takes
no parameter
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vInitializeRandomFunction(NetLib_tdfnulRandom pfn_ulFunc)
{
g_pfn_ulNetRandom = pfn_ulFunc;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_vRegisterDisconnectCallback
Initialise the callback for disconnection
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a functions that takes an NetLib_tduxPlayerId for parameter and returns
nothing
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vRegisterDisconnectCallback(NetLib_tdfnvDisconnectCallback pfn_vDisconnectCallback)
{
g_pfn_vDisconnectCallBack = pfn_vDisconnectCallback;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vRegisterFilterSessionCallback
Registers the FilterSession callback
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a function that returns a NetLib_tdeErrorStatus and takes a pointer to a
NetLib_tdstSessionInfo variable
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : June 11,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vRegisterFilterSessionCallback(NetLib_tdfneFilterSessionCallback eSessionFilter)
{
g_pfn_eSessionFilter = eSessionFilter;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vRegisterPlayerConnectionRequestFilter
Registers the PlayerConnectionRequestFilter callback
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a function that returns a NetLib_tdeErrorStatus and takes a pointer to a
NetLib_tdstPlayerInfo variable
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : June 11,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vRegisterPlayerConnectionRequestFilter(NetLib_tdfnePlayerConnectionRequestFilterCallback ePlayerConnectionRequestFilter)
{
g_pfn_ePlayerConnectionRequestFilter = ePlayerConnectionRequestFilter;
}
/*
------------------------------------------------------------------------------------------
SETTING NETLIB PARAMETERS:
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : vNetSetSessionId
Sets a new session id
////////////////////////////////////////////////////////////////////////////////
Input : A new session id
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : September 17,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void vNetSetSessionId(NetLib_tduxSessionId ulNewSessionId)
{
gs_stCurrentSession.uxSessionId = ulNewSessionId;
vLevel1SetSessionId(ulNewSessionId);
}
/*//////////////////////////////////////////////////////////////////////////////
Description :vNetSetOwnPlayerId
Sets a new player id
////////////////////////////////////////////////////////////////////////////////
Input : The new player id
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void vNetSetOwnPlayerId(NetLib_tduxPlayerId ulNewPlayerId)
{
M_ulNetPlayerIdSlot(pstNetGetOwnPlayerSlot()) = ulNewPlayerId;
/* Informs the level 1 of the index of the local player :*/
vLevel1SetPlayerId(ulNewPlayerId);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetCopyPlayerInfoFromId
Copy players info
////////////////////////////////////////////////////////////////////////////////
Input : a player id and a pointer to a netlib_tdstplayerinfo
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occures
////////////////////////////////////////////////////////////////////////////////
Creation date : September,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetCopyPlayerInfoFromId(NetLib_tduxPlayerId ulPlayerId,long lParam)
{
tdstCopyInfo *p_stCopyInfo;
p_stCopyInfo = (tdstCopyInfo *)lParam;
p_stCopyInfo->uwCurrentPlayerSlot++;
return NetLib_eCopystPlayerInfo(&p_stCopyInfo->p_stPlayerInfoArray[p_stCopyInfo->uwCurrentPlayerSlot-1],pstNetGetPlayerSlot(ulPlayerId));
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetInternalChangeMaxNbrOfPlayers
Changes the maximum number of players in the session (internal function)
////////////////////////////////////////////////////////////////////////////////
Input : uwNewMaxPlayers : the new value for the maximum players
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occures
NetLib_E_es_AlreadyTooMuchPlayers if the new value is lower than the number
of players in the session : the value is not changed
////////////////////////////////////////////////////////////////////////////////
Creation date : October 28,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetInternalChangeMaxNbrOfPlayers(unsigned short uwNewMaxPlayers)
{
unsigned short c_uwCurrentPlayer;
NetLib_tdstPlayerInfo *d_stNewPlayerInfo;
NetLib_tdstPlayerInfo stInvalidPlayer;
NetLib_tdstDoForAllDesc stForAllDesc;
tdstCopyInfo stCopyInfo;
NetLib_tdeErrorStatus eErrorReturned;
if(uwNewMaxPlayers <gs_stCurrentSession.uwNumberOfPlayers)
/* the number of players in the session is greater than the new max number of player specified*/
return NetLib_E_es_AlreadyTooMuchPlayers;
if(uwNewMaxPlayers == gs_stCurrentSession.uwMaxNumberOfPlayers) return NetLib_E_es_NoError;
eErrorReturned = eLevel1SetMaxNumberOfRemotePlayers((unsigned short)(uwNewMaxPlayers-1));
if(eErrorReturned != NetLib_E_es_NoError) return eErrorReturned;
d_stNewPlayerInfo = (NetLib_tdstPlayerInfo*)pMalloc(uwNewMaxPlayers*sizeof(NetLib_tdstPlayerInfo));
if(!d_stNewPlayerInfo)
{
eLevel1SetMaxNumberOfRemotePlayers((unsigned short)(gs_stCurrentSession.uwMaxNumberOfPlayers-1));
return NetLib_E_es_NotEnoughMemory;
}
stCopyInfo.p_stPlayerInfoArray = d_stNewPlayerInfo;
stCopyInfo.uwCurrentPlayerSlot = 0;
stForAllDesc.m_pfn_eForAll = eNetCopyPlayerInfoFromId;
stForAllDesc.m_lParameter = (long)&stCopyInfo;
stForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stForAllDesc.m_ucIncludeLocal = NetLib_C_ucIncludeLocalPlayer;
NetLib_eDoForAllPlayers(&stForAllDesc);
M_ulNetPlayerIdSlot(&stInvalidPlayer) = C_uxNetInvalidId;
stInvalidPlayer.uxPlayerDescriptionLength = 0;
stInvalidPlayer.pPlayerDescriptionData = C_pNull;
stInvalidPlayer.m_ucLittleBigEndian = 0;
stInvalidPlayer.Options =NULL;
for(c_uwCurrentPlayer=gs_stCurrentSession.uwNumberOfPlayers;c_uwCurrentPlayer<uwNewMaxPlayers;c_uwCurrentPlayer++)
{
NetLib_eCopystPlayerInfo(&d_stNewPlayerInfo[c_uwCurrentPlayer],&stInvalidPlayer);
}
vFree((tdpPointer)gs_stCurrentSession.d_stPlayerInfo);
gs_stCurrentSession.d_stPlayerInfo = d_stNewPlayerInfo;
/* Since DoForAllPlayers begins with the local player :*/
gs_stCurrentSession.uwIndexOfLocalPlayer = 0;
gs_stCurrentSession.uwMaxNumberOfPlayers = uwNewMaxPlayers;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetMaxNumberOfPlayers
Sets the maximum number of players in the session.
////////////////////////////////////////////////////////////////////////////////
Input : uwNewMaxPlayers : the new value for the maximum players
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occures
NetLib_E_es_AlreadyTooMuchPlayers if the new value is lower than the number
of players in the session : the value is not changed
////////////////////////////////////////////////////////////////////////////////
Creation date : October 28,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSetMaxNumberOfPlayers(unsigned short uwNewMaxPlayers)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstSendDesc stSendDesc;
tdpPointer pMsg;
eErrorReturned = eNetInternalChangeMaxNbrOfPlayers(uwNewMaxPlayers);
if(eErrorReturned != NetLib_E_es_NoError) return eErrorReturned;
if (gs_stCurrentSession.uwNumberOfPlayers>1)
{
/* Informs other players :*/
/* Sends a disconnection message to all the players :*/
stSendDesc.m_tduxRecipientId = C_uxNetBroadcastId;
stSendDesc.m_ulMaxWaitingTime = 0;
pMsg = pMalloc(sizeof(unsigned short));
if(!pMsg) return NetLib_E_es_PlayersNotInformed;
*((unsigned short *)pMsg) = uwNewMaxPlayers;
stSendDesc.m_pMessageData = pMsg;
stSendDesc.m_uwMessageLength = sizeof(unsigned short);
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucReadReceiptRequired;
stSendDesc.m_ulMaxWaitingTime = gs_ulLocalTimeScale*2;
stSendDesc.m_stReadReceiptDesc.m_ulReemitFreq = gs_ulLocalTimeScale/2;
stSendDesc.m_stReadReceiptDesc.m_uxReadReceiptId = E_Net_mt_MaxNbrOfPlayers;
stSendDesc.m_stReadReceiptDesc.p_fnv_ReadReceiptCallback = (NetLib_tdfnvReadReceiptCallback)C_pNull;
eNetInternalSendMessage(&stSendDesc,E_Net_mt_MaxNbrOfPlayers);
vFree(pMsg);
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetSessionDescription
Initialize the SessionDescriptor.
////////////////////////////////////////////////////////////////////////////////
Input : ucBufferLength : the length of the session descriptor.
pSessionDescrData : a buffer from which the session desriptor will be copied
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_NotEnoughMemory if the necessary memory couldn't be allocated.
////////////////////////////////////////////////////////////////////////////////
Creation date : April 1,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSetSessionDescription(NetLib_tduxDescriptionLength uxBufferLength,tdpPointer pSessionDescrData,char b_InformOtherPlayers)
{
NetLib_tdstSendDesc stSendDesc;
tdpPointer pMsgBody;
tdpPointer pOriginData;
NetLib_tdeErrorStatus eErrorReturned;
if(gs_stCurrentSession.pSessionDescriptionData /*!= (tdpPointer)C_pNull*/)
{
vFree((tdpPointer)gs_stCurrentSession.pSessionDescriptionData);
gs_stCurrentSession.pSessionDescriptionData = C_pNull;
gs_stCurrentSession.uxSessionDescriptionLength = 0;
}
if(uxBufferLength)
{
gs_stCurrentSession.pSessionDescriptionData = (tdpPointer)pMalloc(uxBufferLength);
if(gs_stCurrentSession.pSessionDescriptionData /*!=(tdpPointer)C_pNull*/)
{
gs_stCurrentSession.uxSessionDescriptionLength = uxBufferLength;
g_pfn_vNetMemcpy(gs_stCurrentSession.pSessionDescriptionData,pSessionDescrData,uxBufferLength);
}
else
{
gs_stCurrentSession.pSessionDescriptionData = C_pNull;
gs_stCurrentSession.uxSessionDescriptionLength = 0;
return NetLib_E_es_NotEnoughMemory;
}
}
if(!b_InformOtherPlayers) return NetLib_E_es_NoError;
stSendDesc.m_tduxRecipientId = C_uxNetBroadcastId;
stSendDesc.m_ulMaxWaitingTime = 0;
pMsgBody=pMalloc(gs_stCurrentSession.uxSessionDescriptionLength+sizeof(NetLib_tduxDescriptionLength));
if(!pMsgBody) return NetLib_E_es_NotEnoughMemory;
pOriginData = pMsgBody;
*((NetLib_tduxDescriptionLength *)pOriginData)=gs_stCurrentSession.uxSessionDescriptionLength;
pOriginData = (tdpPointer)((NetLib_tduxDescriptionLength *)pOriginData + 1);
if(gs_stCurrentSession.uxSessionDescriptionLength)
g_pfn_vNetMemcpy(pOriginData,gs_stCurrentSession.pSessionDescriptionData,gs_stCurrentSession.uxSessionDescriptionLength);
stSendDesc.m_pMessageData = pMsgBody;
stSendDesc.m_uwMessageLength=gs_stCurrentSession.uxSessionDescriptionLength+sizeof(NetLib_tduxDescriptionLength);
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
if (gs_uwMode==NetLib_Mode_Direct)
{
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucReadReceiptRequired;
stSendDesc.m_stReadReceiptDesc.m_ulMaxWaitingTime = 2*gs_ulLocalTimeScale;
stSendDesc.m_stReadReceiptDesc.m_ulReemitFreq = gs_ulLocalTimeScale/2;
stSendDesc.m_stReadReceiptDesc.m_uxReadReceiptId = E_Net_mt_SysSessionDescriptorChanged;
stSendDesc.m_stReadReceiptDesc.p_fnv_ReadReceiptCallback = (NetLib_tdfnvReadReceiptCallback)C_pNull;
}
else stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucNoReadReceipt;
eErrorReturned = eNetInternalSendMessage(&stSendDesc,E_Net_mt_SysSessionDescriptorChanged);
vFree(pMsgBody);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetLocalPlayerDescription
Initialize the Player descriptor of the local player.
////////////////////////////////////////////////////////////////////////////////
Input : ucBufferLength : the length of the player descriptor.
pPlayerDescrData : a buffer from which the player desriptor will be copied
b_InformOtherPlayers : if non zero, sends a message to all other players that the
local player description has changed...
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_NotEnoughMemory if the necessary memory couldn't be allocated.
NetLib_E_es_PlayersNotInformed if all the players couldn't be informed (can be due
either to a lack of memory or because the sending file of one player is full).
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSetLocalPlayerDescription(NetLib_tduxDescriptionLength ucBufferLength,tdpPointer pPlayerDescrData,char b_InformOtherPlayers)
{
return NetLib_eSetPlayerDescription(NetLib_uxGetOwnPlayerId(),ucBufferLength,
pPlayerDescrData,b_InformOtherPlayers);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetPlayerDescription
Initialize the Player descriptor of the player specified by the first argument.
////////////////////////////////////////////////////////////////////////////////
Input : ulIdPlayer : the id of the player concerned
ucBufferLength : the length of the player descriptor.
pPlayerDescrData : a buffer from which the player desriptor will be copied
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_NotEnoughMemory if the necessary memory couldn't be allocated.
NetLib_E_es_UnknownPlayerId if the id is not in the session player list
////////////////////////////////////////////////////////////////////////////////
Creation date : April 9,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSetPlayerDescription(NetLib_tduxPlayerId ulPlayerId,NetLib_tduxDescriptionLength ucBufferLength,tdpPointer pPlayerDescrData,char b_InformOtherPlayers)
{
NetLib_tdstPlayerInfo *p_stTheConcernedPlayer;
NetLib_tdstSendDesc stSendDesc;
tdpPointer pMsgBody;
tdpPointer pOriginData;
NetLib_tdeErrorStatus eErrorReturned;
p_stTheConcernedPlayer = pstNetGetPlayerSlot(ulPlayerId);
if(!p_stTheConcernedPlayer)
/* No player has been found*/
return NetLib_E_es_UnknownPlayerId;
if(p_stTheConcernedPlayer->pPlayerDescriptionData /*!= (tdpPointer)C_pNull*/)
{
/* if it allready has a descriptor, it must be destroyed : */
vFree((tdpPointer)p_stTheConcernedPlayer->pPlayerDescriptionData);
p_stTheConcernedPlayer->pPlayerDescriptionData = C_pNull;
p_stTheConcernedPlayer->uxPlayerDescriptionLength = 0;
}
if(ucBufferLength)
{
p_stTheConcernedPlayer->pPlayerDescriptionData = (tdpPointer)pMalloc(ucBufferLength);
if(p_stTheConcernedPlayer->pPlayerDescriptionData /*!= (tdpPointer)C_pNull*/)
{
p_stTheConcernedPlayer->uxPlayerDescriptionLength = ucBufferLength;
g_pfn_vNetMemcpy(p_stTheConcernedPlayer->pPlayerDescriptionData,pPlayerDescrData,ucBufferLength);
}
else
{
p_stTheConcernedPlayer->pPlayerDescriptionData = C_pNull;
p_stTheConcernedPlayer->uxPlayerDescriptionLength = 0;
return NetLib_E_es_NotEnoughMemory;
}
}
if(!b_InformOtherPlayers) return NetLib_E_es_NoError;
stSendDesc.m_tduxRecipientId = C_uxNetBroadcastId;
stSendDesc.m_ulMaxWaitingTime = 0;
pMsgBody=pMalloc(p_stTheConcernedPlayer->uxPlayerDescriptionLength+sizeof(NetLib_tduxDescriptionLength)
+sizeof(NetLib_tduxPlayerId));
if(!pMsgBody) return NetLib_E_es_NotEnoughMemory;
pOriginData = pMsgBody;
*((NetLib_tduxPlayerId *)pOriginData) = M_ulNetPlayerIdSlot(p_stTheConcernedPlayer);
pOriginData = (tdpPointer)((NetLib_tduxPlayerId*)pOriginData+1);
*((NetLib_tduxDescriptionLength *)pOriginData)=p_stTheConcernedPlayer->uxPlayerDescriptionLength;
pOriginData = (tdpPointer)((NetLib_tduxDescriptionLength *)pOriginData + 1);
if(p_stTheConcernedPlayer->uxPlayerDescriptionLength)
g_pfn_vNetMemcpy(pOriginData,p_stTheConcernedPlayer->pPlayerDescriptionData,
p_stTheConcernedPlayer->uxPlayerDescriptionLength);
stSendDesc.m_pMessageData=pMsgBody;
stSendDesc.m_uwMessageLength=p_stTheConcernedPlayer->uxPlayerDescriptionLength+
sizeof(NetLib_tduxDescriptionLength)+sizeof(NetLib_tduxPlayerId);
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
if (gs_uwMode==NetLib_Mode_Direct)
{
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucReadReceiptRequired;
stSendDesc.m_stReadReceiptDesc.m_ulMaxWaitingTime = 2*gs_ulLocalTimeScale;
stSendDesc.m_stReadReceiptDesc.m_ulReemitFreq = gs_ulLocalTimeScale/2;
stSendDesc.m_stReadReceiptDesc.m_uxReadReceiptId = E_Net_mt_SysSessionDescriptorChanged;
stSendDesc.m_stReadReceiptDesc.p_fnv_ReadReceiptCallback = (NetLib_tdfnvReadReceiptCallback)C_pNull;
}
else stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucNoReadReceipt;
eErrorReturned = eNetInternalSendMessage(&stSendDesc,E_Net_mt_SysPlayerDescriptorChanged);
vFree(pMsgBody);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vSetAcceptWithoutListening
Sets the flag gs_ucAcceptWithoutListening
////////////////////////////////////////////////////////////////////////////////
Input : NetLib_C_ucAcceptWithoutListening a connection is accepted without a listening
call occured
NetLib_C_ucListenForAccept a connection is accepted only after a listening call
occured
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : July 9, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vSetAcceptWithoutListening(unsigned char ucParam)
{
gs_ucAcceptWithoutListening = ucParam;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSetInternetSimulDelay
Sets the internet simulation delay
////////////////////////////////////////////////////////////////////////////////
Input : a Netlib_tdulTimeInfo
////////////////////////////////////////////////////////////////////////////////
Output : a NetLib_tdeErrorStatus code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSetInternetSimulDelay(NetLib_tdulTimeInfo ulTimeToWait,NetLib_tdulTimeInfo ulRandom)
{
if ((gs_ulInternetDelay || gs_ulInternetRandom) && !(ulTimeToWait || ulRandom))
{
eNetRemoveEngineFunction(iNetEngineInternetSimulation);
}
if (!(gs_ulInternetDelay || gs_ulInternetRandom) && (ulTimeToWait || ulRandom))
{
eNetAddEngineFunction(iNetEngineInternetSimulation);
}
if (ulTimeToWait || ulRandom) gs_ArtificialLatency=1;
else gs_ArtificialLatency=0;
gs_ulInternetDelay = ulTimeToWait;
gs_ulInternetRandom = ulRandom;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vSetPreSessionPlayerMaxWaitingTime
Initialize the maximum time the information about a player who
want to join the session must be kept...
////////////////////////////////////////////////////////////////////////////////
Input : ulMaxDeltaTime : a NetLib_tdulTimeInfo
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vSetPreSessionPlayerMaxWaitingTime(NetLib_tdulTimeInfo ulMaxDeltaTime)
{
gs_tm_ulPreSessionPlayerMaxWaitingTime = ulMaxDeltaTime;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vSetReemissionMode
Sets the reemission mode
////////////////////////////////////////////////////////////////////////////////
Input : 0 if the message is not resent after a full sys msg
1 if the message is resent after a full sys msg
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : June 18,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vSetReemissionMode(unsigned char ucNewReemissionMode)
{
vLevel1SetReemissionMode(ucNewReemissionMode);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetInitLagsAndLatencies
Init lags and latencies procedure.
////////////////////////////////////////////////////////////////////////////////
Input : A player id
a long
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : June 20,96
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetInitLagsAndLatencies(NetLib_tduxPlayerId ulPlayerId, long lParam)
{
static unsigned short uwPlayerCount;
if(ulPlayerId == C_uxNetInvalidId) uwPlayerCount = 0;
else
{
gs_d_stTimeDeltas[uwPlayerCount].ulPlayerId = ulPlayerId;
gs_d_stTimeDeltas[uwPlayerCount].NumberOfRetries = 0;
gs_d_stTimeDeltas[uwPlayerCount].LastRetries = 0;
gs_d_stTimeDeltas[uwPlayerCount].ulLatency = 0;
gs_d_stTimeDeltas[uwPlayerCount].dDeltaWithLocal = 0.0;
gs_d_stTimeDeltas[uwPlayerCount].ulScaleOfRecipient = 0;
uwPlayerCount++;
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSampleLagsAndLatencies
Builds an internal table of approximate time lags and latencies between the machines. Each
machine is queried ucNumberOfRetries times, and answers are expected until ulTimeOut
is spent in the function or all answers are received.
////////////////////////////////////////////////////////////////////////////////
Input : number of times to retry the evaluation for each remote player
timeout to interrupt the calibration before all replies are received if this is the case
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : June 20,96
Author : Benoit Germain
Modification : David Fournier
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSampleLagsAndLatencies(unsigned short ucNumberOfRetries, unsigned long ulTimeOut)
{
NetLib_tdfnePlayerConnectionRequestFilterCallback pfn_eOldPlayerConnectionRequestFilter;
unsigned short uwCurrentPlayer, uwPlayerCount;
tdstNetMessage *p_stTimeMessage;
unsigned long ulInitialDateOfOperation;
NetLib_tdeErrorStatus eReturnValue;
NetLib_tdstDoForAllDesc stForAllDesc;
tdstNetPingMessage *pPingMes;
unsigned short countPing=0;
tdstNetTimeDelta *pTimeDelta;
short notFinish;
unsigned long LastTime=0,CurTime,Wait=50,MaxWait,iWait;
/* remember the time to handle timeouts */
ulInitialDateOfOperation = g_pfn_ulNetGetTimeInfo();
/* free any lingering array of deltas */
if(gs_d_stTimeDeltas) vFree((tdpPointer) gs_d_stTimeDeltas);
gs_d_stTimeDeltas = (tdstNetTimeDelta *) pMalloc(sizeof(tdstNetTimeDelta) * gs_stCurrentSession.uwMaxNumberOfPlayers);
/* if we could allocate the array and the message */
if (!gs_d_stTimeDeltas) return NetLib_E_es_NotEnoughMemory;
uwPlayerCount = gs_stCurrentSession.uwNumberOfPlayers;
/* remember the old function pointer */
pfn_eOldPlayerConnectionRequestFilter = g_pfn_ePlayerConnectionRequestFilter;
/* point to a function that always denies incoming player access while we sample the delays */
NetLib_vRegisterPlayerConnectionRequestFilter(eNetDenyPlayerAccess);
/* scan the player list of the current session */
eNetInitLagsAndLatencies(C_uxNetInvalidId,0l);
stForAllDesc.m_pfn_eForAll = eNetInitLagsAndLatencies;
stForAllDesc.m_lParameter = (long)&gs_d_stTimeDeltas;
stForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stForAllDesc.m_ucIncludeLocal = NetLib_C_ucIncludeLocalPlayer;
NetLib_eDoForAllPlayers(&stForAllDesc);
/* now we handle incoming delta reply messages */
gs_b_ucDeltaCalibrationIsEnabled = 1;
do
{
CurTime=GetTickCount();
if (CurTime>LastTime+50)
{
/* create a new message */
p_stTimeMessage=(tdstNetMessage *)pMalloc(sizeof(tdstNetMessage)+sizeof(tdstNetPingMessage));
if (p_stTimeMessage)
{
/* session and sender id, type of message */
p_stTimeMessage->uxSessionId = gs_stCurrentSession.uxSessionId;
p_stTimeMessage->uxRecipientId=C_uxNetBroadcastId;
p_stTimeMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stTimeMessage->eMessageType = E_Net_mt_SysTimeDeltaRequest;
p_stTimeMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stTimeMessage->uxReplaceType = 0;
p_stTimeMessage->uxReplace = 1;
p_stTimeMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* we store our time in the message, and put room in it so that
* the recipient just has to fill it before replying. */
p_stTimeMessage->uwMessageSizeInBytes = sizeof(tdstNetPingMessage);
/* what time is it, expressed in universal lag units ? */
pPingMes=(tdstNetPingMessage *) (p_stTimeMessage + 1);
pPingMes->ulTimeOfSender = ulTimeInfoToLagUnits(g_pfn_ulNetGetTimeInfo(), gs_ulLocalTimeScale);
pPingMes->numPing=countPing++;
/* try to send the message */
if(gs_ArtificialLatency)
eReturnValue=eInternetSimuSendMessage(C_uxNetBroadcastId,p_stTimeMessage);
else
eReturnValue=eLevel1SendMessage(p_stTimeMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
}
LastTime=CurTime;
}
NetLib_vEngine();
notFinish=0;
/* compute if all answer are arrived. */
MaxWait=0;
for (uwCurrentPlayer=0;uwCurrentPlayer<uwPlayerCount;uwCurrentPlayer++)
{
pTimeDelta=gs_d_stTimeDeltas+uwCurrentPlayer;
if (pTimeDelta->ulPlayerId!=NetLib_uxGetOwnPlayerId())
{
if (pTimeDelta->NumberOfRetries < ucNumberOfRetries) notFinish=1;
if (pTimeDelta->NumberOfRetries)
{
iWait=pTimeDelta->ulLatency/pTimeDelta->NumberOfRetries;
}
else iWait=50;
if (iWait>MaxWait) MaxWait=iWait;
}
}
Wait=MaxWait;
}while ((notFinish) && (g_pfn_ulNetGetTimeInfo() < ulInitialDateOfOperation + ulTimeOut));
/* restore the old function pointer */
NetLib_vRegisterPlayerConnectionRequestFilter(pfn_eOldPlayerConnectionRequestFilter);
/* now we no longer handle incoming delta reply messages */
gs_b_ucDeltaCalibrationIsEnabled = 0;
/* compute the average time delta and latency for each remote player. Note that each player keeps
* its own ucNumberOfRetries because we cannot be sure that all answers will arrive. Only the
* local player has no answer because we know the delta and latency with ourself are zero. */
for (uwCurrentPlayer=0;uwCurrentPlayer<uwPlayerCount;uwCurrentPlayer ++)
{
if (gs_d_stTimeDeltas[uwCurrentPlayer].NumberOfRetries)
{
/* note that the delta is expressed in C_ulUniversalLagUnit th of second */
gs_d_stTimeDeltas[uwCurrentPlayer].dDeltaWithLocal/=gs_d_stTimeDeltas[uwCurrentPlayer].NumberOfRetries;
gs_d_stTimeDeltas[uwCurrentPlayer].ulLatency/=gs_d_stTimeDeltas[uwCurrentPlayer].NumberOfRetries;
#if defined(NET_USE_DEBUG)
vDebugSISISISI(Net_C_Debug_NetSer,"Player",gs_d_stTimeDeltas[uwCurrentPlayer].ulPlayerId,
"Number of retries",gs_d_stTimeDeltas[uwCurrentPlayer].NumberOfRetries,
"Delta",(long)gs_d_stTimeDeltas[uwCurrentPlayer].dDeltaWithLocal,
"Latency",gs_d_stTimeDeltas[uwCurrentPlayer].ulLatency);
#endif /* NET_USE_DEBUG */
}
}
return NetLib_E_es_NoError;
}
/*
------------------------------------------------------------------------------------------
GETTING INFORMATION:
------------------------------------------------------------------------------------------
*/
NetLib_tducBigLittleEndian _NET_CALLING_CONV_ NetLib_ucGetPlayerLittleBigEndian(NetLib_tduxPlayerId ulPlayerId)
{
NetLib_tdstPlayerInfo *p_stPlayerConcerned;
p_stPlayerConcerned = pstNetGetPlayerSlot(ulPlayerId);
if(!p_stPlayerConcerned) return NetLib_ucGetLittleBigEndian();
else return p_stPlayerConcerned->m_ucLittleBigEndian;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eIsPlayerOverInternet
returns the id of the session
////////////////////////////////////////////////////////////////////////////////
Input : A player Id
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_True if the player is over internet,
NetLib_E_es_False if not,
and if player id is C_InvalidPlayerId, the return value is true iff at least one
of the players is over internet
////////////////////////////////////////////////////////////////////////////////
Creation date : December 17, 96
Author : Christophe Roguet
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eIsPlayerOverInternet(NetLib_tduxPlayerId ulPlayerId)
{
unsigned short uwCount;
NetLib_tdstPlayerInfo *p_stPlayerConcerned;
if(ulPlayerId==C_uxNetInvalidId)
{ /* is there any one over internet ? */
for(uwCount = 0; uwCount <gs_stCurrentSession.uwNumberOfPlayers; uwCount++)
if(gs_stCurrentSession.d_stPlayerInfo[uwCount].m_bOverInternet)
return NetLib_E_es_True;
return NetLib_E_es_False;
}
else
{ /* is this particular player over internet ? */
p_stPlayerConcerned = pstNetGetPlayerSlot(ulPlayerId);
if(p_stPlayerConcerned)
if(p_stPlayerConcerned->m_bOverInternet)
return NetLib_E_es_True;
else
return NetLib_E_es_False;
return NetLib_E_es_UnknownPlayerId;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uxGetSessionId
returns the id of the session
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : the Id of the session
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxSessionId _NET_CALLING_CONV_ NetLib_uxGetSessionId(void)
{
return gs_stCurrentSession.uxSessionId;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetSessionDescription
Retrieves the SessionDescriptor.
////////////////////////////////////////////////////////////////////////////////
Input : p_ucBufferLength : the length of the maximum session descriptor to be read
pSessionDescrData : a buffer in which the session desriptor will be copied
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError : if no errors occured.
NetLib_E_es_NotEnoughMemory : if the buffer given was too short to contain the descriptor
////////////////////////////////////////////////////////////////////////////////
Creation date : April 1,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
Be aware to allocate the pSessionDescrData buffer with enough size
(see ucGetSessionDescriptorLength). If it does not have enough size, only
the number of bytes given by the first parameter are copied to the buffer.
When the functions returns, p_ucBufferLength contains the number of
bytes effectively read.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eGetSessionDescription(NetLib_tduxDescriptionLength *p_ucBufferLength,tdpPointer pSessionDescrData)
{
NetLib_tdeErrorStatus eErrorReturned;
if(gs_stCurrentSession.uxSessionDescriptionLength<=*p_ucBufferLength)
{
*p_ucBufferLength = gs_stCurrentSession.uxSessionDescriptionLength;
eErrorReturned = NetLib_E_es_NoError;
}
else
{
eErrorReturned = NetLib_E_es_NotEnoughMemory;
}
if(*p_ucBufferLength)
{
g_pfn_vNetMemcpy(pSessionDescrData,gs_stCurrentSession.pSessionDescriptionData,*p_ucBufferLength);
}
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uxGetSessionDescriptionLength
Returns the length of the Session descriptor.
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : The length of the session descriptor
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxDescriptionLength _NET_CALLING_CONV_ NetLib_uxGetSessionDescriptionLength(void)
{
return gs_stCurrentSession.uxSessionDescriptionLength;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uwGetMaxNumberOfPlayers
Returns the maximum number of players in the session
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : the maximum number of players in the session
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
unsigned short _NET_CALLING_CONV_ NetLib_uwGetMaxNumberOfPlayers(void)
{
return gs_stCurrentSession.uwMaxNumberOfPlayers;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uwGetTotalNumberPlayer
Returns the number of players in the session including the local player
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : the number of players in the session, including the local player
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
unsigned short _NET_CALLING_CONV_ NetLib_uwGetTotalNumberPlayer(void)
{
return gs_stCurrentSession.uwNumberOfPlayers;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uxGetOwnPlayerId
returns the id of the local player
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : the Id of the local player
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxPlayerId _NET_CALLING_CONV_ NetLib_uxGetOwnPlayerId(void)
{
return M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer]);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetPlayersIdFromSession
Returns the players Id in the session including the local player
////////////////////////////////////////////////////////////////////////////////
Input : d_ulListPlayersId : an array that will containt the list of the Id
uwNumberOfPlayers : the number of players expected
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_NumberOfPlayerLarger : if the number of player contained in the session is
larger thant the one specified in the function parameter
NetLib_E_es_NumberOfPlayerSmaller : if the number of player contained in the session is
smaller thant the one specified in the function parameter
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
Be carreful to send the correct uwNumberOfPlayers and to alloc enough for
the d_ulListPlayersId. see uwGetTotalNumberPlayer()
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eGetPlayersIdFromSession(NetLib_tduxPlayerId *d_ulListPlayersId,unsigned short *p_uwNumberOfPlayers)
{
NetLib_tdeErrorStatus eErrorReturned;
unsigned short c_uwCurPlay;
unsigned short c_uwCount;
eErrorReturned = NetLib_E_es_NoError;
if(*p_uwNumberOfPlayers < gs_stCurrentSession.uwNumberOfPlayers)
{
eErrorReturned = NetLib_E_es_NumberOfPlayerLarger;
}
else if(*p_uwNumberOfPlayers > gs_stCurrentSession.uwNumberOfPlayers)
{
*p_uwNumberOfPlayers = gs_stCurrentSession.uwNumberOfPlayers;
eErrorReturned = NetLib_E_es_NumberOfPlayerSmaller;
}
/* Then build and return the list of Ids*/
d_ulListPlayersId[0] = NetLib_uxGetOwnPlayerId();
c_uwCurPlay = NetLib_uwGetFirstRemotePlayerIdPosition();
c_uwCount = 1;
while ((c_uwCount < *p_uwNumberOfPlayers) && (c_uwCurPlay != NetLib_C_uwInvalidPosition))
{
d_ulListPlayersId[c_uwCount] = NetLib_uxGetNextRemotePlayerId(&c_uwCurPlay);
c_uwCount++;
}
if(c_uwCount>=*p_uwNumberOfPlayers) eErrorReturned = NetLib_E_es_NumberOfPlayerSmaller;
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_uwGetFirstRemotePlayerIdPosition
Returns the index of the first remote player
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : The index of the first remote player, if there is remote player
the function returns -1
////////////////////////////////////////////////////////////////////////////////
Creation date : April 29,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
unsigned short _NET_CALLING_CONV_ NetLib_uwGetFirstRemotePlayerIdPosition(void)
{
unsigned short uwIndexReturned;
uwIndexReturned =0;
while ((uwIndexReturned < gs_stCurrentSession.uwMaxNumberOfPlayers) &&
((M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[uwIndexReturned]) == C_uxNetInvalidId)
||(uwIndexReturned == gs_stCurrentSession.uwIndexOfLocalPlayer)))
uwIndexReturned ++;
if(uwIndexReturned >= gs_stCurrentSession.uwMaxNumberOfPlayers)
uwIndexReturned = NetLib_C_uwInvalidPosition ;
return uwIndexReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_ulGetNextRemotePlayerId
Returns the player id which position is given by the argument
and increase the argument to the next position where there is a remote
player
////////////////////////////////////////////////////////////////////////////////
Input : p_uwStartPosition a pointer to the starting position. When the function returns,
it contains the next position to the players array of the current session that
contains information about a remote player. If there is no next position, it is
set to -1
////////////////////////////////////////////////////////////////////////////////
Output : the id of the player at the uwStartPosition if it is a remote player,
otherwise returns C_uxNetInvalidId
////////////////////////////////////////////////////////////////////////////////
Creation date : April 29,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxPlayerId _NET_CALLING_CONV_ NetLib_uxGetNextRemotePlayerId(unsigned short*p_uwStartPosition)
{
NetLib_tduxPlayerId ulPlayerIdReturned;
if(*p_uwStartPosition >=gs_stCurrentSession.uwMaxNumberOfPlayers)
{
*p_uwStartPosition = NetLib_C_uwInvalidPosition;
return C_uxNetInvalidId;
}
if(*p_uwStartPosition == gs_stCurrentSession.uwIndexOfLocalPlayer)
ulPlayerIdReturned = C_uxNetInvalidId;
else
ulPlayerIdReturned = M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[*p_uwStartPosition]);
*p_uwStartPosition = *p_uwStartPosition +1;
while ((*p_uwStartPosition < gs_stCurrentSession.uwMaxNumberOfPlayers)
&&((M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[*p_uwStartPosition]) == C_uxNetInvalidId)
||(*p_uwStartPosition == gs_stCurrentSession.uwIndexOfLocalPlayer)))
(*p_uwStartPosition)++;
if(*p_uwStartPosition >= gs_stCurrentSession.uwMaxNumberOfPlayers)
*p_uwStartPosition = NetLib_C_uwInvalidPosition ;
return ulPlayerIdReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetPlayerDescription
Retrieves the Player descriptor of the local player.
////////////////////////////////////////////////////////////////////////////////
Input : p_ucBufferLength : the length of the maximum player descriptor to be read
pPlayerDescrData : a buffer in which the player desriptor will be copied
ulPlayerId : the player concerned
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError : if no errors occured.
NetLib_E_es_NotEnoughMemory : if the buffer given was too short to contain the descriptor
NetLib_E_es_UnknownPlayerId : if the player id specified is unknown
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
Be aware to allocate the pPlayerDescrData buffer with enough size
(see ucGetPlayerDescriptorLength). If it does not have enough size, only
the number of bytes given by the first parameter are copied to the buffer.
When the functions returns, p_ucBufferLength contains the number of
bytes effectively read.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eGetPlayerDescription(NetLib_tduxDescriptionLength *p_ucBufferLength,tdpPointer pPlayerDescrData,NetLib_tduxPlayerId ulPlayerId)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstPlayerInfo *p_stThePlayer;
if (ulPlayerId==C_uxNetInvalidId) return NetLib_E_es_UnknownPlayerId;
if((p_stThePlayer = pstNetGetPlayerSlot(ulPlayerId))==0)
return NetLib_E_es_UnknownPlayerId;
if(p_stThePlayer->uxPlayerDescriptionLength<=*p_ucBufferLength)
{
*p_ucBufferLength = p_stThePlayer->uxPlayerDescriptionLength;
eErrorReturned = NetLib_E_es_NoError;
}
else eErrorReturned = NetLib_E_es_NotEnoughMemory;
if(*p_ucBufferLength)
g_pfn_vNetMemcpy(pPlayerDescrData,p_stThePlayer->pPlayerDescriptionData,*p_ucBufferLength);
return eErrorReturned;
}
/*///////////////////////////////////////////////////////////////////////////////
Description : NetLib_uxGetPlayerDescriptionLength
Returns the length of the Player 's descriptor specified by the parameter
////////////////////////////////////////////////////////////////////////////////
Input : ulPlayerId : the player concerned
////////////////////////////////////////////////////////////////////////////////
Output : The length of the session descriptor
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
If the player given in parameter is not found, the function returns 0. be careful
because if the player does not have a player descriptor, it also returns 0
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxDescriptionLength _NET_CALLING_CONV_ NetLib_uxGetPlayerDescriptionLength(NetLib_tduxPlayerId ulPlayerId)
{
NetLib_tdstPlayerInfo *p_stThePlayer;
p_stThePlayer = pstNetGetPlayerSlot(ulPlayerId);
if(p_stThePlayer) return p_stThePlayer->uxPlayerDescriptionLength;
else return 0;
}
/* Get a parameter in a string. */
static void getStringParam(char *string,char *clef,char *valor,unsigned short sizeval)
{
char *deb,*fin;
unsigned short s;
if (string)
{
deb=strstr(string,clef);
if (deb)
{
deb=strchr(deb+1,'\'');
if (deb++)
{
fin=strchr(deb+1,'\'');
if (fin)
{
s=fin-deb;
if (s>sizeval-1) s=sizeval-1;
memcpy(valor,deb,s);
valor[s]=0;
return;
}
}
}
}
*valor=0;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetPlayerName
Retrieves the player name.
////////////////////////////////////////////////////////////////////////////////
Input : ulPlayerId : the player concerned
Output : NULL : if errors occured.
adress of options otherwise.
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_eGetPlayerName(NetLib_tduxPlayerId ulPlayerId,char *Name,unsigned short SizeMaxName)
{
NetLib_tdstPlayerInfo *p_stThePlayer;
if ((p_stThePlayer=pstNetGetPlayerSlot(ulPlayerId))==NULL) return;
getStringParam(p_stThePlayer->Options,"name",Name,SizeMaxName);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetGameName
Retrieves the game name.
////////////////////////////////////////////////////////////////////////////////
Input : none.
Output : NULL : if errors occured.
adress of options otherwise.
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_eGetGameName(char *Name,unsigned short SizeMaxName)
{
getStringParam(gs_stCurrentSession.GameOptions,"name",Name,SizeMaxName);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_ulTellRemoteTimerValue
gives the estimated value of a remote player's timer for a given local time.
////////////////////////////////////////////////////////////////////////////////
Input : ulRemoteId: the remote player's id
ulLocalTimerValue: the local time
////////////////////////////////////////////////////////////////////////////////
Output : 0 if the remote player is unknown
the local time if the specified player is the local player
else another time
////////////////////////////////////////////////////////////////////////////////
Creation date : July 2,1996
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdulTimeInfo _NET_CALLING_CONV_ NetLib_ulTellRemoteTimerValue(NetLib_tduxPlayerId ulRemoteId, NetLib_tdulTimeInfo ulLocalTimerValue)
{
unsigned short c_uwCurrentIndex;
if (ulRemoteId == C_uxNetInvalidId || !gs_d_stTimeDeltas) return 0;
else if (ulRemoteId == NetLib_uxGetOwnPlayerId()) return ulLocalTimerValue;
else
{
/* Retrieves the index of the remote player:*/
c_uwCurrentIndex = 0;
while ((c_uwCurrentIndex < gs_stCurrentSession.uwMaxNumberOfPlayers)
&& (gs_d_stTimeDeltas[c_uwCurrentIndex].ulPlayerId != ulRemoteId))
{
c_uwCurrentIndex ++;
}
/* if we found a corresponding player in our database */
if (c_uwCurrentIndex < gs_stCurrentSession.uwMaxNumberOfPlayers)
{
NetLib_tdulTimeInfo res=ulLagUnitsToTimeInfo(ulTimeInfoToLagUnits(ulLocalTimerValue, gs_ulLocalTimeScale)
- (long)gs_d_stTimeDeltas[c_uwCurrentIndex].dDeltaWithLocal,
gs_d_stTimeDeltas[c_uwCurrentIndex].ulScaleOfRecipient);
#if defined(NET_USE_DEBUG)
vDebugSI(Net_C_Debug_NetSer,"Estimate",res);
#endif /* NET_USE_DEBUG */
return res;
}
else return 0;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_ulTellRemotePlayerLag
gives the estimated value of a remote player's latency in local time info value
////////////////////////////////////////////////////////////////////////////////
Input : ulRemoteId: the remote player's id
////////////////////////////////////////////////////////////////////////////////
Output : 0 if the remote player is unknown or the local player
else another time
////////////////////////////////////////////////////////////////////////////////
Creation date : July 4,1996
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdulTimeInfo _NET_CALLING_CONV_ NetLib_ulTellRemotePlayerLag(NetLib_tduxPlayerId ulRemoteId,unsigned short *pNumberOfReplies)
{
unsigned short c_uwCurrentIndex;
if (pNumberOfReplies) *pNumberOfReplies=0;
if ((ulRemoteId==C_uxNetInvalidId) || (ulRemoteId==NetLib_uxGetOwnPlayerId()) ||
!gs_d_stTimeDeltas) return 0;
c_uwCurrentIndex = 0;
while ((c_uwCurrentIndex<gs_stCurrentSession.uwMaxNumberOfPlayers)
&& (gs_d_stTimeDeltas[c_uwCurrentIndex].ulPlayerId != ulRemoteId))
{
c_uwCurrentIndex ++;
}
/* if we found a corresponding player in our database */
if (c_uwCurrentIndex < gs_stCurrentSession.uwMaxNumberOfPlayers)
{
if (pNumberOfReplies) *pNumberOfReplies=gs_d_stTimeDeltas[c_uwCurrentIndex].NumberOfRetries;
return ulLagUnitsToTimeInfo(gs_d_stTimeDeltas[c_uwCurrentIndex].ulLatency, gs_ulLocalTimeScale);
}
else return 0;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eAcceptWithoutListening
Gets the flag gs_ucAcceptWithoutListening
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_C_ucAcceptWithoutListening: a connection is accepted without a listening
call occured
NetLib_C_ucListenForAccept: a connection is accepted only after a listening call
occured
////////////////////////////////////////////////////////////////////////////////
Creation date : July 9, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eAcceptWithoutListening(void)
{
switch(gs_ucAcceptWithoutListening)
{
case NetLib_C_ucAcceptWithoutListening:
return NetLib_E_es_True;
case NetLib_C_ucListenForAccept:
return NetLib_E_es_False;
default :
return NetLib_E_es_UnknownError;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : uwNetGetPlayerIndex
retrieves the index of a player
////////////////////////////////////////////////////////////////////////////////
Input : A player id
////////////////////////////////////////////////////////////////////////////////
Output : An index if the player is found
otherwise NetLib_C_uwInvalidPosition
////////////////////////////////////////////////////////////////////////////////
Creation date : September 6, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
unsigned short _NET_CALLING_CONV_ uwNetGetPlayerIndex(NetLib_tduxPlayerId ulPlayerId)
{
unsigned short c_uwCount;
c_uwCount = gs_stCurrentSession.uwMaxNumberOfPlayers-1;
while ((c_uwCount!=NetLib_C_uwInvalidPosition)
&&(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount])!=ulPlayerId))
c_uwCount--;
return c_uwCount;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : pstNetGetPlayerSlot
Returns a pointer to the slot of the player
////////////////////////////////////////////////////////////////////////////////
Input : A player id
////////////////////////////////////////////////////////////////////////////////
Output : a pointer if the player is found
otherwise Null
////////////////////////////////////////////////////////////////////////////////
Creation date : September 6, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdstPlayerInfo * _NET_CALLING_CONV_ pstNetGetPlayerSlot(NetLib_tduxPlayerId ulPlayerId)
{
unsigned short c_uwCount;
if((c_uwCount = uwNetGetPlayerIndex(ulPlayerId))!=NetLib_C_uwInvalidPosition)
return &(gs_stCurrentSession.d_stPlayerInfo[c_uwCount]);
else
return (NetLib_tdstPlayerInfo * )C_pNull;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : pstNetGetOwnPlayerSlot
Returns a pointer to the slot of the local player
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : a pointer if the player is found
otherwise Null
////////////////////////////////////////////////////////////////////////////////
Creation date : September 23, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdstPlayerInfo * _NET_CALLING_CONV_ pstNetGetOwnPlayerSlot(void)
{
if(gs_stCurrentSession.uwIndexOfLocalPlayer<=gs_stCurrentSession.uwMaxNumberOfPlayers)
return &gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer];
else
return (NetLib_tdstPlayerInfo * )C_pNull;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_eCopystPlayerInfo
////////////////////////////////////////////////////////////////////////////////
Input : a dest and a source
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus NetLib_eCopystPlayerInfo(NetLib_tdstPlayerInfo *p_stDest,NetLib_tdstPlayerInfo *p_stSrc)
{
memcpy(p_stDest,p_stSrc,sizeof(NetLib_tdstPlayerInfo));
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : void vNetClearSessionInfo
Clear differents pointer of the object given in parameter
////////////////////////////////////////////////////////////////////////////////
Input : pSessionToClear : a pointer to the session to clear
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
This function frees the memory used for :
-> the session information
-> the player information for each player
-> the player information array.
//////////////////////////////////////////////////////////////////////////////*/
void vNetClearSessionInfo(NetLib_tdstSessionInfo *pSessionToClear)
{
unsigned short c_uwCount;
if(pSessionToClear /*!=(NetLib_tdstSessionInfo*)C_pNull*/)
{
pSessionToClear->uxSessionId=C_uxNetInvalidId;
pSessionToClear->uxSessionDescriptionLength = 0;
if(pSessionToClear->pSessionDescriptionData /*!=(tdpPointer)C_pNull*/)
{
vFree((tdpPointer)pSessionToClear->pSessionDescriptionData);
pSessionToClear->pSessionDescriptionData = (tdpPointer)C_pNull;
}/* End of if(pSessionToClear->pSessionDescriptionData !=C_pNull)*/
if(pSessionToClear->d_stPlayerInfo /*!=(NetLib_tdstPlayerInfo*)C_pNull*/)
{
/* Clear players informations*/
/* First Player descriptions*/
for(c_uwCount = 0; c_uwCount < pSessionToClear->uwMaxNumberOfPlayers; c_uwCount++)
{
pSessionToClear->d_stPlayerInfo[c_uwCount].uxPlayerDescriptionLength = 0;
if(pSessionToClear->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData /*!=(tdpPointer)C_pNull*/)
{
vFree((tdpPointer)pSessionToClear->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData);
pSessionToClear->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData = (tdpPointer)C_pNull;
}/* End of if(pSessionToClear.d_stPlayerInfo[c_uwCount]...*/
}/* end of for */
/* Now clear the array of playerInfo :*/
vFree((tdpPointer)pSessionToClear->d_stPlayerInfo);
pSessionToClear->d_stPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
}/* end of if(pSessionToClear.d_stPlayerInfo != C_pNull) */
pSessionToClear->uwNumberOfPlayers = 0;
pSessionToClear->uwMaxNumberOfPlayers = 0;
pSessionToClear->uwIndexOfLocalPlayer = (unsigned short)-1;
}/* End of if(pSessionToClear != C_pNull) */
}/* End of function */
/*
------------------------------------------------------------------------------------------
GETTING SESSIONS :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eOpenGetActiveSessions
Opens the request session mode
////////////////////////////////////////////////////////////////////////////////
Input : uwNumberOfSessionWaited : the number of session expected
////////////////////////////////////////////////////////////////////////////////
Output : An error code or NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 19,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eOpenGetActiveSessions(unsigned short uwNumberOfSessionWaited,
NetLib_tdulTimeInfo ulFreq,NetLib_tduxDescriptionLength ucMaxPlayerInfo)
{
unsigned short c_uwCount;
if(!uwNumberOfSessionWaited) return NetLib_E_es_ShouldNotReach;
/* Erase previous data :*/
/* Previous sessions found :*/
NetLib_eCloseAndResetGetActiveSessions();
/* Reinit :*/
gs_eListeningMode = E_Net_LisMod_ON;
if(eNetAddEngineFunction(iNetEngineGetActiveSession)!=NetLib_E_es_NoError)
{
NetLib_eCloseAndResetGetActiveSessions();
return NetLib_E_es_NotEnoughMemory;
}
gs_dstSessions = (NetLib_tdstSessionInfo *)pMalloc(sizeof(NetLib_tdstSessionInfo)*uwNumberOfSessionWaited);
gs_dpucWaitForReply = (unsigned char *)pMalloc(sizeof(unsigned char)*uwNumberOfSessionWaited);
if (!(gs_dstSessions /*!=(NetLib_tdstSessionInfo*)C_pNull*/) ||
!(gs_dpucWaitForReply /*!= (unsigned char**)C_pNull*/))
{
NetLib_eCloseAndResetGetActiveSessions();
return NetLib_E_es_NotEnoughMemory;
}
gs_uwNumberOfSessionsExpected = uwNumberOfSessionWaited;
/* there was enough memory :*/
/* Initialize the array :*/
for(c_uwCount = 0; c_uwCount < uwNumberOfSessionWaited;c_uwCount++)
{
gs_dstSessions[c_uwCount].uxSessionId=C_uxNetInvalidId;
gs_dstSessions[c_uwCount].uxSessionDescriptionLength=0;
gs_dstSessions[c_uwCount].pSessionDescriptionData=(tdpPointer)C_pNull;
gs_dstSessions[c_uwCount].uwMaxNumberOfPlayers = 0;
gs_dstSessions[c_uwCount].uwNumberOfPlayers = 0;
gs_dstSessions[c_uwCount].d_stPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_dstSessions[c_uwCount].uwIndexOfLocalPlayer = (unsigned short)-1;
gs_dpucWaitForReply[c_uwCount] = 0;
}
gs_uxMaxPlayerInfo=ucMaxPlayerInfo;
eLevel1SendSessionRequestMsg(gs_uxMaxPlayerInfo);
gs_tm_ulGetActiveSessionsFreq = ulFreq;
gs_tm_ulPrevGetActiveSessions = g_pfn_ulNetGetTimeInfo();
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eGetSessionsFound
Checks for the sessions found
////////////////////////////////////////////////////////////////////////////////
Input : *p_uwNumberOfSessionWaited : the number of session expected
**pd_stSessionInfoFound : pointer to an array of session description containing
the sessions found.
////////////////////////////////////////////////////////////////////////////////
Output : An error code or NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 19,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
The pointer may be temporary and should not be stored for later use...
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eGetSessionsFound(unsigned short *p_uwNumberOfSessionWaited,NetLib_tdstSessionInfo **pd_stSessionInfoFound)
{
unsigned short c_uwCount;
if (!gs_dpucWaitForReply || !gs_dstSessions)
{
*p_uwNumberOfSessionWaited = 0;
*pd_stSessionInfoFound = (NetLib_tdstSessionInfo*)C_pNull;
return NetLib_E_es_UnknownError;
}
*p_uwNumberOfSessionWaited = 0;
for(c_uwCount = 0;c_uwCount <gs_c_uwNumberOfSessionsDetected;c_uwCount++)
{
if(gs_dpucWaitForReply[c_uwCount])
{
(*p_uwNumberOfSessionWaited)++;
}
}
*pd_stSessionInfoFound = gs_dstSessions;
/* if(*p_uwNumberOfSessionWaited<gs_uwNumberOfSessionsExpected)
{*/
if(*p_uwNumberOfSessionWaited==gs_c_uwNumberOfSessionsDetected)
return NetLib_E_es_FoundLessThanRequest;
else
{
*p_uwNumberOfSessionWaited=gs_c_uwNumberOfSessionsDetected;
return NetLib_E_es_ShouldWait;
}
/* }
else return NetLib_E_es_NoError;*/
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eCloseGetActiveSessions
Closes the GetActiveSessions Process. Does not erase the array of the sessions
found.
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 30,96
Author : Albert Pa<50>s
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eCloseGetActiveSessions(void)
{
tdeNetMessageType eMsgType;
/* Stop listening */
eNetRemoveEngineFunction(iNetEngineGetActiveSession);
gs_eListeningMode = E_Net_LisMod_OFF;
/*Clear data:*/
if(gs_dpucWaitForReply)
{
vFree((tdpPointer)gs_dpucWaitForReply);
gs_dpucWaitForReply = C_pNull;
}
gs_uwNumberOfSessionsExpected = 0;
/* if sending and receiving lists contains previous msgs, clear them*/
eMsgType = E_Net_mt_SysRequestActiveSessions;
eNetLevel1EraseAllMessages(C_uxNetSystemId,C_GetNbrMsg_OUTGOING,eNetIsMessageType,(void*)(&eMsgType));
return NetLib_E_es_NoError;
}
/*///////////////////////////////////////////////////////////////////////////////
Description : NetLib_eCloseAndResetGetActiveSessions
Closes the GetActiveSessions Process. Erase the array of the sessions
found.
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 30,96
Author : Albert Pa<50>s
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eCloseAndResetGetActiveSessions(void)
{
unsigned short c_uwCount;
tdeNetMessageType eMsgType;
if(gs_dstSessions)
{
for(c_uwCount = 0; c_uwCount <gs_c_uwNumberOfSessionsDetected; c_uwCount++)
vNetClearSessionInfo(gs_dstSessions+c_uwCount);
vLevel1DestroySessionCellList();
vFree((tdpPointer)gs_dstSessions);
gs_dstSessions = (NetLib_tdstSessionInfo *)C_pNull;
}
NetLib_eCloseGetActiveSessions();
eMsgType = E_Net_mt_SysRequestActiveSessionsReply;
eNetLevel1EraseAllMessages(C_uxNetSystemId,C_GetNbrMsg_INCOMING,eNetIsMessageType,(void*)(&eMsgType));
gs_c_uwNumberOfSessionsDetected = 0;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetGetActiveSessions
Returns the number of Sessions found in the net and an array of
NetLib_tdstSessionInfo containing information about each game.
////////////////////////////////////////////////////////////////////////////////
Input : p_uwNumberOfSessionWaited : the maximum number of session expected. When the
functions returns, it contains the number of session effectively found.
pd_stSessionInfoFound : a pointer to an array of NetLib_tdstSessionInfo that contains
for each session informations about it.
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_TimeOut if time out
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pa<50>s
////////////////////////////////////////////////////////////////////////////////
Comment : The pointer may be temporary and should not be stored for later use...
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eGetActiveSessions(unsigned short *p_uwNumberOfSessionWaited,NetLib_tdstSessionInfo **pd_stSessionInfoFound,
NetLib_tdulTimeInfo ulMaxWaitingTime,NetLib_tduxDescriptionLength ucMaxPlayerInfo)
{
NetLib_tdeErrorStatus eErrorReturned;
tdstNetBlockingLoopDescription stLoopDesc;
tdstNetGetActiveLoopDesc stGetActiveLoopDesc;
/* Open the getactive session processus*/
eErrorReturned = NetLib_eOpenGetActiveSessions(*p_uwNumberOfSessionWaited,500,ucMaxPlayerInfo);
/* Init return values :*/
*p_uwNumberOfSessionWaited = 0;
*pd_stSessionInfoFound = (NetLib_tdstSessionInfo*)C_pNull;
/* If an error occured, close the processus */
if(eErrorReturned !=NetLib_E_es_NoError)
{
NetLib_eCloseAndResetGetActiveSessions();
return eErrorReturned;
}
/* Now waiting for either *p_uwNumberOfSessionWaited session or time out :*/
stLoopDesc.m_ulMaxWaitingTime = ulMaxWaitingTime;
stLoopDesc.m_eGoOnCondition = NetLib_E_es_FoundLessThanRequest;
stLoopDesc.m_pfn_eEvaluation = eNetGetActiveSessionsCompleted;
stGetActiveLoopDesc.m_pd_stSessionInfoFound = pd_stSessionInfoFound;
stGetActiveLoopDesc.m_p_uwNumberOfSessionWaited =p_uwNumberOfSessionWaited;
stLoopDesc.m_lParam = (long)&stGetActiveLoopDesc;
eErrorReturned = NetLib_eBlockingLoop(&stLoopDesc);
NetLib_eGetSessionsFound(p_uwNumberOfSessionWaited,pd_stSessionInfoFound);
/*
Stop listening mode:
*/
NetLib_eCloseGetActiveSessions();
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetGetActiveSessionsCompleted
Check if a get active sessions operation is completed or not
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a tdstNetGetActiveLoopDesc cast in void *
////////////////////////////////////////////////////////////////////////////////
Output : the return value of NetLib_eGetSessionsFound
////////////////////////////////////////////////////////////////////////////////
Creation date : August 30,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetGetActiveSessionsCompleted(long lParam)
{
tdstNetGetActiveLoopDesc *p_stGetActiveLoopDesc;
unsigned short nbrSession;
NetLib_tdeErrorStatus eErrorReturned;
p_stGetActiveLoopDesc = (tdstNetGetActiveLoopDesc *)lParam;
nbrSession=*(p_stGetActiveLoopDesc->m_p_uwNumberOfSessionWaited);
eErrorReturned=NetLib_eGetSessionsFound(&nbrSession,p_stGetActiveLoopDesc->m_pd_stSessionInfoFound);
if (gs_c_uwNumberOfSessionsDetected==gs_uwNumberOfSessionsExpected)
{
return NetLib_E_es_NoError;
}
else return NetLib_E_es_FoundLessThanRequest;
}
/*
------------------------------------------------------------------------------------------
CONNECTING TO A SESSION :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eNetConnectToSession
Ask a session for a connection
////////////////////////////////////////////////////////////////////////////////
Input :
ulIdSessionWanted : the id of the session to witch the connection is wanted
uwMaxWaitingTime
d_ucWaitForListen : an array of NumberOfPlayer size, if the slot iSlot is set to
a non zero value, the connection wait for a listen of the corresponding player
Otherwise if the slot is 0, the connection does not wait for a listen, and the
remote player take considers the new player as a playe of the session
////////////////////////////////////////////////////////////////////////////////
Output :
NetLib_E_es_NoError if no error occured
NetLib_E_es_UnknownSessionId if the Id specified is unknown
NetLib_E_es_ServiceNotYetProvided if the number of player in the current session is greater
than one.
NetLib_E_es_NotEnoughMemory if there was not enough memory to finish the function. In
that case, some data in the sessio description may be lost...
NetLib_E_es_ConnectionFailure if the connection fails. In that case, some data in
the session description are lost. Must ask for sessions avaible
before starting a new connection
NetLib_E_es_TimeOut : a time out occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 3-4,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
This function makes a connection between the player and the session specified
by the argument. If it succeed, some changes occurs :
-> the id of the local session is set to the one to witch the connection is done
-> the session description length is set to the one to witch the connection is done
-> the session description data is set to the one to witch the connection is done
-> the max number of players is set to the one to witch the connection is done
-> the effective number of players is set to the one to witch the connection is done +1
-> the id of the local player may change
-> the index of the local player is correctly set.
////////////////////////////////////////////////////////////////////////////////
WARNING :
This functions only provides connection from a session of one player to a session
of n players. It does not yet provide connection from a session of m players
to a session of n players. This will may be done later...
Such a protocol can be developped by the program.
////////////////////////////////////////////////////////////////////////////////
Modification date : April 9,96
Author : Alber Pa<50>s
Modification : Adding time out managing
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eConnectToSession(NetLib_tdstConnectDesc *p_stConnectDesc)
{
NetLib_tdeErrorStatus eErrorReturned;
unsigned short c_uwSessionChosen;
unsigned short c_uwCount;
NetLib_tduxPlayerId ulNewPlayerId;
tdstNetConnectLoopDesc stConnLoopDesc;
tdstNetBlockingLoopDescription stLoopDesc;
NetLib_eCloseGetActiveSessions();
/* Search for the session concerned :*/
c_uwSessionChosen = gs_c_uwNumberOfSessionsDetected;
for(c_uwCount = 0; c_uwCount <gs_c_uwNumberOfSessionsDetected; c_uwCount++)
{
if(gs_dstSessions[c_uwCount].uxSessionId ==p_stConnectDesc->m_uxSessionId)
c_uwSessionChosen = c_uwCount;
else vNetClearSessionInfo(&gs_dstSessions [c_uwCount]);
}/* End for */
if(c_uwSessionChosen >= gs_c_uwNumberOfSessionsDetected)
{
/* Destroy information in level 1 since they have been destroyed in level 2*/
vLevel1DestroySessionCellList();
vFree((tdpPointer)gs_dstSessions);
gs_dstSessions = (NetLib_tdstSessionInfo *)C_pNull;
return NetLib_E_es_UnknownSessionId;
}
/* A session has been found :*/
if(gs_stCurrentSession.uwNumberOfPlayers > 1)
{/* we do not still ensure this service */
vNetClearSessionInfo(&gs_dstSessions[c_uwSessionChosen]);
vFree((tdpPointer)gs_dstSessions);
gs_dstSessions = (NetLib_tdstSessionInfo *)C_pNull;
vLevel1DestroySessionCellList();
return NetLib_E_es_ServiceNotYetProvided;
}
/*Initialize global object for the connection :*/
/* First the tstSessionInfo object : gs_stConnectRequestSessionInfo */
/* if it contains some thing : clear it*/
if(gs_p_stConnectRequestSessionInfo /*!= (NetLib_tdstSessionInfo*)C_pNull*/)
{/* Should not occured but...*/
vNetClearSessionInfo(gs_p_stConnectRequestSessionInfo);
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo);
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo*)C_pNull;
}/* End of if(gs_p_stConnectRequestSessionInfo != C_pNull)*/
/* Builds a new Session info object :*/
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo*)pMalloc(sizeof(NetLib_tdstSessionInfo));
if(!gs_p_stConnectRequestSessionInfo)
{/*there was not enouth memory to create gs_p_stConnectRequestSessionInfo */
vNetClearSessionInfo(&gs_dstSessions[c_uwSessionChosen]);
vFree((tdpPointer)gs_dstSessions);
gs_dstSessions = (NetLib_tdstSessionInfo *)C_pNull;
vLevel1DestroySessionCellList();
return NetLib_E_es_NotEnoughMemory;
}
/* the id of the session : */
gs_p_stConnectRequestSessionInfo->uxSessionId=gs_dstSessions[c_uwSessionChosen].uxSessionId ;
/* the session information length :*/
gs_p_stConnectRequestSessionInfo->uxSessionDescriptionLength=gs_dstSessions[c_uwSessionChosen].uxSessionDescriptionLength;
/* the session information data*/
gs_p_stConnectRequestSessionInfo->pSessionDescriptionData=gs_dstSessions[c_uwSessionChosen].pSessionDescriptionData;
/* the max number of players :*/
gs_p_stConnectRequestSessionInfo->uwMaxNumberOfPlayers=gs_dstSessions[c_uwSessionChosen].uwMaxNumberOfPlayers;
/* the number of effective players */
gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers=gs_dstSessions[c_uwSessionChosen].uwNumberOfPlayers;
/* the array of player information :*/
gs_p_stConnectRequestSessionInfo->d_stPlayerInfo=gs_dstSessions[c_uwSessionChosen].d_stPlayerInfo;
/* the index of the local player : normaly at -1 */
gs_p_stConnectRequestSessionInfo->uwIndexOfLocalPlayer=gs_dstSessions[c_uwSessionChosen].uwIndexOfLocalPlayer;
/* Now erase the gs_dstSessions array :
The pointers d_stPlayerInfo and pSessionDescriptionData of the
gs_dstSessions[c_uwSessionChosen] are not deleted since
the gs_p_stConnectRequestSessionInfo uses them */
vFree((tdpPointer)gs_dstSessions );
gs_dstSessions = (NetLib_tdstSessionInfo*)C_pNull;
/* Redraw a new player id if necessary */
ulNewPlayerId=NetLib_uxGetOwnPlayerId();
c_uwCount = 0;
while(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
while ((c_uwCount<gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers) &&
(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount])
!=ulNewPlayerId)) c_uwCount++;
if(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
/* It means that the id is the same with one of the players in the session :*/
ulNewPlayerId = ulNetGetNewPlayerId();
vNetSetOwnPlayerId(ulNewPlayerId);
c_uwCount = 0;
}/* End if(c_uwCount..*/
}/*while(b_ucDone < 2)*/
/* Initialize gs_d_tdeConnectRequestStatusArray :*/
if(gs_d_tdeConnectRequestStatusArray /*!= (tdeConnectRequestStatus*)C_pNull*/)
/* It is not set to null because it is reallocated just after :*/
vFree((tdpPointer)gs_d_tdeConnectRequestStatusArray);
gs_d_tdeConnectRequestStatusArray=(tdeNetConnectRequestStatus*)
pMalloc(sizeof(tdeNetConnectRequestStatus)*gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers);
if(!gs_d_tdeConnectRequestStatusArray)
{ /* There was not enough memory to create gs_d_tdeConnectRequestStatusArray */
/* Cancel the connection*/
vNetClearSessionInfo(gs_p_stConnectRequestSessionInfo);
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo);
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo*)C_pNull;
gs_c_uwNumberOfSessionsDetected = 0;
vLevel1DestroySessionCellList();
return NetLib_E_es_NotEnoughMemory;
}
for(c_uwCount=0;c_uwCount<gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers;c_uwCount++)
gs_d_tdeConnectRequestStatusArray[c_uwCount] = E_Net_ConReqSta_Todo;
/* Update level 1 informations */
eLevel1StripSessionList(p_stConnectDesc->m_uxSessionId);
/* FIRST STEP :*/
/* Wait for all remote players reply to a connection request */
stLoopDesc.m_ulMaxWaitingTime = p_stConnectDesc->m_ulMaxWaitingTime;
stLoopDesc.m_eGoOnCondition = NetLib_E_es_OperationInProgress;
stLoopDesc.m_pfn_eEvaluation = eNetConnectionCompleted;
stConnLoopDesc.m_ulPrevTimeInfo = 0;
stConnLoopDesc.m_ulFreq = p_stConnectDesc->m_ulMaxWaitingTime/REPEAT_COUNT;
stLoopDesc.m_lParam = (long)&stConnLoopDesc;
eErrorReturned = NetLib_eBlockingLoop(&stLoopDesc);
if(eErrorReturned==NetLib_E_es_NoError)
{
/* SECOND STEP :*/
/* Wait for all remote players make a listen */
stLoopDesc.m_ulMaxWaitingTime = p_stConnectDesc->m_ulMaxWaitingTime;
stLoopDesc.m_eGoOnCondition = NetLib_E_es_OperationInProgress;
stLoopDesc.m_pfn_eEvaluation = eNetListeningCompleted;
stConnLoopDesc.m_ulPrevTimeInfo = 0;
stConnLoopDesc.m_ulFreq = p_stConnectDesc->m_ulMaxWaitingTime/REPEAT_COUNT;
stLoopDesc.m_lParam = (long)&stConnLoopDesc;
eErrorReturned = NetLib_eBlockingLoop(&stLoopDesc);
if(eErrorReturned == NetLib_E_es_NoError)
{
/* LAST STEP :*/
/* Connection succedd : Set data : */
/* Initialise local player informations :*/
NetLib_eCopystPlayerInfo(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers],
pstNetGetPlayerSlot(NetLib_uxGetOwnPlayerId()));
/* initialize the "internet mark" for the local player */
gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers].m_bOverInternet=0;
vNetSetSessionId(gs_p_stConnectRequestSessionInfo->uxSessionId);
gs_stCurrentSession.uxSessionDescriptionLength=gs_p_stConnectRequestSessionInfo->uxSessionDescriptionLength;
if(gs_stCurrentSession.pSessionDescriptionData!=(tdpPointer)C_pNull) vFree(gs_stCurrentSession.pSessionDescriptionData);
gs_stCurrentSession.pSessionDescriptionData = gs_p_stConnectRequestSessionInfo->pSessionDescriptionData;
gs_stCurrentSession.uwMaxNumberOfPlayers = gs_p_stConnectRequestSessionInfo->uwMaxNumberOfPlayers;
gs_stCurrentSession.uwNumberOfPlayers = gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers + 1;
/* List of player info*/
vFree((tdpPointer)gs_stCurrentSession.d_stPlayerInfo);
gs_stCurrentSession.d_stPlayerInfo = gs_p_stConnectRequestSessionInfo->d_stPlayerInfo;
/* Index of local player :*/
gs_stCurrentSession.uwIndexOfLocalPlayer = gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers;
/* Clear all that must be cleared :*/
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo);
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo*)C_pNull;
vFree((tdpPointer)gs_d_tdeConnectRequestStatusArray);
gs_d_tdeConnectRequestStatusArray = (tdeNetConnectRequestStatus*)C_pNull;
gs_c_uwNumberOfSessionsDetected = 0;
eNetSendTCPAddress(); /* Send TCPAddress. */
return eErrorReturned;
}
}
if(eErrorReturned != NetLib_E_es_NoError)
{
/* Cancel the connection :*/
eNetCancelConnection();
/* Send message :*/
NetLib_eFlushSendingList(p_stConnectDesc->m_ulMaxWaitingTime);
/* Clear all that must be cleared :*/
for(c_uwCount=0;c_uwCount<gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers;c_uwCount++)
{
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData);
/* It is no used since all will be destroyed :
gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData = (tdpPointer)C_pNull; */
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]));
}
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo->pSessionDescriptionData);
/* Not necessary : gs_p_stConnectRequestSessionInfo->pSessionDescriptionData = (tdpPointer)C_pNull; */
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo->d_stPlayerInfo);
/* Not necessary : gs_p_stConnectRequestSessionInfo->d_stPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull; */
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo);
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo*)C_pNull;
vFree((tdpPointer)gs_d_tdeConnectRequestStatusArray);
gs_d_tdeConnectRequestStatusArray = (tdeNetConnectRequestStatus*)C_pNull;
gs_c_uwNumberOfSessionsDetected = 0;
/* the param deny :*/
p_stConnectDesc->m_lConDenyParam = gs_lConDenyParam;
gs_lConDenyParam = 0;
vLevel1DestroySessionCellList();
}/*End of if(eErrorReturned != NetLib_E_es_NoError)*/
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eNetSendAcknowledgementMessage(void)
Sends an agreement msg to all remote players that have not still reply
with a LISTENED msg.
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 14,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetSendAcknowledgementMessage(void)
{
unsigned short c_uwCount;
tdstNetMessage *p_stConnectRequestMessage;
NetLib_tdeErrorStatus eErrorReturned;
c_uwCount = 0;
while(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
if ((M_ulNetPlayerIdSlot(&(gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]))
!= C_uxNetInvalidId) &&
(gs_d_tdeConnectRequestStatusArray[c_uwCount]!=E_Net_ConReqSta_Listened))
{
p_stConnectRequestMessage=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+1);
if(p_stConnectRequestMessage)
{
p_stConnectRequestMessage->uxRecipientId=M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]);
p_stConnectRequestMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stConnectRequestMessage->eMessageType = E_Net_mt_SysConnectAcknowledgement;
p_stConnectRequestMessage->uwMessageSizeInBytes = 1;
p_stConnectRequestMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stConnectRequestMessage->uxReplaceType = 0;
p_stConnectRequestMessage->uxReplace = 0;
*((char *)(p_stConnectRequestMessage+1))=0; /* Flag for direct route.*/
if(gs_ArtificialLatency)
eErrorReturned=eInternetSimuSendMessage(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]),
p_stConnectRequestMessage);
else eErrorReturned=eLevel1SendMessage(p_stConnectRequestMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned ==NetLib_E_es_NoError) c_uwCount++;
else vFree((tdpPointer)p_stConnectRequestMessage);
}
}
else c_uwCount++;
}/* End of while*/
return NetLib_E_es_NoError;
}
/*////////////////////////////////////////////////////////////////////////////////
Description : eNetSendConnectionRequestMessage
Sends an connect request msg to all remote players that have neither still reply
with a LISTENED msg nor with an agreement msg
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : August 14,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetSendConnectionRequestMessage(void)
{
unsigned short c_uwCount;
tdstNetMessage *p_stConnectRequestMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdpPointer pOriginData;
c_uwCount = 0;
while(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
if ((M_ulNetPlayerIdSlot(&(gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]))
!= C_uxNetInvalidId)
&&(gs_d_tdeConnectRequestStatusArray[c_uwCount]!=E_Net_ConReqSta_Done)
&&(gs_d_tdeConnectRequestStatusArray[c_uwCount]!=E_Net_ConReqSta_Listened))
{
p_stConnectRequestMessage = (tdstNetMessage*)pMalloc(
sizeof(tdstNetMessage)
+gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength
+sizeof(NetLib_tduxDescriptionLength)
+sizeof(NetLib_tducBigLittleEndian)
+sizeof(char)); /* the "via internet" mark */
if(p_stConnectRequestMessage)
{
p_stConnectRequestMessage->eMessageType = E_Net_mt_SysConnectRequest;
p_stConnectRequestMessage->uxRecipientId=M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]);
p_stConnectRequestMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stConnectRequestMessage->uwMessageSizeInBytes =
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength
+sizeof(NetLib_tduxDescriptionLength)+sizeof(NetLib_tducBigLittleEndian)+sizeof(char) /* the "via internet" mark */;
p_stConnectRequestMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stConnectRequestMessage->uxReplaceType = 0;
p_stConnectRequestMessage->uxReplace = 0;
/* Body :*/
pOriginData = (tdpPointer)(p_stConnectRequestMessage + 1);
/* The length of the player desription :*/
*((NetLib_tduxDescriptionLength*)pOriginData) =
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength;
pOriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)pOriginData + 1);
if(gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength)
{
/* The player description : */
g_pfn_vNetMemcpy(pOriginData,
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].pPlayerDescriptionData,
gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength);
}
pOriginData+=gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer].uxPlayerDescriptionLength;
*((NetLib_tducBigLittleEndian*)pOriginData) = NetLib_ucGetLittleBigEndian();
pOriginData = (tdpPointer) ( pOriginData+ sizeof(NetLib_tducBigLittleEndian) );
/* set the "via internet" mark */
if(eLevel1GoesToIP(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount])))
*((char *)pOriginData)=1;
else
*((char *)pOriginData)=0;
/* send the message */
if(gs_ArtificialLatency)
eErrorReturned=eInternetSimuSendMessage(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]),
p_stConnectRequestMessage);
else
eErrorReturned=eLevel1SendMessage(p_stConnectRequestMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned !=NetLib_E_es_NoError)
vFree((tdpPointer)p_stConnectRequestMessage);
}
}
c_uwCount++;
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetConnectionCompleted
Check if all the remote players answered to the connection request.
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a tdstNetConnectLoopDesc casted into a void*
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if completed
NetLib_E_es_OperationInProgress if not completed
NetLib_E_es_UnknownError if an error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : September 1,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetConnectionCompleted(long lParam)
{
unsigned short c_uwCount;
tdstNetConnectLoopDesc *p_stDescLoop;
p_stDescLoop = (tdstNetConnectLoopDesc *)lParam;
/* Ask for connection if necessary :*/
if(g_pfn_ulNetGetTimeInfo()-p_stDescLoop->m_ulPrevTimeInfo >= p_stDescLoop->m_ulFreq)
{
eNetSendConnectionRequestMessage();
p_stDescLoop->m_ulPrevTimeInfo = g_pfn_ulNetGetTimeInfo();
}
/* Check if it is not finished :*/
c_uwCount = 0;
while((c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)&&
((gs_d_tdeConnectRequestStatusArray[c_uwCount]==E_Net_ConReqSta_Done)||
(gs_d_tdeConnectRequestStatusArray[c_uwCount]==E_Net_ConReqSta_Listened)))
c_uwCount++;
/* Check if it is finished :*/
if(c_uwCount >=gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers) return NetLib_E_es_NoError;
/* Check if no error occured :*/
switch(gs_d_tdeConnectRequestStatusArray[c_uwCount])
{
case E_Net_ConReqSta_Invalid:
return NetLib_E_es_UnknownError;
case E_Net_ConReqSta_Refused:
return NetLib_E_es_ConnectionRemoteRefused;
case E_Net_ConReqSta_SessionChanged :
return NetLib_E_es_ConnectionSessionChanged;
case E_Net_ConReqSta_WaitBusy :
return NetLib_E_es_ConnectionWaitBusy;
};
return NetLib_E_es_OperationInProgress;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetListeningCompleted
Check if all the remote players have listened the player
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a tdstNetConnectLoopDesc casted into a void*
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if completed
NetLib_E_es_OperationInProgress if not completed
////////////////////////////////////////////////////////////////////////////////
Creation date : September 1,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetListeningCompleted(long lParam)
{
unsigned short c_uwCount;
tdstNetConnectLoopDesc *p_stDescLoop;
p_stDescLoop = (tdstNetConnectLoopDesc *)lParam;
c_uwCount = 0;
while ((c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)&&
(gs_d_tdeConnectRequestStatusArray[c_uwCount]==E_Net_ConReqSta_Listened))
c_uwCount++;
if(c_uwCount >= gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
return NetLib_E_es_NoError;
if(g_pfn_ulNetGetTimeInfo()-p_stDescLoop->m_ulPrevTimeInfo>=p_stDescLoop->m_ulFreq)
{
eNetSendAcknowledgementMessage();
p_stDescLoop->m_ulPrevTimeInfo = g_pfn_ulNetGetTimeInfo();
}
return NetLib_E_es_OperationInProgress;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eNetCancelConnection
Cancel a connection
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
An NetLib_tdeErrorStatus if an error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : June 13,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetCancelConnection(void)
{
unsigned short c_uwCount;
tdstNetMessage *p_stCancelMsg;
if(gs_p_stConnectRequestSessionInfo)
{
for(c_uwCount = 0; c_uwCount <gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers;c_uwCount++)
{
p_stCancelMsg = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage));
if(p_stCancelMsg)
{
if ((gs_d_tdeConnectRequestStatusArray)&&
(gs_d_tdeConnectRequestStatusArray[c_uwCount]==E_Net_ConReqSta_Listened))
p_stCancelMsg->eMessageType = E_Net_mt_SysDisconnection;
else p_stCancelMsg->eMessageType = E_Net_mt_SysConnectCancel;
p_stCancelMsg->uxRecipientId=M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]);
p_stCancelMsg->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stCancelMsg->uxPriority = NetLib_C_uxMaxPriority;
p_stCancelMsg->uxReplaceType = 0;
p_stCancelMsg->uxReplace = 0;
p_stCancelMsg->uwMessageSizeInBytes = 0;
if (gs_ArtificialLatency)
eInternetSimuSendMessage(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]),
p_stCancelMsg);
else
eLevel1SendMessage(p_stCancelMsg,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
}
}
}
return NetLib_E_es_NoError;
}
/*
------------------------------------------------------------------------------------------
LISTENING A PLAYER :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_eListenForRequest
Listen for a request of connection
When the functions returns, the parameter contain information about a new player
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to listening description structure
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
An error code otherwise
////////////////////////////////////////////////////////////////////////////////
Creation date : August 29,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eListenForRequest(NetLib_tdstListenDesc*p_stListenDesc)
{
tdstNetBlockingLoopDescription stListenLoopDesc;
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstPlayerInfo *p_stNewPlayerSlot;
NetLib_tdstSendDesc stSendDesc;
unsigned short c_uwCount;
char flagDirect=0; /* Direct route flag.*/
if (gs_uwMode==NetLib_Mode_Direct)
{
if(p_stListenDesc->m_ulMaxWaitingTime)
{
stListenLoopDesc.m_ulMaxWaitingTime = p_stListenDesc->m_ulMaxWaitingTime;
stListenLoopDesc.m_eGoOnCondition = NetLib_E_es_NoNewPlayer;
stListenLoopDesc.m_pfn_eEvaluation = eNetListenCompleted;
stListenLoopDesc.m_lParam = (long)C_pNull;
eErrorReturned = NetLib_eBlockingLoop(&stListenLoopDesc);
}
else eErrorReturned = eNetListenCompleted((long)C_pNull);
if(eErrorReturned != NetLib_E_es_NoError) return eErrorReturned;
p_stNewPlayerSlot = pstNetGetPlayerSlot(C_uxNetInvalidId);
if(!p_stNewPlayerSlot) return NetLib_E_es_ShouldNotReach;
/* Here we have a new player :*/
stSendDesc.m_tduxRecipientId = M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo);
stSendDesc.m_ulMaxWaitingTime = 0;
stSendDesc.m_pMessageData = &flagDirect;
stSendDesc.m_uwMessageLength =1;
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucNoReadReceipt;
eErrorReturned = eNetInternalSendMessage(&stSendDesc,E_Net_mt_SysConnectListened);
if(eErrorReturned !=NetLib_E_es_NoError) return eErrorReturned;
M_ulNetPlayerIdSlot(p_stNewPlayerSlot)=M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo);
NetLib_eCopystPlayerInfo(p_stNewPlayerSlot,gs_p_stPreSessionPlayerInfo);
gs_stCurrentSession.uwNumberOfPlayers ++;
/* free memory :*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
}
else
{
p_stNewPlayerSlot=NULL;
for (c_uwCount=0;c_uwCount<gs_stCurrentSession.uwMaxNumberOfPlayers;c_uwCount++)
{
if (M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount])!=C_uxNetInvalidId)
{
if (gs_stCurrentSession.d_stPlayerInfo[c_uwCount].wNewPlayer)
{
p_stNewPlayerSlot = &gs_stCurrentSession.d_stPlayerInfo[c_uwCount];
p_stNewPlayerSlot->wNewPlayer=0;
break;
}
}
}
if (p_stNewPlayerSlot==NULL) return NetLib_E_es_NoNewPlayer;
}
/* fill the parameter :*/
p_stListenDesc->m_uxPlayerId = M_ulNetPlayerIdSlot(p_stNewPlayerSlot);
p_stListenDesc->m_uxPlayerDescriptionLength = p_stNewPlayerSlot->uxPlayerDescriptionLength;
if ((p_stNewPlayerSlot->uxPlayerDescriptionLength) && (p_stListenDesc->m_pPlayerDescriptionData))
g_pfn_vNetMemcpy(p_stListenDesc->m_pPlayerDescriptionData,
p_stNewPlayerSlot->pPlayerDescriptionData,
p_stNewPlayerSlot->uxPlayerDescriptionLength);
else p_stListenDesc->m_pPlayerDescriptionData = C_pNull;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetCheckTimeOutOfPlayerConnected
Check if the timeout on a player who asked for a connection has run out
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment : If the time out has run out, then the gs_p_stPreSessionPlayerInfo is cleared
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetCheckTimeOutOfPlayerConnected(unsigned char b_ClearInfo)
{
if(gs_p_stPreSessionPlayerInfo /*!=(NetLib_tdstPlayerInfo*)C_pNull*/)
{
if ((g_pfn_ulNetGetTimeInfo) && (gs_tm_ulPreSessionPlayerMaxWaitingTime) &&
(gs_tm_ulPreSessionPlayerTimer + gs_tm_ulPreSessionPlayerMaxWaitingTime < (*g_pfn_ulNetGetTimeInfo)()))
{
if(b_ClearInfo)
{
/* time out occured, so close connection with player and free memory :*/
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
/* Free memory :*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
/* Not necessary :
gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData = (tdpPointer)C_pNull;
*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
}
return NetLib_E_es_TimeOutExpired;
}
return NetLib_E_es_TimeOutNotExpired;
}
return NetLib_E_es_NoNewPlayer;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eNetListenCompleted
Test if a connection request is completed.
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if there is a player waiting for a connectio,n
NetLib_E_es_NoNewPlayer if there was no player waiting for a connection
////////////////////////////////////////////////////////////////////////////////
Creation date : August 29,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetListenCompleted(long lParam)
{
if(gs_tdePreSessionPlayerStatus == E_Net_ConRecSta_DONE)
return NetLib_E_es_NoError;
else
return NetLib_E_es_NoNewPlayer;
}
/*
------------------------------------------------------------------------------------------
DISCONNECTION :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_eDisconnectRemotePlayer
Close connection with the player specified by the parameter
////////////////////////////////////////////////////////////////////////////////
Input : ulOldIdPlayer : a player id representing the player disconnected
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eDisconnectRemotePlayer(NetLib_tduxPlayerId ulOldPlayerId)
{
NetLib_tdeErrorStatus eErrorReturned;
tdpPointer pMsg;
NetLib_tdstSendDesc stSendDesc;
/* test whether the disconnected player is the local player */
if(NetLib_uxGetOwnPlayerId()==ulOldPlayerId)
return NetLib_E_es_InvalidHandle;
/* test whether the disconnected player exists */
if(uwNetGetPlayerIndex(ulOldPlayerId)==NetLib_C_uwInvalidPosition)
return NetLib_E_es_UnknownPlayerId;
/* Inform all other players :*/
/* Sends a disconnection message to all the players :*/
stSendDesc.m_tduxRecipientId = C_uxNetBroadcastId;
stSendDesc.m_ulMaxWaitingTime = 0;
pMsg = pMalloc(sizeof(NetLib_tduxPlayerId));
if(!pMsg) return NetLib_E_es_NotEnoughMemory;
*((NetLib_tduxPlayerId*)pMsg) = ulOldPlayerId;
stSendDesc.m_pMessageData = pMsg;
stSendDesc.m_uwMessageLength =sizeof(NetLib_tduxPlayerId);
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucNoReadReceipt;
eErrorReturned = eNetInternalSendMessage(&stSendDesc,E_Net_mt_SysDisconnectRemotePlayer);
vFree((tdpPointer)pMsg);
if(eErrorReturned==NetLib_E_es_NoError)
/* call the disconnection callback and erase the player from local tables */
eErrorReturned = eNetDisconnectPlayer(ulOldPlayerId, 1);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_vDisconnectAllRemotePlayers
Close connection with all the players of the session
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vDisconnectAllRemotePlayers(void)
{
NetLib_tdstDoForAllDesc stDoForAllDesc;
stDoForAllDesc.m_pfn_eForAll = eNetDisconnectPlayer;
stDoForAllDesc.m_lParameter = 0;
stDoForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stDoForAllDesc.m_ucIncludeLocal = NetLib_C_ucNotIncludeLocalPlayer;
NetLib_eDoForAllPlayers(&stDoForAllDesc);
if (gs_uwMode==NetLib_Mode_Direct) vNetSetSessionId(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer]));
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_vDisconnectFromSession
Disconnect the player from the session
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April,15 96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment : Since the function must send disconnection messages before closing the connection,
it may take some time to process it.
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vDisconnectFromSession(void)
{
NetLib_tdstSendDesc stSendDesc;
/* Sends a disconnection message to all the players :*/
stSendDesc.m_tduxRecipientId = C_uxNetBroadcastId;
stSendDesc.m_ulMaxWaitingTime = 0;
stSendDesc.m_pMessageData = C_pNull;
stSendDesc.m_uwMessageLength =0;
stSendDesc.m_uxPriority = NetLib_C_uxNoPriority;
stSendDesc.m_uxReplaceType = 0;
stSendDesc.m_uxReplaceFlag = 0;
stSendDesc.m_ucReadReceiptFlag = NetLib_C_ucNoReadReceipt;
eNetInternalSendMessage(&stSendDesc,E_Net_mt_SysDisconnection);
NetLib_eFlushSendingList(500);
/* Close the connections :*/
NetLib_vDisconnectAllRemotePlayers();
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetDisconnectPlayer
Disconnect a player and invoke the callback
////////////////////////////////////////////////////////////////////////////////
Input : A player id and a param
////////////////////////////////////////////////////////////////////////////////
Output : An error code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetDisconnectPlayer(NetLib_tduxPlayerId ulPlayerId,long lParam)
{
if(lParam && g_pfn_vDisconnectCallBack) g_pfn_vDisconnectCallBack(ulPlayerId);
return eNetRemoveRemotePlayer(ulPlayerId);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetRemoveRemotePlayer
Close connection with the player specified by the parameter
////////////////////////////////////////////////////////////////////////////////
Input : ulOldIdPlayer : a player id representing the player disconnected
////////////////////////////////////////////////////////////////////////////////
Output : None
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetRemoveRemotePlayer(NetLib_tduxPlayerId ulOldPlayerId)
{
NetLib_tdstPlayerInfo *p_stPlayer;
/* Update the broadcast table. */
vLevel1SupBroadcastDest(ulOldPlayerId);
vLevel1SupBroadcastSource(ulOldPlayerId);
p_stPlayer = pstNetGetPlayerSlot(ulOldPlayerId);
if ((ulOldPlayerId!=NetLib_uxGetOwnPlayerId())&&(p_stPlayer))
{
/* Erase the description of the player :*/
if(p_stPlayer->pPlayerDescriptionData) vFree(p_stPlayer->pPlayerDescriptionData);
if(p_stPlayer->Options) vFree(p_stPlayer->Options);
p_stPlayer->pPlayerDescriptionData = (tdpPointer)C_pNull;
p_stPlayer->uxPlayerDescriptionLength = 0;
M_ulNetPlayerIdSlot(p_stPlayer) = C_uxNetInvalidId;
gs_stCurrentSession.uwNumberOfPlayers --;
eLevel1DisconnectRemotePlayer(ulOldPlayerId);
return NetLib_E_es_NoError;
}
else return NetLib_E_es_UnknownPlayerId;
}
/*
------------------------------------------------------------------------------------------
SENDING MESSAGES:
------------------------------------------------------------------------------------------
*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetInternalSendMessage(NetLib_tdstSendDesc *p_stSendDesc,tdeNetMessageType eMessageType)
{
/* Local vars :*/
tdstNetMessage *pstMessage;
tdpPointer pOriginData;
NetLib_tdeErrorStatus eErrorReturned;
tdstNetBlockingLoopDescription stLoopDesc;
tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc;
NetLib_tdstDoForAllDesc stDoForAllDesc;
long a2_lParam[2];
tdstNetIter stIter;
/* Builds a tdstNetMessage object : */
pstMessage = (tdstNetMessage *)pMalloc(sizeof(tdstNetMessage)+p_stSendDesc->m_uwMessageLength);
if(pstMessage /*!=(tdstNetMessage*)C_pNull*/)
{
if(p_stSendDesc->m_uwMessageLength)
{
pOriginData = (tdpPointer)(pstMessage + 1);
g_pfn_vNetMemcpy(pOriginData,p_stSendDesc->m_pMessageData,p_stSendDesc->m_uwMessageLength);
}
pstMessage->eMessageType = eMessageType;
pstMessage->uwMessageSizeInBytes = p_stSendDesc->m_uwMessageLength;
pstMessage->uxPriority = p_stSendDesc->m_uxPriority;
pstMessage->uxReplaceType = p_stSendDesc->m_uxReplaceType;
pstMessage->uxReplace=p_stSendDesc->m_uxReplaceFlag;
pstMessage->uxRecipientId=p_stSendDesc->m_tduxRecipientId;
pstMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
if(p_stSendDesc->m_ucReadReceiptFlag==NetLib_C_ucReadReceiptRequired)
{
pstMessage->m_uxReadReceiptId = p_stSendDesc->m_stReadReceiptDesc.m_uxReadReceiptId;
pstMessage->uxRecipientId = p_stSendDesc->m_tduxRecipientId;
eNetAddEngineFunction(iNetEngineReadReceipt);
if(pstMessage->uxRecipientId!=C_uxNetBroadcastId)
{/* build a internal read-receipt structure :*/
pNetList2IterInit(&stIter,&gs_stReadReceiptList);
vNetList2ToEnd(&stIter);
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)
pNetList2ReservElem(&stIter,sizeof(tdstNetInternalReadReceiptDesc));
if (p_stInternalReadReceiptDesc)
{
eErrorReturned=eNetBuildInternalReadReceiptDesc(p_stInternalReadReceiptDesc,pstMessage,&(p_stSendDesc->m_stReadReceiptDesc));
if(eErrorReturned != NetLib_E_es_NoError)
{
vFree((tdpPointer)pstMessage);
return eErrorReturned;
}
}
else return NetLib_E_es_NotEnoughMemory;
}
else
{
stDoForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stDoForAllDesc.m_pfn_eForAll = eNetBuildAndAddReadReceipt;
a2_lParam[0] = (long)pstMessage;
a2_lParam[1] = (long)&(p_stSendDesc->m_stReadReceiptDesc);
stDoForAllDesc.m_lParameter = (long)a2_lParam;
stDoForAllDesc.m_ucIncludeLocal = NetLib_C_ucNotIncludeLocalPlayer;
eErrorReturned = NetLib_eDoForAllPlayers(&stDoForAllDesc);
}
}
else pstMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* Call the level 1 function to send the message : */
if(gs_ArtificialLatency) eErrorReturned = eInternetSimuSendMessage(p_stSendDesc->m_tduxRecipientId,pstMessage);
else eErrorReturned = eLevel1SendMessage(pstMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree((tdpPointer)pstMessage);
}
else return NetLib_E_es_NotEnoughMemory;
if ((eErrorReturned == NetLib_E_es_NoError) && (p_stSendDesc->m_ulMaxWaitingTime))
{
/* A blocking send is request :*/
/* Init the description structure:*/
stLoopDesc.m_ulMaxWaitingTime = p_stSendDesc->m_ulMaxWaitingTime;
stLoopDesc.m_eGoOnCondition = NetLib_E_es_False;
stLoopDesc.m_pfn_eEvaluation = eNetSendCompleted;
stLoopDesc.m_lParam = (long)(p_stSendDesc->m_tduxRecipientId);
/* Call the blocking procedure :*/
return NetLib_eBlockingLoop(&stLoopDesc);
}
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eSendMessage
Sends a message to a specific player
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a structure used to intialise the sending operation
////////////////////////////////////////////////////////////////////////////////
Output : An error code
////////////////////////////////////////////////////////////////////////////////
Creation date : August 27, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eSendMessage(NetLib_tdstSendDesc *p_stSendDesc)
{
#if defined(NET_USE_DEBUG)
vDebugSISISISI(Net_C_Debug_NetSer,"Send message Dest",p_stSendDesc->m_tduxRecipientId,
"Size",p_stSendDesc->m_uwMessageLength,
"Replace flag",p_stSendDesc->m_uxReplaceFlag,
"Read receipt flag",p_stSendDesc->m_ucReadReceiptFlag);
#endif /* NET_USE_DEBUG */
return eNetInternalSendMessage(p_stSendDesc,E_Net_mt_EngineMessage);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetBuildAndAddReadReceipt
Loop function for read-reciept management
////////////////////////////////////////////////////////////////////////////////
Input : A lot of things
////////////////////////////////////////////////////////////////////////////////
Output : An error code
////////////////////////////////////////////////////////////////////////////////
Creation date : October 21, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetBuildAndAddReadReceipt(NetLib_tduxPlayerId ulPlayerId,long lParam)
{
NetLib_tdeErrorStatus eErrorReturned;
tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc;
long *a2_lParam;
NetLib_tduxPlayerId ulOldPlayerId;
tdstNetIter stIter;
a2_lParam = (long*)lParam;
ulOldPlayerId = ((tdstNetMessage*)(a2_lParam[0]))->uxRecipientId;
((tdstNetMessage*)(a2_lParam[0]))->uxRecipientId = ulPlayerId;
pNetList2IterInit(&stIter,&gs_stReadReceiptList);
vNetList2ToEnd(&stIter);
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)
pNetList2ReservElem(&stIter,sizeof(tdstNetInternalReadReceiptDesc));
if (p_stInternalReadReceiptDesc)
{
eErrorReturned=eNetBuildInternalReadReceiptDesc(p_stInternalReadReceiptDesc,(tdstNetMessage*)(a2_lParam[0]),(NetLib_tdstReadReceiptDesc *)(a2_lParam[1]));
}
else eErrorReturned=NetLib_E_es_NotEnoughMemory;
((tdstNetMessage*)(a2_lParam[0]))->uxRecipientId = ulOldPlayerId;
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eFlushSendingList
Empty sending list of all players, sending system list
////////////////////////////////////////////////////////////////////////////////
Input : Time out
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if the operation is completed
An error code if there is a problem
////////////////////////////////////////////////////////////////////////////////
Creation date : September 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eFlushSendingList(NetLib_tdulTimeInfo ulMaxWaitingTime)
{
tdstNetBlockingLoopDescription stLoopDesc;
stLoopDesc.m_ulMaxWaitingTime = ulMaxWaitingTime;
stLoopDesc.m_eGoOnCondition = NetLib_E_es_OperationInProgress;
stLoopDesc.m_pfn_eEvaluation = eNetFlushCompleted;
stLoopDesc.m_lParam = (long)C_pNull;
return NetLib_eBlockingLoop(&stLoopDesc);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetSendCompleted
Check if a sending operation is completed or not
////////////////////////////////////////////////////////////////////////////////
Input : void *vParam : a player id casted into a void*
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_False if the sending list of the player is ok but not empty
NetLib_E_es_NoError if the sending list is ok and empty
An error code if the sending list is not ok
////////////////////////////////////////////////////////////////////////////////
Creation date : August 27, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetSendCompleted(long lParam)
{
NetLib_tdeErrorStatus eErrorReturned;
if (((eErrorReturned = eLevel1IsSendingListOk((NetLib_tduxPlayerId)lParam))==NetLib_E_es_NoError)
&&(eLevel1IsSendingListEmpty((NetLib_tduxPlayerId)lParam)!=NetLib_E_es_True))
return NetLib_E_es_False;
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_ePlayerFlushCompleted
Check if a flush operation is completed or not for a specific player
////////////////////////////////////////////////////////////////////////////////
Input : ulPlayerId the id of the player concerned
ulParameter : not used
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if the operation is completed
NetLib_E_es_OperationInProgress if the operation is not completed
An error code if there is a problem
////////////////////////////////////////////////////////////////////////////////
Creation date : September 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_ePlayerFlushCompleted(NetLib_tduxPlayerId ulPlayerId,long lParameter)
{
NetLib_tdeErrorStatus eErrorReturned;
eErrorReturned = NetLib_E_es_NoError;
if ((eLevel1IsSendingListEmpty(ulPlayerId)!=NetLib_E_es_True)
&&((eErrorReturned = eLevel1IsSendingListOk(ulPlayerId))==NetLib_E_es_NoError))
return NetLib_E_es_OperationInProgress;
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetFlushCompleted
Check if a flush operation is completed or not
////////////////////////////////////////////////////////////////////////////////
Input : void *vParam : not used
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if the operation is completed
NetLib_E_es_OperationInProgress if the operation is not completed
An error code if there is a problem
////////////////////////////////////////////////////////////////////////////////
Creation date : September 3, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetFlushCompleted(long Param)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstDoForAllDesc stDoForAllDesc;
if((eErrorReturned = NetLib_ePlayerFlushCompleted(C_uxNetSystemId,0L))!=NetLib_E_es_NoError)
return eErrorReturned;
stDoForAllDesc.m_pfn_eForAll = NetLib_ePlayerFlushCompleted;
stDoForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stDoForAllDesc.m_lParameter = 0L;
stDoForAllDesc.m_ucIncludeLocal = NetLib_C_ucNotIncludeLocalPlayer;
return NetLib_eDoForAllPlayers(&stDoForAllDesc);
}
/*
------------------------------------------------------------------------------------------
GETTING MESSAGES :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : eLevel1SendReadReceiptMessage
Sends a read receipt msg
////////////////////////////////////////////////////////////////////////////////
Input : a message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetSendReadReceiptMessage(tdstNetMessage *p_stMsg)
{
tdstNetMessage *p_stNewMsg;
p_stNewMsg = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(NetLib_uxReadReceiptId));
if(!p_stNewMsg) return NetLib_E_es_NotEnoughMemory;
/* initialise the msg header:*/
p_stNewMsg->eMessageType = E_Net_mt_ReadReceipt;
p_stNewMsg->uxRecipientId=p_stMsg->uxSenderId;
p_stNewMsg->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stNewMsg->uxPriority = NetLib_C_uxMaxPriority;
p_stNewMsg->uxReplaceType = 0;
p_stNewMsg->uxReplace = 0;
p_stNewMsg->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
p_stNewMsg->uwMessageSizeInBytes = sizeof(NetLib_uxReadReceiptId);
/* set the msg body :*/
*((NetLib_uxReadReceiptId*)(p_stNewMsg+1)) = p_stMsg->m_uxReadReceiptId;
return eLevel1SendMessage(p_stNewMsg,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eReadMessage
Reads a message from a player.
////////////////////////////////////////////////////////////////////////////////
Input :
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError : if no errors occurs or an error code
////////////////////////////////////////////////////////////////////////////////
Creation date : August 27,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eReadMessage(NetLib_tdstReadDesc *p_stReadDesc)
{
/* Local vars :*/
tdstNetMessage *p_stReadMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdpPointer pOriginData;
tdstNetBlockingLoopDescription stBlockingLoopDesc;
p_stReadMessage = (tdstNetMessage*)C_pNull;
if(p_stReadDesc->m_ulMaxWaitingTime)
{
/* a time-out is specified, so wait for a message :*/
stBlockingLoopDesc.m_ulMaxWaitingTime = p_stReadDesc->m_ulMaxWaitingTime;
stBlockingLoopDesc.m_eGoOnCondition = NetLib_E_es_FIFOIsEmpty;
stBlockingLoopDesc.m_pfn_eEvaluation = eNetReadCompleted;
stBlockingLoopDesc.m_lParam = p_stReadDesc->m_uxSenderId?(long)&p_stReadDesc->m_uxSenderId : (long)C_pNull;
if((eErrorReturned = NetLib_eBlockingLoop(&stBlockingLoopDesc))!=NetLib_E_es_NoError)
return eErrorReturned;
}
eErrorReturned = eLevel1ReadMessage(p_stReadDesc->m_uxSenderId,&p_stReadMessage,p_stReadDesc->m_bRemoveFromQueue);
if(eErrorReturned == NetLib_E_es_NoError)
{
/* It should not be C_pNull :*/
if(p_stReadMessage /*!=(tdstNetMessage*)C_pNull*/)
{
#if defined(NET_USE_DEBUG)
vDebugSISI(Net_C_Debug_NetSer,"Read message Source",p_stReadMessage->uxSenderId,
"Size",p_stReadMessage->uwMessageSizeInBytes);
#endif /* NET_USE_DEBUG */
p_stReadDesc->m_uxSenderId=p_stReadMessage->uxSenderId;
/* the data begins after the header of the message :*/
pOriginData = (tdpPointer)(p_stReadMessage + 1);
/* Determines wether the buffer given is enough : */
if(p_stReadMessage->uwMessageSizeInBytes <= p_stReadDesc->m_uwMessageLength)
p_stReadDesc->m_uwMessageLength = p_stReadMessage->uwMessageSizeInBytes; /* Sets the value of the bytes read */
else/* The message read is larger than the buffer given iin argument*/
eErrorReturned = p_stReadDesc->m_uwMessageLength?
NetLib_E_es_MessageTooLong:/* if not 0, the buffer specified is too short*/
NetLib_E_es_NoError;/* if 0 is specified, the data is not copied to the buffer*/
if ((p_stReadDesc->m_pMessageData) && (p_stReadDesc->m_uwMessageLength)) /* copy all the data to the buffer*/
g_pfn_vNetMemcpy(p_stReadDesc->m_pMessageData,pOriginData,p_stReadDesc->m_uwMessageLength);
/* Sets the original size of the message :*/
p_stReadDesc->m_uwOrigMsgLength = p_stReadMessage->uwMessageSizeInBytes;
/* if th emsg requires a read-receipt, send it :*/
if(p_stReadMessage->m_uxReadReceiptId!=NetLib_C_ucNoReadReceipt) eNetSendReadReceiptMessage(p_stReadMessage);
/* Frees the memory allocated : */
if(p_stReadDesc->m_bRemoveFromQueue) vFree((tdpPointer)p_stReadMessage);
return eErrorReturned;
}
p_stReadDesc->m_uwMessageLength = 0;
return NetLib_E_es_UnknownError;
}
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetReadCompleted
Check if a reading operation is completed or not
////////////////////////////////////////////////////////////////////////////////
Input : the player id casted in void*
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_FIFOIsEmpty if no message is available,
NetLib_E_es_NoError if no error occured; or a specific error code.
////////////////////////////////////////////////////////////////////////////////
Creation date : August 27,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetReadCompleted(long lParam)
{
tdstNetMessage *p_stReadMessage;
NetLib_tduxPlayerId ulPlayerId = (NetLib_tduxPlayerId)lParam;
return eLevel1ReadMessage(ulPlayerId,&p_stReadMessage,0);
}
/*
------------------------------------------------------------------------------------------
NETLIB ENGINE FUNCTIONS :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description :void NetLib_vEngine(void)
Engine of the net.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
This function ensures the behavior of the net library.
It sends effectively messages.
It ensures incomming messages.
It processes system messages....
This function must be call in all loop where communication is required.
For example :
while(..)
{
// Calling for a net function or expecting a net callback :
...
// Must call vNetEngine :
vNetEngine();
...
}
It can also be called in a separated thread...
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vEngine(void)
{
tdstNetIter stIter;
tdfn_vNetEngineFunc *ppfnEngine;
#if defined(NET_USE_DEBUG)
vDebugS(Net_C_Debug_NetSer,"vNetEngine");
#endif /* NET_USE_DEBUG */
ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2IterInit(&stIter,&gs_stEngineFunction);
while (ppfnEngine)
{
if ((*ppfnEngine)()) ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2DeleteElem(&stIter);
else ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2Next(&stIter);
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetBuildEngineFunctionsList
Builds the initial engine function list
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A netLib_tdeErrorStatus code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetBuildEngineFunctionsList(void)
{
if (iNetList2Init(&gs_stEngineFunction)) return NetLib_E_es_NotEnoughMemory;
/* Add functions :*/
eNetAddEngineFunction(iNetEngineSysMsg);
eNetAddEngineFunction(iLevel1NetEngine);
eNetAddEngineFunction(iNetEngineTCPReconect);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetAddEngineFunction
Adds an engine function
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a function(void)(*)(void)
////////////////////////////////////////////////////////////////////////////////
Output : A netLib_tdeErrorStatus code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetAddEngineFunction(tdfn_vNetEngineFunc p_fn_vEngineFunc)
{
tdstNetIter stIter;
tdfn_vNetEngineFunc *ppfnEngine;
ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2IterInit(&stIter,&gs_stEngineFunction);
while (ppfnEngine)
{
if (*ppfnEngine==p_fn_vEngineFunc) return NetLib_E_es_NoError;
else ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2Next(&stIter);
}
if (pNetList2InsertElem(&stIter,&p_fn_vEngineFunc,sizeof(tdfn_vNetEngineFunc)))
return NetLib_E_es_NoError;
else return NetLib_E_es_NotEnoughMemory;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetRemoveEngineFunction
Removes an engine function
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a function(void)(*)(void)
////////////////////////////////////////////////////////////////////////////////
Output : A netLib_tdeErrorStatus code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetRemoveEngineFunction(tdfn_vNetEngineFunc p_fn_vEngineFunc)
{
tdstNetIter stIter;
tdfn_vNetEngineFunc *ppfnEngine;
ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2IterInit(&stIter,&gs_stEngineFunction);
while (ppfnEngine)
{
if (*ppfnEngine==p_fn_vEngineFunc)
{
pNetList2DeleteElem(&stIter);
break;
}
else ppfnEngine=(tdfn_vNetEngineFunc*)pNetList2Next(&stIter);
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetEmptyEngineFunctionList
Empties the netengine function list
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A netLib_tdeErrorStatus code
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment :
There is no free to the pointer returned by the getfirstcelldata function
since it is a function pointer
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetEmptyEngineFunctionList(void)
{
tdstNetIter stIter;
pNetList2IterInit(&stIter,&gs_stEngineFunction);
vNetList2Clear(&stIter);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : iNetEngineSysMsg
Engine function : handles sys msg.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment : A call to vLevel1OutgoingNetEngine is done just after processing sys msg because
an answer could have been posted
//////////////////////////////////////////////////////////////////////////////*/
int _NET_CALLING_CONV_ iNetEngineSysMsg(void)
{
NetLib_tdeErrorStatus eErrorReturned;
tdstNetMessage *pstMes;
tdeNetProtocol eProt;
tduwNetChannel uwChannel;
while(eLevel1GetSysMsg(&pstMes,&eProt,&uwChannel) != NetLib_E_es_FIFOIsEmpty)
{
if (pstMes && (pstMes->eMessageType > E_Net_mt_FirstSysMessage)
&& (pstMes->eMessageType < E_Net_mt_LastSysMsg)
&& (gs_pfn_eSysMsgMap[pstMes->eMessageType]))
{
if ((pstMes->uxBodyBigEndian!=NetLib_ucGetLittleBigEndian())
&&(gs_pfn_eSysMsgSwapMap[pstMes->eMessageType]))
gs_pfn_eSysMsgSwapMap[pstMes->eMessageType](pstMes,eProt,uwChannel);
eErrorReturned=gs_pfn_eSysMsgMap[pstMes->eMessageType](pstMes,eProt,uwChannel);
}
else
{
eErrorReturned = NetLib_E_es_ShouldNotReach;
vFree(pstMes);
}
}
vLevel1OutgoingNetEngine();
return 0;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : iNetEngineGetActiveSession
Engine function : Handles getactive sessions.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
int _NET_CALLING_CONV_ iNetEngineGetActiveSession(void)
{
/*if we are in a listening mode, send a listening msg :*/
if ((gs_eListeningMode == E_Net_LisMod_ON)
&&(g_pfn_ulNetGetTimeInfo()-gs_tm_ulPrevGetActiveSessions >=gs_tm_ulGetActiveSessionsFreq)
&&(gs_uwNumberOfSessionsExpected > gs_c_uwNumberOfSessionsDetected)
&&(eLevel1SendSessionRequestMsg(gs_uxMaxPlayerInfo)==NetLib_E_es_NoError))
{
gs_tm_ulPrevGetActiveSessions = g_pfn_ulNetGetTimeInfo();
}
return 0;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : iNetEngineReadReceipt
Engine function : Handles read receipt message.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : Octover 15,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
int _NET_CALLING_CONV_ iNetEngineReadReceipt(void)
{
NetLib_tdulTimeInfo ulCurrentTime;
tdstNetMessage *p_stNewMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdstNetIter stIter;
tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc;
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)
pNetList2IterInit(&stIter,&gs_stReadReceiptList);
while (p_stInternalReadReceiptDesc)
{
ulCurrentTime = g_pfn_ulNetGetTimeInfo();
/* Check time:*/
if (p_stInternalReadReceiptDesc->m_ulFirstSending+
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_ulMaxWaitingTime<ulCurrentTime)
{ /* too much time elapsed without receiving a read receipt*/
/* Call the callback with the failure flag*/
if(p_stInternalReadReceiptDesc->m_stReadReceiptDesc.p_fnv_ReadReceiptCallback)
{
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.p_fnv_ReadReceiptCallback(
p_stInternalReadReceiptDesc->m_p_stMessage->uxRecipientId,
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_uxReadReceiptId,
NetLib_C_ucReadReceiptFailure,
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_lCallbackParam);
}
/* remove the message :*/
eNetEraseInternalReadReceiptDesc(p_stInternalReadReceiptDesc);
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)pNetList2DeleteElem(&stIter);
}
else
{/* check if it is time to send again*/
if ((p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_ulReemitFreq)
&&(p_stInternalReadReceiptDesc->m_ulPreviousSending+p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_ulReemitFreq
<=ulCurrentTime))
{/* it's time to resend*/
p_stNewMessage = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+p_stInternalReadReceiptDesc->m_p_stMessage->uwMessageSizeInBytes);
if(p_stNewMessage)
{
g_pfn_vNetMemcpy(p_stNewMessage,p_stInternalReadReceiptDesc->m_p_stMessage,
sizeof(tdstNetMessage)+p_stInternalReadReceiptDesc->m_p_stMessage->uwMessageSizeInBytes);
p_stNewMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
/* Call the level 1 function to send the message : */
if(gs_ArtificialLatency) eErrorReturned = eInternetSimuSendMessage(p_stNewMessage->uxRecipientId,p_stNewMessage);
else eErrorReturned = eLevel1SendMessage(p_stNewMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned ==NetLib_E_es_NoError) p_stInternalReadReceiptDesc->m_ulPreviousSending = ulCurrentTime;
}
}
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)pNetList2Next(&stIter);
}
}
if (ulNetList2NbrElem(&gs_stReadReceiptList)==0) return 1;
else return 0;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : iNetEngineInternetSimulation
Engine function : Simulate internet delay.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
int _NET_CALLING_CONV_ iNetEngineInternetSimulation(void)
{
/* If internet delay, send what must be sent :*/
if(gs_ArtificialLatency) eNetManageInternetDelay();
return 0;
}
/*
------------------------------------------------------------------------------------------
CLOSING THE LIBRARY:
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_vCloseLibrary
Close definetively the library.
////////////////////////////////////////////////////////////////////////////////
Input : none
////////////////////////////////////////////////////////////////////////////////
Output : none
////////////////////////////////////////////////////////////////////////////////
Creation date : May 6,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Comment : before calling this function, make sure that no more connection exists
with remote players. if not, call the vDisconnectFromSession function.
//////////////////////////////////////////////////////////////////////////////*/
void _NET_CALLING_CONV_ NetLib_vCloseLibrary(void)
{
unsigned short c_uwCount;
vNetLibFreeSynchro();
vNetList2Kill(&gs_stPlayerSendingList);
vNetList2Kill(&gs_stReadReceiptList);
/* dispose of time delta information */
if (gs_d_stTimeDeltas) vFree((tdpPointer) gs_d_stTimeDeltas);
gs_d_stTimeDeltas = (tdstNetTimeDelta *) C_pNull;
gs_ulLocalTimeScale = 0;
gs_b_ucDeltaCalibrationIsEnabled = 0;
/* Sets the session id to an invalid one :*/
vNetSetSessionId(C_uxNetInvalidId);
/* Sets the length of the description to zero :*/
gs_stCurrentSession.uxSessionDescriptionLength = 0;
/* Free the memory used for the session description :*/
if(gs_stCurrentSession.pSessionDescriptionData)
vFree((tdpPointer)gs_stCurrentSession.pSessionDescriptionData);
gs_stCurrentSession.pSessionDescriptionData = C_pNull;
/* Deleting informations about the current session :*/
for (c_uwCount=0;c_uwCount<gs_stCurrentSession.uwMaxNumberOfPlayers;c_uwCount++)
{/* For each player, free the memory used for the description data*/
if(gs_stCurrentSession.d_stPlayerInfo[c_uwCount].pPlayerDescriptionData)
vFree((tdpPointer)gs_stCurrentSession.d_stPlayerInfo[c_uwCount].pPlayerDescriptionData);
}
/* Free the memory used for the array of players*/
vFree((tdpPointer)gs_stCurrentSession.d_stPlayerInfo);
gs_stCurrentSession.d_stPlayerInfo = (NetLib_tdstPlayerInfo *)C_pNull;
/* Sets the max number of players to zero :*/
gs_stCurrentSession.uwMaxNumberOfPlayers = 0;
/* sets the number of players to zero :*/
gs_stCurrentSession.uwNumberOfPlayers = 0;
/* Sets the index of the local player to an invalid value*/
gs_stCurrentSession.uwIndexOfLocalPlayer = (unsigned short)-1;
if(gs_p_stPreSessionPlayerInfo) vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo *)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
NetLib_eCloseAndResetGetActiveSessions();
gs_eListeningMode = E_Net_LisMod_INVALID;
if(gs_p_stConnectRequestSessionInfo)
vFree((tdpPointer)gs_p_stConnectRequestSessionInfo);
gs_p_stConnectRequestSessionInfo = (NetLib_tdstSessionInfo *)C_pNull;
if(gs_d_tdeConnectRequestStatusArray)
vFree((tdpPointer)gs_d_tdeConnectRequestStatusArray);
gs_d_tdeConnectRequestStatusArray = (tdeNetConnectRequestStatus *)C_pNull;
g_pfn_vDisconnectCallBack = (NetLib_tdfnvDisconnectCallback)C_pNull;
g_pfn_ulNetRandom = (NetLib_tdfnulRandom)C_pNull;
g_pfn_ulNetGetTimeInfo = (NetLib_tdfnulGetTimeInfo)C_pNull;
/* Empty engine function list:*/
eNetEmptyEngineFunctionList();
vNetList2Kill(&gs_stEngineFunction);
/* Clear message map :*/
eNetClearMessageMap();
eNetClearMessageSwapLittleBigEndianMap();
/* Calling level-1 closing function :*/
vLevel1CloseLibrary();
/* Frees the memory used for the library*/
vDoneMalloc();
gs_cIsNetlibInitialised = 0;
}
/*
------------------------------------------------------------------------------------------
OTHER FUNCTIONS :
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eDoForAllPlayers
Call a specific function for all the players in the library.
////////////////////////////////////////////////////////////////////////////////
Input : pfn_ucForAll pointer to the function called
ulParameter : parameter given to the function
ucIncludeLocal : if it is non-zero, the function is also called for the local player,
otherwise not.
////////////////////////////////////////////////////////////////////////////////
Output : the last value returned by the function
////////////////////////////////////////////////////////////////////////////////
Creation date : August 9,1996
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eDoForAllPlayers(NetLib_tdstDoForAllDesc *p_stDoForAllDesc)
{
unsigned short uwPosition;
NetLib_tdeErrorStatus eErrorReturned;
/* If the local player is included :*/
if(p_stDoForAllDesc->m_ucIncludeLocal == NetLib_C_ucIncludeLocalPlayer)
{
eErrorReturned=p_stDoForAllDesc->m_pfn_eForAll(NetLib_uxGetOwnPlayerId(),
p_stDoForAllDesc->m_lParameter);
}
else eErrorReturned = p_stDoForAllDesc->m_eGoOnCondition;
uwPosition = NetLib_uwGetFirstRemotePlayerIdPosition();
if(uwPosition == NetLib_C_uwInvalidPosition)
return NetLib_E_es_NoMorePlayers;
while ((uwPosition != NetLib_C_uwInvalidPosition)
&&(eErrorReturned == p_stDoForAllDesc->m_eGoOnCondition))
{
eErrorReturned = p_stDoForAllDesc->m_pfn_eForAll(NetLib_uxGetNextRemotePlayerId(&uwPosition),
p_stDoForAllDesc->m_lParameter);
}
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_eBlockingLoop
Bloking loop function
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to a tdstNetBlockingLoopDescription
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_TimeOut if a time out occured
Or an error code returned by the evaluation function
////////////////////////////////////////////////////////////////////////////////
Creation date : August 27,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ NetLib_eBlockingLoop(tdstNetBlockingLoopDescription *p_stLoopParam)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdulTimeInfo ulWaitingTime;
if(g_pfn_ulNetGetTimeInfo) ulWaitingTime = g_pfn_ulNetGetTimeInfo();
else
{
if(p_stLoopParam->m_ulMaxWaitingTime)
return NetLib_E_es_TimeOutNotInitialised;
ulWaitingTime = 0;
}
/* Blocking loop :*/
do
{
NetLib_vEngine();
if ((g_pfn_ulNetGetTimeInfo)
&&(ulWaitingTime + p_stLoopParam->m_ulMaxWaitingTime < g_pfn_ulNetGetTimeInfo()))
eErrorReturned = NetLib_E_es_TimeOut;
else eErrorReturned = p_stLoopParam->m_pfn_eEvaluation(p_stLoopParam->m_lParam);
}while(eErrorReturned == p_stLoopParam->m_eGoOnCondition);
/* We leave the loop :*/
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetIsMessageType
////////////////////////////////////////////////////////////////////////////////
Input :
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_True
NetLib_E_es_False
////////////////////////////////////////////////////////////////////////////////
Creation date : August 22,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetIsMessageType(tdstNetMessage *p_stMessage,void *p_vType)
{
if(p_stMessage->eMessageType == *((tdeNetMessageType*)p_vType)) return NetLib_E_es_True;
else return NetLib_E_es_False;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : unsigned long ulTimeInfoToLagUnits(NetLib_tdulTimeInfo ulTime, unsigned long ulTickForTimeInfo)
converts the value returned by the time info function to universal time units.
This is because time info functions may return values in different units on the
various platforms. This function is necessary to uniformize the values.
////////////////////////////////////////////////////////////////////////////////
Input : ulTime: the time to convert
ulTickForTimeInfo: ticks for one second in time info units
////////////////////////////////////////////////////////////////////////////////
Output : the converted time
////////////////////////////////////////////////////////////////////////////////
Creation date : July 30,96
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
unsigned long ulTimeInfoToLagUnits(NetLib_tdulTimeInfo ulTime, unsigned long ulTickForTimeInfo)
{
return (unsigned long)(ulTime * (C_ulUniversalLagUnit / (double)ulTickForTimeInfo));
}
/*//////////////////////////////////////////////////////////////////////////////
Description : tdeErrorStatus eNetDenyPlayerAccess(NetLib_tdstPlayerInfo *p_stPlayerInfo)
returns always false. This is to be used in the g_pfn_ePlayerConnectionRequestFilter
variable so that all incoming player connexion requests are denied.
////////////////////////////////////////////////////////////////////////////////
Input : a structure describing a player
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_False
////////////////////////////////////////////////////////////////////////////////
Creation date : June 20,96
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetDenyPlayerAccess(NetLib_tdstPlayerInfo *p_stConReqDesc,long *plParam)
{
*plParam = -1;
return NetLib_E_es_False;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tduxPlayerId ulNetGetNewPlayerId
Returns a new player Id
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : tdulPlauyerId : a new player id
////////////////////////////////////////////////////////////////////////////////
Creation date : April 5, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tduxPlayerId ulNetGetNewPlayerId()
{
return (NetLib_tduxPlayerId)((*g_pfn_ulNetRandom)() % (C_uxNetLastUserId+1));
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdulTimeInfo ulLagUnitsToTimeInfo(NetLib_tdulTimeInfo ulTime, unsigned long ulTickForTimeInfo)
converts an universal lag unit expressed time to its time info united value.
This is because time info functions may return values in different units on the
various platforms. This function is necessary to uniformize the values.
////////////////////////////////////////////////////////////////////////////////
Input : ulLagTime: the time to convert
ulTickForTimeInfo: ticks for one second in time info units
////////////////////////////////////////////////////////////////////////////////
Output : the converted time
////////////////////////////////////////////////////////////////////////////////
Creation date : July 30,96
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdulTimeInfo ulLagUnitsToTimeInfo(unsigned long ulLagTime, unsigned long ulTickForTimeInfo)
{
return (unsigned long)(ulLagTime * (ulTickForTimeInfo / (double)C_ulUniversalLagUnit));
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetEraseInternalReadReceiptDesc
Erase an internal readreceipt desc
////////////////////////////////////////////////////////////////////////////////
Input : A pointer to a pointer to the read-receipt object
////////////////////////////////////////////////////////////////////////////////
Output : an error status
////////////////////////////////////////////////////////////////////////////////
Creation date : October 15,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetEraseInternalReadReceiptDesc(tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc)
{
vFree((tdpPointer)(p_stInternalReadReceiptDesc->m_p_stMessage));
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetBuildInternalReadReceiptDesc
Build a read/receipt internal structure
////////////////////////////////////////////////////////////////////////////////
Input : A pointer to a pointer to an internal read-receipt description structure
A pointer to a message
A pointer to a read-receipt description structure
////////////////////////////////////////////////////////////////////////////////
Output : an error status
////////////////////////////////////////////////////////////////////////////////
Creation date : October 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetBuildInternalReadReceiptDesc(tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc,
tdstNetMessage *p_stMessage,NetLib_tdstReadReceiptDesc *p_stReadReceiptDesc)
{
if(!p_stMessage) return NetLib_E_es_InvalidMessage;
/* initialise the structure:*/
p_stInternalReadReceiptDesc->m_p_stMessage=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+p_stMessage->uwMessageSizeInBytes);
if(!p_stInternalReadReceiptDesc->m_p_stMessage) return NetLib_E_es_NotEnoughMemory;
/* copy the message :*/
g_pfn_vNetMemcpy(p_stInternalReadReceiptDesc->m_p_stMessage,p_stMessage,sizeof(tdstNetMessage)+p_stMessage->uwMessageSizeInBytes);
/* copy the read-receipt description structure*/
g_pfn_vNetMemcpy(&(p_stInternalReadReceiptDesc->m_stReadReceiptDesc),p_stReadReceiptDesc,sizeof(NetLib_tdstReadReceiptDesc));
/* init time info :*/
p_stInternalReadReceiptDesc->m_ulPreviousSending=p_stInternalReadReceiptDesc->m_ulFirstSending=g_pfn_ulNetGetTimeInfo();
return NetLib_E_es_NoError;
}
/*
------------------------------------------------------------------------------------------
DEFAULT NET FUNCTIONS
------------------------------------------------------------------------------------------
*/
#ifndef _NO_USE_DEFAULT_NET_FUNCTIONS_
/*//////////////////////////////////////////////////////////////////////////////
Description : unsigned long fn_ulDefaultNetRandom(void)
Default random function
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : unsigned long : random number
////////////////////////////////////////////////////////////////////////////////
Creation date : April 5, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
unsigned long _NET_CALLING_CONV_ fn_ulDefaultNetRandom(void)
{
unsigned long ulRandomValueReturned;
/* Getting a 32-bit random value : */
ulRandomValueReturned = (((unsigned long)rand())<<16) |((unsigned short)rand());
return ulRandomValueReturned;
}
#endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/
#ifndef _NO_USE_DEFAULT_NET_FUNCTIONS_
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdulTimeInfo fn_ulDefaultNetGetTimeInfo(void)
Default function for getting time info (used for timeout)
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_tdulTimeInfo
////////////////////////////////////////////////////////////////////////////////
Creation date : April 5, 96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdulTimeInfo _NET_CALLING_CONV_ fn_ulDefaultNetGetTimeInfo(void)
{
return (NetLib_tdulTimeInfo)GetTickCount();
}
#endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/
/*
------------------------------------------------------------------------------------------
NETLIB SYSTEM MESSAGE HANDLERS
------------------------------------------------------------------------------------------
*/
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetBuildMessageSwapLittleBigEndianMap
Builds a map of functions processing little/big endian swap for sys msg
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetBuildMessageSwapLittleBigEndianMap(void)
{
unsigned short uwCount;
/* Build message map :*/
gs_pfn_eSysMsgSwapMap=(tdfn_eNetSysMsgSwapLittleBigEndian *)pMalloc(sizeof(tdfn_eNetSysMsgSwapLittleBigEndian)*E_Net_mt_LastSysMsg);
if(!gs_pfn_eSysMsgSwapMap) return NetLib_E_es_NotEnoughMemory;
for(uwCount = 0;uwCount <E_Net_mt_LastSysMsg;uwCount++)
{
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,uwCount,((tdfn_eNetSysMsgSwapLittleBigEndian)C_pNull));
}
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysRequestActiveSessionsReply,eSwapLittleBigEndianSysMsgRequestSessionReply);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysConnectAgreement,eSwapLittleBigEndianSysMsgConnectAgreement);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysConnectDeny,eSwapLittleBigEndianSysMsgConnectDeny);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysPlayerDescriptorChanged,eSwapLittleBigEndianSysMsgPlayerDescriptorChanged);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysTimeDeltaRequest,eSwapLittleBigEndianSysMsgTimeDeltaRequest);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysTimeDeltaReply,eSwapLittleBigEndianSysMsgTimeDeltaRequest);/*same structure used*/
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysDisconnectRemotePlayer,eSwapLittleBigEndianSysMsgDisconnectRemotePlayer);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_ReadReceipt,eSwapLittleBigEndianSysMsgReadReceipt);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_MaxNbrOfPlayers,eSwapLittleBigEndianSysMsgMaxNbrOfPlayers);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgSwapMap,E_Net_mt_SysSynchro,eSwapLittleBigEndianSysMsgSynchro);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : Builds the netlib sys message map
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetBuildMessageMap(void)
{
unsigned short uwCount;
/* Build message map :*/
gs_pfn_eSysMsgMap = (tdfn_eNetSysMsgHandle *)pMalloc(sizeof(tdfn_eNetSysMsgHandle)*E_Net_mt_LastSysMsg);
if(!gs_pfn_eSysMsgMap) return NetLib_E_es_NotEnoughMemory;
for(uwCount = 0;uwCount <E_Net_mt_LastSysMsg;uwCount++)
{
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,uwCount,((tdfn_eNetSysMsgHandle)C_pNull));
}
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysUnknownSender,eHandleNetSysMsgUnknownSender);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysUnknownRecipient,eHandleNetSysMsgUnknownRecipient);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysFullBuffer,eHandleNetSysMsgFullBuffer);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysRequestActiveSessions,eHandleNetSysMsgRequestSession);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysRequestActiveSessionsReply,eHandleNetSysMsgRequestSessionReply);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectRequest,eHandleNetSysMsgConnectRequest);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectCancel,eHandleNetSysMsgConnectCancel);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectAcknowledgement,eHandleNetSysMsgConnectAcknowledgement);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectAgreement,eHandleNetSysMsgConnectAgreement);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectListened,eHandleNetSysMsgConnectListened);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysConnectDeny,eHandleNetSysMsgConnectDeny);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysWaitFollow,eHandleNetSysMsgWaitFollow);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysWaitBusy,eHandleNetSysMsgWaitBusy);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysDisconnection,eHandleNetSysMsgDisconnection);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysPlayerDescriptorChanged,eHandleNetSysMsgPlayerDescriptorChanged);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysSessionDescriptorChanged,eHandleNetSysMsgSessionDescriptorChanged);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysTimeDeltaRequest,eHandleNetSysMsgTimeDeltaRequest);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysTimeDeltaReply,eHandleNetSysMsgTimeDeltaReply);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysDisconnectRemotePlayer,eHandleNetSysMsgDisconnectRemotePlayer);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_ReadReceipt,eHandleNetSysMsgReadReceipt);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_MaxNbrOfPlayers,eHandleNetSysMsgMaxNbrOfPlayers);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_TCPAddress,eHandleNetSysMsgTCPAddress);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_TCPIsMe,eHandleNetSysMsgTCPIsMe);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_TCPSupRoute,eHandleNetSysMsgTCPSupRoute);
M_vNetAddMessageMapEntry(gs_pfn_eSysMsgMap,E_Net_mt_SysSynchro,eHandleNetSysMsgSynchro);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : Clears the netlib sys message map
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetClearMessageSwapLittleBigEndianMap(void)
{
if (gs_pfn_eSysMsgSwapMap) vFree((tdpPointer)gs_pfn_eSysMsgSwapMap);
gs_pfn_eSysMsgMap = (tdfn_eNetSysMsgSwapLittleBigEndian*)C_pNull;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : Clears the netlib sys message map
////////////////////////////////////////////////////////////////////////////////
Input : None
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 14,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetClearMessageMap(void)
{
if (gs_pfn_eSysMsgMap) vFree((tdpPointer)gs_pfn_eSysMsgMap);
gs_pfn_eSysMsgMap = (tdfn_eNetSysMsgHandle *)C_pNull;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgUnknownSender
Handle of the system message : Unknown sender
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgUnknownSender(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
return eLevel1HandleSysMsgUnknownSender(pstMes);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgUnknownRecipient
Handle of the system message : Unknown Recipient
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgUnknownRecipient(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
return eLevel1HandleSysMsgUnknownRecipient(pstMes);
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgFullBuffer
Handle of the system message : Full buffer
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgFullBuffer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
eLevel1HandleSysMsgFullBuffer(pstMes,eProt,uwChannel);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eSwapLittleBigEndianSysMsgPlayerDescriptorChanged
Swaps the system message : E_Net_mt_SysPlayerDescriptorChanged
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body : -> ulPlayerId -> Swap
-> ucDescriptionLength -> nothing
-> pDescription -> Game's problem
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgPlayerDescriptorChanged(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgPlayerDescriptorChanged
Handle of the system message : E_Net_mt_SysPlayerDescriptorChanged
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgPlayerDescriptorChanged(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdstPlayerInfo *p_stThePlayer;
tdpPointer pOriginData;
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxSessionId != gs_stCurrentSession.uxSessionId)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
/* If the local player is the recipient and the sender exists in the current session*/
if ((uwNetGetPlayerIndex(pstMes->uxSenderId)!=NetLib_C_uwInvalidPosition)
&& (pstMes->uxRecipientId == NetLib_uxGetOwnPlayerId()))
{
if (pstMes->m_uxReadReceiptId!=NetLib_C_ucNoReadReceipt)
/* if read-receipt required :*/
eNetSendReadReceiptMessage(pstMes);
p_stThePlayer = pstNetGetPlayerSlot(*((NetLib_tduxPlayerId*)(pstMes+1)));
if(!p_stThePlayer)
{
vFree(pstMes);
return NetLib_E_es_UnknownPlayerId;
}
if(p_stThePlayer->pPlayerDescriptionData)
{
vFree(p_stThePlayer->pPlayerDescriptionData);
p_stThePlayer->uxPlayerDescriptionLength = 0;
}
/* Initialize the new data :*/
pOriginData = (tdpPointer )(pstMes + 1);
pOriginData = (tdpPointer)(((NetLib_tduxPlayerId*)pOriginData)+1);
p_stThePlayer->uxPlayerDescriptionLength = *((NetLib_tduxDescriptionLength*)pOriginData);
pOriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)pOriginData + 1);
if(p_stThePlayer->uxPlayerDescriptionLength)
{
p_stThePlayer->pPlayerDescriptionData = (tdpPointer)pMalloc(p_stThePlayer->uxPlayerDescriptionLength);
if(p_stThePlayer->pPlayerDescriptionData /*!=(tdpPointer)C_pNull*/)
{
g_pfn_vNetMemcpy(p_stThePlayer->pPlayerDescriptionData,pOriginData,p_stThePlayer->uxPlayerDescriptionLength);
vFree(pstMes);
return NetLib_E_es_NoError;
}
vFree(pstMes);
return NetLib_E_es_NotEnoughMemory;
}
p_stThePlayer->pPlayerDescriptionData = C_pNull;
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*else*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgSessionDescriptorChanged
Handle of the system message : E_Net_mt_SysSessionDescriptorChanged
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : May 30,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgSessionDescriptorChanged(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdpPointer pOriginData;
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxSessionId != gs_stCurrentSession.uxSessionId)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
if(pstMes->uxRecipientId == NetLib_uxGetOwnPlayerId())
{
if(pstMes->m_uxReadReceiptId!=NetLib_C_ucNoReadReceipt)
/* if read-receipt required :*/
eNetSendReadReceiptMessage(pstMes);
if(gs_stCurrentSession.pSessionDescriptionData /*!=(tdpPointer)C_pNull*/)
{
vFree(gs_stCurrentSession.pSessionDescriptionData);
/* Not necessary because reallocated just after :*/
/* p_stThePlayer->pPlayerDescriptionData = (tdpPointer)C_pNull;*/
gs_stCurrentSession.uxSessionDescriptionLength = 0;
}
/* Initialize the new data :*/
pOriginData = (tdpPointer )(pstMes + 1);
gs_stCurrentSession.uxSessionDescriptionLength = *((NetLib_tduxDescriptionLength*)pOriginData);
pOriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)pOriginData + 1);
if(gs_stCurrentSession.uxSessionDescriptionLength)
{
gs_stCurrentSession.pSessionDescriptionData = (tdpPointer)pMalloc(gs_stCurrentSession.uxSessionDescriptionLength);
if(gs_stCurrentSession.pSessionDescriptionData /*!=(tdpPointer)C_pNull*/)
{
g_pfn_vNetMemcpy(gs_stCurrentSession.pSessionDescriptionData,pOriginData,
gs_stCurrentSession.uxSessionDescriptionLength );
vFree(pstMes);
return NetLib_E_es_NoError;
}
else
{
vFree(pstMes);
return NetLib_E_es_NotEnoughMemory;
}
}
else
{
gs_stCurrentSession.pSessionDescriptionData = C_pNull;
vFree(pstMes);
return NetLib_E_es_NoError;
}
}
else
{
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : pstNetBuildRequestSessionReplyMsg
Builds a message with the informations of the session
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : A pointer to the msg or NULL
////////////////////////////////////////////////////////////////////////////////
Creation date : September 20,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
It builds a message E_Net_mt_SysRequestActiveSessionsReply
The body of the message is (in this order) :
-> The id of the session
-> the max number players of the session
-> the effective number of players in the session
-> Player 1 's id
-> Player 2 's id
...
-> Player n 's id (where n equals the number of effective player)
-> the length of the session description in bytes
-> the session description data (number of bytes given by the previous slot)
-> the length of the player 1 description in bytes
-> the player 1 description data (number of bytes given by the previous slot)
-> the player 1 big/little endian flag
...
-> the length of the player n description in bytes
-> the player n description data
-> the player n big/little endian flag
-> a bytes for route building for the player 1
...
-> the length of the player n description in bytes
(where n equals the number of effective player)
-> the player n description data (number of bytes given by the previous slot)
(where n equals the number of effective player)
-> a bytes for route building for the player n
//////////////////////////////////////////////////////////////////////////////*/
tdstNetMessage *pstNetBuildRequestSessionReplyMsg(tdeNetProtocol eProt,tduwNetChannel uwChannel,unsigned long ucMaxPlayerInfo)
{
tdstNetMessage *p_stMsgReturned;
unsigned short uwMessageLength;
unsigned short c_uwCurrentPlayerIndex;
unsigned short c_uwCurrentSlot;
tdpPointer p_OriginData;
NetLib_tduxPlayerId *d_ulPlayerIdArray;
NetLib_tduxDescriptionLength ucDescLength, ucCopyLength;
/* Determine the size of the message :*/
uwMessageLength =
sizeof(NetLib_tduxSessionId) /* for the id of the session*/
+sizeof(unsigned short) /* for the maximum numbers of players */
+sizeof(unsigned short) /* for the number of players*/
+sizeof(NetLib_tduxSessionId) * gs_stCurrentSession.uwNumberOfPlayers /* For each Id of the players of the session */
+sizeof(NetLib_tduxDescriptionLength)/* For the length of the session description*/
+gs_stCurrentSession.uxSessionDescriptionLength/* for the session description*/
+sizeof(NetLib_tduxDescriptionLength) * gs_stCurrentSession.uwNumberOfPlayers /* For the length of each player description */
+sizeof(NetLib_tducBigLittleEndian)*gs_stCurrentSession.uwNumberOfPlayers /* for the big/little endian flag*/
+sizeof(NetLib_tduxDescriptionLength); /* for the player description truncation size*/
for(c_uwCurrentPlayerIndex=0;c_uwCurrentPlayerIndex<gs_stCurrentSession.uwMaxNumberOfPlayers;c_uwCurrentPlayerIndex ++)
{/* For each player description :*/
if(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex]) != C_uxNetInvalidId)
{
ucDescLength=gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex].uxPlayerDescriptionLength;
if (ucDescLength<=ucMaxPlayerInfo)
uwMessageLength += ucDescLength;
else uwMessageLength += ucMaxPlayerInfo;
}
}
p_stMsgReturned = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage) + uwMessageLength);
if(!p_stMsgReturned) return (tdstNetMessage*)C_pNull;
/* Message length :*/
p_stMsgReturned->uwMessageSizeInBytes = uwMessageLength;
/* type :*/
p_stMsgReturned->eMessageType = E_Net_mt_SysRequestActiveSessionsReply;
p_stMsgReturned->uxPriority = NetLib_C_uxNoPriority;
p_stMsgReturned->uxReplaceType = 0;
p_stMsgReturned->uxReplace = 0;
p_stMsgReturned->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* And now : the body :*/
/* The id of the session :*/
p_OriginData = (tdpPointer)(p_stMsgReturned + 1);
*((NetLib_tduxSessionId*)p_OriginData) = gs_stCurrentSession.uxSessionId;
/* The maximum number of players*/
p_OriginData = (tdpPointer)((NetLib_tduxSessionId*)p_OriginData + 1);
*((unsigned short *)p_OriginData) = gs_stCurrentSession.uwMaxNumberOfPlayers;
/* The number of players*/
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
*((unsigned short *)p_OriginData) = gs_stCurrentSession.uwNumberOfPlayers;
/* For each player : the ID :*/
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
/* d_ulPlayerIdArray is set to the correct place where ids are to be put :*/
d_ulPlayerIdArray = (NetLib_tduxPlayerId *)p_OriginData;
p_OriginData = (tdpPointer)((NetLib_tduxPlayerId*)p_OriginData +
gs_stCurrentSession.uwNumberOfPlayers);
/* The length of the Session description : */
*((NetLib_tduxDescriptionLength *)p_OriginData) = gs_stCurrentSession.uxSessionDescriptionLength;
/* The session description :*/
p_OriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)p_OriginData + 1);
if(gs_stCurrentSession.uxSessionDescriptionLength)
{
g_pfn_vNetMemcpy(p_OriginData,gs_stCurrentSession.pSessionDescriptionData,
gs_stCurrentSession.uxSessionDescriptionLength);
}
p_OriginData = (tdpPointer)p_OriginData + gs_stCurrentSession.uxSessionDescriptionLength;
/* the player description truncation size (which might have been changed on the remote side */
*((NetLib_tduxDescriptionLength*)p_OriginData)=ucMaxPlayerInfo;
p_OriginData = p_OriginData + sizeof(NetLib_tduxDescriptionLength);
/* For each player : */
c_uwCurrentSlot = 0;
for (c_uwCurrentPlayerIndex=0;c_uwCurrentPlayerIndex<gs_stCurrentSession.uwMaxNumberOfPlayers;c_uwCurrentPlayerIndex++)
{
if (M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex]) !=C_uxNetInvalidId)
{
d_ulPlayerIdArray[c_uwCurrentSlot++]=M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex]);
ucDescLength=gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex].uxPlayerDescriptionLength;
/* The length of the description of the player :*/
*((NetLib_tduxDescriptionLength*)p_OriginData)=ucDescLength;
/* the description of the player :*/
p_OriginData=(tdpPointer)((NetLib_tduxDescriptionLength*)p_OriginData + 1);
if(ucDescLength)
{
ucCopyLength=ucDescLength>ucMaxPlayerInfo?ucMaxPlayerInfo:ucDescLength;
g_pfn_vNetMemcpy(p_OriginData,
gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex].pPlayerDescriptionData,
ucCopyLength);
p_OriginData=(tdpPointer)p_OriginData+ucCopyLength;
}
*((NetLib_tducBigLittleEndian*)p_OriginData)=gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentPlayerIndex].m_ucLittleBigEndian;
p_OriginData=(tdpPointer)((NetLib_tducBigLittleEndian*)p_OriginData + 1);
}
}
return p_stMsgReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgRequestSession
Handle of the system message : Request session(E_Net_mt_SysRequestActiveSessions)
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_NotEnoughMemory if there was not enough memory
NetLib_E_es_ShouldNotReach if the message should not reach this point
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgRequestSession(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tduxPlayerId ulExSenderNewRecipientId;
unsigned long ucMaxPlayerInfo;
/* If the current number of players is equal to the max number of player, do not answer :*/
if(gs_stCurrentSession.uwMaxNumberOfPlayers==gs_stCurrentSession.uwNumberOfPlayers)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
/* Builds the message :*/
/* Erase the previous message :*/
ulExSenderNewRecipientId = pstMes->uxSenderId;
ucMaxPlayerInfo=*((NetLib_tduxDescriptionLength *)(pstMes+1));
vFree(pstMes);
/* Build the new message :*/
pstMes = pstNetBuildRequestSessionReplyMsg(eProt,uwChannel,ucMaxPlayerInfo);
if(!pstMes) return NetLib_E_es_NotEnoughMemory;
/* Recipient id :*/
pstMes->uxRecipientId = ulExSenderNewRecipientId;
pstMes->uxSenderId = NetLib_uxGetOwnPlayerId();
eErrorReturned = eLevel1SendMessage(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetRetrieveInfoSession
Retrieves and creates a session info from a msg
////////////////////////////////////////////////////////////////////////////////
Input : a msg
a pointer to a pointer to a session info structure
a pointer to an array of unsigned char
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : September,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetRetrieveInfoSession(tdstNetMessage *p_stMsgReturned,NetLib_tdstSessionInfo **p_stSessionInfoReceived,unsigned char **pp_ucWaitForReply)
{
tdpPointer p_OriginData;
unsigned short c_uwCount;
NetLib_tduxPlayerId *p_dListPlayerId;
NetLib_tduxDescriptionLength ucMaxPlayerInfo, ucActualSize, ucCopySize;
*p_stSessionInfoReceived=(NetLib_tdstSessionInfo *)pMalloc(sizeof(NetLib_tdstSessionInfo));
if(!(*p_stSessionInfoReceived)) return NetLib_E_es_NotEnoughMemory;
p_OriginData=(tdpPointer)(p_stMsgReturned + 1);
/* The session id :*/
(*p_stSessionInfoReceived)->uxSessionId = *((NetLib_tduxSessionId*)p_OriginData);
p_OriginData = (tdpPointer)((NetLib_tduxSessionId*)p_OriginData + 1);
/* Retrieves the maximum number of players :*/
(*p_stSessionInfoReceived)->uwMaxNumberOfPlayers = *((unsigned short*)p_OriginData);
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
/* Retrieves the number of players :*/
(*p_stSessionInfoReceived)->uwNumberOfPlayers = *((unsigned short *)p_OriginData);
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
/* Retrieves the list of id's players :*/
/* Cast part of the message to a list of players Id :*/
(*p_stSessionInfoReceived)->d_stPlayerInfo = (NetLib_tdstPlayerInfo *)
pMalloc(sizeof(NetLib_tdstPlayerInfo)*(*p_stSessionInfoReceived)->uwMaxNumberOfPlayers);
if(!(*p_stSessionInfoReceived)->d_stPlayerInfo)
{
vFree((tdpPointer)(*p_stSessionInfoReceived));
*p_stSessionInfoReceived= (NetLib_tdstSessionInfo *)C_pNull;
return NetLib_E_es_NotEnoughMemory;
}
(*p_stSessionInfoReceived)->uwIndexOfLocalPlayer = NetLib_C_uwInvalidPosition;
p_dListPlayerId = (NetLib_tduxPlayerId *)p_OriginData;
p_OriginData = (tdpPointer)((NetLib_tduxPlayerId *)p_OriginData+(*p_stSessionInfoReceived)->uwNumberOfPlayers);
/* The length of the session description :*/
(*p_stSessionInfoReceived)->uxSessionDescriptionLength = *((NetLib_tduxDescriptionLength*)p_OriginData);
p_OriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)p_OriginData+1);
/* the session description*/
if((*p_stSessionInfoReceived)->uxSessionDescriptionLength)
{
(*p_stSessionInfoReceived)->pSessionDescriptionData = pMalloc((*p_stSessionInfoReceived)->uxSessionDescriptionLength);
if(!(*p_stSessionInfoReceived)->pSessionDescriptionData)
{
vFree((tdpPointer)(*p_stSessionInfoReceived)->d_stPlayerInfo);
vFree((tdpPointer)*p_stSessionInfoReceived);
*p_stSessionInfoReceived = (NetLib_tdstSessionInfo*)C_pNull;
return NetLib_E_es_NotEnoughMemory;
}
g_pfn_vNetMemcpy((*p_stSessionInfoReceived)->pSessionDescriptionData,
p_OriginData,
(*p_stSessionInfoReceived)->uxSessionDescriptionLength);
}
else (*p_stSessionInfoReceived)->pSessionDescriptionData = C_pNull;
p_OriginData = p_OriginData + (*p_stSessionInfoReceived)->uxSessionDescriptionLength;
/* player description truncation size */
(*p_stSessionInfoReceived)->uxPlayerDescTruncation=ucMaxPlayerInfo=*((NetLib_tduxDescriptionLength*)p_OriginData);
p_OriginData = p_OriginData + sizeof(NetLib_tduxDescriptionLength);
/* Player initialisation :*/
for(c_uwCount = 0;c_uwCount <(*p_stSessionInfoReceived)->uwNumberOfPlayers;c_uwCount++)
{
M_ulNetPlayerIdSlot(&((*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount]))=p_dListPlayerId[c_uwCount];
ucActualSize=(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].uxPlayerDescriptionLength=*((NetLib_tduxDescriptionLength*)p_OriginData);
p_OriginData=(tdpPointer)((NetLib_tduxDescriptionLength*)p_OriginData+1);
(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].Options=NULL;
ucCopySize= ucActualSize > ucMaxPlayerInfo ? ucMaxPlayerInfo : ucActualSize;
if(ucCopySize)
{
(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData=
pMalloc(ucCopySize);
if((*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData)
g_pfn_vNetMemcpy((*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData,
p_OriginData,
ucCopySize);
else (*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].uxPlayerDescriptionLength=0;
}
else (*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData=C_pNull;
p_OriginData = p_OriginData+ucCopySize;
(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].m_ucLittleBigEndian=*((NetLib_tducBigLittleEndian*)p_OriginData);
p_OriginData = (tdpPointer)((NetLib_tducBigLittleEndian*)p_OriginData+1);
}
for (c_uwCount=(*p_stSessionInfoReceived)->uwNumberOfPlayers;c_uwCount<(*p_stSessionInfoReceived)->uwMaxNumberOfPlayers;c_uwCount++)
{
M_ulNetPlayerIdSlot(&((*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount]))=C_uxNetInvalidId;
(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].pPlayerDescriptionData=C_pNull;
(*p_stSessionInfoReceived)->d_stPlayerInfo[c_uwCount].uxPlayerDescriptionLength=0;
}
/*the waitforreply array :*/
*pp_ucWaitForReply = (unsigned char*)p_OriginData;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetHaveSessionsSamePlayers
Check if two sessions have the same players or not
////////////////////////////////////////////////////////////////////////////////
Input : NetLib_tdstSessionInfo *: one session
NetLib_tdstSessionInfo *: the other
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : September,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetHaveSessionsSamePlayers(NetLib_tdstSessionInfo *p_stSessionInfo1,NetLib_tdstSessionInfo *p_stSessionInfo2)
{
unsigned short c_uwCount;
unsigned short c_uwCount2;
NetLib_tdeErrorStatus eErrorReturned;
if(p_stSessionInfo1->uwNumberOfPlayers!=p_stSessionInfo2->uwNumberOfPlayers)
return NetLib_E_es_False;
/* Checking wether elements are equal or not*/
/* It is supposed that in each array, every id is different from all others*/
eErrorReturned = NetLib_E_es_True;
c_uwCount = 0;
while ((eErrorReturned == NetLib_E_es_True)
&&(c_uwCount < p_stSessionInfo1->uwNumberOfPlayers))
{
c_uwCount2 = 0;
while ((c_uwCount2 < p_stSessionInfo2->uwNumberOfPlayers)&&
(M_ulNetPlayerIdSlot(&(p_stSessionInfo1->d_stPlayerInfo[c_uwCount]))
!=M_ulNetPlayerIdSlot(&(p_stSessionInfo2->d_stPlayerInfo[c_uwCount2]))))
c_uwCount2++;
if(c_uwCount2 >=p_stSessionInfo2->uwNumberOfPlayers)
eErrorReturned = NetLib_E_es_False;
c_uwCount++;
}
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eNetCopySessionInfo
Copy information from one NetLib_tdstSessionInfo to another
////////////////////////////////////////////////////////////////////////////////
Input : NetLib_tdstSessionInfo *p_stDest : the destination
NetLib_tdstSessionInfo *p_stSrc : the source
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : September,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetCopySessionInfo(NetLib_tdstSessionInfo *p_stDest,NetLib_tdstSessionInfo *p_stSrc)
{
p_stDest->uxSessionId = p_stSrc->uxSessionId;
p_stDest->uwMaxNumberOfPlayers = p_stSrc->uwMaxNumberOfPlayers;
p_stDest->uwNumberOfPlayers = p_stSrc->uwNumberOfPlayers;
p_stDest->uwIndexOfLocalPlayer = p_stSrc->uwIndexOfLocalPlayer;
p_stDest->uxSessionDescriptionLength = p_stSrc->uxSessionDescriptionLength;
p_stDest->pSessionDescriptionData = p_stSrc->pSessionDescriptionData;
p_stDest->d_stPlayerInfo = p_stSrc->d_stPlayerInfo;
p_stDest->uxPlayerDescTruncation = p_stSrc->uxPlayerDescTruncation;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eSwapLittleBigEndianSysMsgRequestSessionReply
Swap the system message : Request session reply
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body :
->ulSesssionId ->swap
->uwMaxNbrOfPlayers ->swap
->uwNbrOfPlayers ->swap
->ulPlayer1Id ->swap
->.
->.
->.
->ulPlayernId ->swap
->uxSessionDescriptionLength -> do nothing
->pSessionDescription -> game's problem
->ucPlayer1DescriptionLength -> do nothing
->pPlayer1DescriptionLength -> game's problem
->ucBigLittleEndianFlag -> do nothing
->.
->.
->.
->ucPlayernDescriptionLength -> do nothing
->pPlayernDescriptionLength -> game's problem
->ucBigLittleEndianFlag -> do nothing
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgRequestSessionReply(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdpPointer pData;
unsigned short uwNbrOfPlayers;
pData = (tdpPointer)(pstMes +1);
pData = (tdpPointer)((NetLib_tduxSessionId*)pData+1);
*((unsigned short*)pData) = /*max nbr of players*/
M_NET_uwSwapLittleBigEndian(*(unsigned short*)pData);
pData = (tdpPointer)((unsigned short*)pData+1);
uwNbrOfPlayers = *((unsigned short*)pData) = /*nbr of players*/
M_NET_uwSwapLittleBigEndian(*(unsigned short*)pData);
/* nothing more to do*/
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eHandleNetSysMsgRequestSessionReply
Handle of the system message : Request session reply
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : April 2&3,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Pre-supposed :
The global variables gs_dstSessions and gs_c_uwNumberOfSessionsDetected are correctly
initialised. That is to say enough memory is allocated for the array and the value
of the index is between 0 and the boundary of the array.
////////////////////////////////////////////////////////////////////////////////
Comment :
This functions update informations about sessions which answers to a RequestSession
message :
If it is a new session that answers, the functions create a new entry in the array
of the NetLib_tdstSessionInfo global object :gs_dstSessions and increase the value of
gs_c_uwNumberOfSessionsDetected that represents the number of sessions found
If this session already has an entry in the gs_dstSessions array, the functions
updates its informations about this game if necessary.
The function then call the necessary level 1 functions in order to have the
level 1 informations updated.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgRequestSessionReply(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstSessionInfo *p_stSessionInfoReceived;
NetLib_tdstSessionInfo *p_stSessionInfoPrevious;
unsigned short uwIndexOfSessionFound;
unsigned short c_uwCurrent;
unsigned short uwPrevNbrOfPlayers;
tdstNetTemp *p_stPreviousWait;
unsigned char *p_ucWaitFor;
if(gs_eListeningMode != E_Net_LisMod_ON)
{ /*We are not in a listening mode, so don't care of the message*/
/* but call the level 1 in order to update information */
eLevel1BuildRouteInfoOfSessionPlayer(pstMes,eProt,uwChannel);
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*
FIRST : retrieve informations about the session detected :
*/
eErrorReturned=eNetRetrieveInfoSession(pstMes,&p_stSessionInfoReceived,&p_ucWaitFor);
if(eErrorReturned !=NetLib_E_es_NoError)
{
vFree(pstMes);
return eErrorReturned;
}
/* If a filter function is used, call it to check if the session is valid or not :*/
if(g_pfn_eSessionFilter /* !=((NetLib_tdeErrorStatus (*)(NetLib_tdstSessionInfo*)))C_pNull*/)
{
if(g_pfn_eSessionFilter(p_stSessionInfoReceived)!=NetLib_E_es_True)
{
/* The session has not been accepted, so discard it*/
vNetClearSessionInfo(p_stSessionInfoReceived);
vFree((tdpPointer)p_stSessionInfoReceived);
vFree(pstMes);
return NetLib_E_es_NoError;
}
}
/* search if a session with the same Id exists : */
uwIndexOfSessionFound = 0;
while ((uwIndexOfSessionFound < gs_c_uwNumberOfSessionsDetected) &&
(gs_dstSessions[uwIndexOfSessionFound].uxSessionId!=p_stSessionInfoReceived->uxSessionId))
uwIndexOfSessionFound++;
if(uwIndexOfSessionFound < gs_c_uwNumberOfSessionsDetected)
/* //////////////////////////////////////////////////////////////////////////////// */
/* ////////// A session with the same Id has been found : ////////// */
/* //////////////////////////////////////////////////////////////////////////////// */
{
p_stSessionInfoPrevious = gs_dstSessions+uwIndexOfSessionFound;
eErrorReturned = eNetHaveSessionsSamePlayers(p_stSessionInfoPrevious,p_stSessionInfoReceived);
if(eErrorReturned == NetLib_E_es_True)
/* //////////////////////////////////////////////////////////////////////////////// */
/* ////////// The two lists are equals : ////////// */
/* //////////////////////////////////////////////////////////////////////////////// */
{
vNetClearSessionInfo(p_stSessionInfoReceived);
vFree((tdpPointer)p_stSessionInfoReceived);
p_stSessionInfoReceived = (NetLib_tdstSessionInfo*)C_pNull;
eErrorReturned = eLevel1BuildRouteInfo(pstMes,eProt,uwChannel);
if(eErrorReturned == NetLib_E_es_UnknownPlayerId) eErrorReturned = eLevel1UpdateRouteInfo(pstMes,eProt,uwChannel);
if(eErrorReturned == NetLib_E_es_UnknownSessionId) eErrorReturned = eLevel1AddNewSession(pstMes,eProt,uwChannel);
vFree(pstMes);
return eErrorReturned;
}
/* //////////////////////////////////////////////////////////////////////////////// */
/* ////////// The two lists are different ////////// */
/* //////////////////////////////////////////////////////////////////////////////// */
/* First : free the memory for player description :*/
p_stPreviousWait = (tdstNetTemp *)pMalloc(sizeof(tdstNetTemp)*p_stSessionInfoPrevious->uwNumberOfPlayers);
for (c_uwCurrent=0;c_uwCurrent<p_stSessionInfoPrevious->uwNumberOfPlayers;c_uwCurrent++)
{
if(p_stPreviousWait)
{
p_stPreviousWait[c_uwCurrent].ulPlayerId =M_ulNetPlayerIdSlot(&(p_stSessionInfoPrevious->d_stPlayerInfo[c_uwCurrent]));
}
}
uwPrevNbrOfPlayers = p_stSessionInfoPrevious->uwNumberOfPlayers;
vNetClearSessionInfo(p_stSessionInfoPrevious);
eNetCopySessionInfo(p_stSessionInfoPrevious,p_stSessionInfoReceived);
vFree((tdpPointer)p_stSessionInfoReceived);
p_stSessionInfoReceived = (NetLib_tdstSessionInfo *)C_pNull;
/* Here, data are updated for the level 2*/
/* So now : */
/* Update data in level 1 :*/
eErrorReturned = eLevel1UpdateRouteInfo(pstMes,eProt,uwChannel);
if(eErrorReturned == NetLib_E_es_UnknownSessionId)
/* Create the new session (Normaly should not happen)*/
eErrorReturned = eLevel1AddNewSession(pstMes,eProt,uwChannel);
vFree((tdpPointer)p_stPreviousWait);
vFree(pstMes);
return eErrorReturned;
}/* End of if if(c_uwCurrent < gs_c_uwNumberOfSessionsDetected)...*/
else
/* //////////////////////////////////////////////////////////////////////////////// */
/* ////////// A new session has been found : ////////// */
/* //////////////////////////////////////////////////////////////////////////////// */
{
/* Initialise the entry of the array gs_dstSessions at the */
/* gs_c_uwNumberOfSessionsDetected position with appropriate data */
/* It is supposed that these variables are correctely initialised :*/
/* Enough memory for gs_dstSessions and correct value for gs_c_uwNumberOfSessionsDetected */
if(gs_c_uwNumberOfSessionsDetected>=gs_uwNumberOfSessionsExpected)
{
vNetClearSessionInfo(p_stSessionInfoReceived);
vFree((tdpPointer)p_stSessionInfoReceived);
vFree(pstMes);
return NetLib_E_es_NoError;
}
eNetCopySessionInfo(gs_dstSessions+gs_c_uwNumberOfSessionsDetected,p_stSessionInfoReceived);
vFree((tdpPointer)p_stSessionInfoReceived);
p_stSessionInfoReceived = (NetLib_tdstSessionInfo*)C_pNull;
/* the waiting flag */
gs_dpucWaitForReply[gs_c_uwNumberOfSessionsDetected]=1;
/* Inform level 1 of the new session*/
if((eErrorReturned = eLevel1AddNewSession(pstMes,eProt,uwChannel))==NetLib_E_es_SessionIdAlreadyAcknowledged)
{
if((eErrorReturned = eLevel1BuildRouteInfo(pstMes,eProt,uwChannel))== NetLib_E_es_UnknownPlayerId)
eErrorReturned = eLevel1UpdateRouteInfo(pstMes,eProt,uwChannel);
}
if(eErrorReturned == NetLib_E_es_NoError) gs_c_uwNumberOfSessionsDetected++;
else
{
/* Clear data :*/
vNetClearSessionInfo(gs_dstSessions+gs_c_uwNumberOfSessionsDetected);
gs_dpucWaitForReply[gs_c_uwNumberOfSessionsDetected] = 0;
}
vFree(pstMes);
return eErrorReturned;
}/* End of else if(c_uwCurrent < gs_c_uwNumberOfSessionsDetected)...: new session processed */
}/*End of function */
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectRequest(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message ConnectRequest
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
NetLib_E_es_NotEnoughMemory : the function could not complete the process of the message
because of a lack of memory
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectRequest(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
tdpPointer p_OriginData;
NetLib_tduxPlayerId uxSenderId;
NetLib_tduxPlayerId uxRecipientId;
tdstNetMessage *p_stMessageReturned;
unsigned short c_uwCount;
long lParam;
unsigned char uxPlayerDescriptionLength;
uxSenderId = pstMes->uxSenderId;
uxRecipientId = pstMes->uxRecipientId;
if ((gs_p_stPreSessionPlayerInfo==(NetLib_tdstPlayerInfo*)C_pNull) ||
((gs_p_stPreSessionPlayerInfo /*!= (NetLib_tdstPlayerInfo*)C_pNull*/) &&
(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo) != uxSenderId) &&
(eNetCheckTimeOutOfPlayerConnected(0)==NetLib_E_es_TimeOutExpired)))
{
/* ------------------------------------------------------------
NO PREVIOUS CONNECTION :
------------------------------------------------------------ */
/* Empty the gs_p_stPreSessionPlayerInfo if necessary*/
/* this happens if too mutch time elapsed since the player*/
/* made its connection request*/
if(gs_p_stPreSessionPlayerInfo != (NetLib_tdstPlayerInfo*)C_pNull)
eNetCheckTimeOutOfPlayerConnected(1);
/* Check if the destinee is the local player */
if(uxRecipientId != NetLib_uxGetOwnPlayerId())
{
/* the recipient is not the local player*/
vFree(pstMes);
pstMes = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage));
if (pstMes)
{
/* Send a WaitFollow message to indicate that he must ask*/
/* for connection to this local player first*/
pstMes->eMessageType = E_Net_mt_SysWaitFollow;
pstMes->uxRecipientId = uxSenderId;
pstMes->uxSenderId = NetLib_uxGetOwnPlayerId();
pstMes->uwMessageSizeInBytes = 0;
pstMes->uxPriority = NetLib_C_uxNoPriority;
pstMes->uxReplaceType = 0;
pstMes->uxReplace = 0;
pstMes->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
eErrorReturned = eLevel1SendMessage(pstMes,eProt,uwChannel);
if (eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
else
{ /* Not enough memory to process the message :*/
return NetLib_E_es_NotEnoughMemory;
}
}
/* The local player is the recipient */
/* check if it is not yet connected*/
c_uwCount = 0;
while ((c_uwCount<gs_stCurrentSession.uwMaxNumberOfPlayers)
&&(uxSenderId!=M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount])))
c_uwCount++;
if(c_uwCount < gs_stCurrentSession.uwMaxNumberOfPlayers)
{
/*The player is already in the session*/
/* May be he did not received the listening message*/
/* So resent it :*/
vFree(pstMes);
p_stMessageReturned = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage));
if(p_stMessageReturned)
{
p_stMessageReturned->eMessageType = E_Net_mt_SysConnectListened;
p_stMessageReturned->uxRecipientId=uxSenderId;
p_stMessageReturned->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stMessageReturned->uwMessageSizeInBytes = 0;
p_stMessageReturned->uxPriority = NetLib_C_uxMaxPriority;
p_stMessageReturned->uxReplaceType = 0;
p_stMessageReturned->uxReplace = 0;
p_stMessageReturned->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
if(gs_ArtificialLatency) eErrorReturned = eInternetSimuSendMessage(uxSenderId,p_stMessageReturned);
else eErrorReturned = eLevel1SendMessage(p_stMessageReturned,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned !=NetLib_E_es_NoError) vFree((tdpPointer)p_stMessageReturned);
return eErrorReturned;
}
else return NetLib_E_es_NotEnoughMemory;
}
/* The player is realy a new one :*/
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)pMalloc(sizeof(NetLib_tdstPlayerInfo));
if(!gs_p_stPreSessionPlayerInfo /*== (NetLib_tdstPlayerInfo*)C_pNull*/)
{
/* Not enough memory to process the message */
vFree(pstMes);
return NetLib_E_es_NotEnoughMemory;
}
/* Init player description :*/
M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo) = uxSenderId;
gs_p_stPreSessionPlayerInfo->Options=NULL;
/* sets p_OriginData at the begining of the body of the message :*/
p_OriginData = (tdpPointer)(pstMes + 1);
/* retrieves the length of the player description :*/
gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength=*((NetLib_tduxDescriptionLength*)p_OriginData);
p_OriginData = (tdpPointer)((NetLib_tduxDescriptionLength*)p_OriginData + 1);
if ((gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength) &&
((gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData =
(tdpPointer)pMalloc(gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength))!=0))
{
/* retrieves the player description :*/
g_pfn_vNetMemcpy(gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData,p_OriginData,
gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength);
p_OriginData=p_OriginData + gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength;
}
else
{
p_OriginData=p_OriginData + gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength;
gs_p_stPreSessionPlayerInfo->uxPlayerDescriptionLength = 0;
gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData = (tdpPointer)C_pNull;
}
gs_p_stPreSessionPlayerInfo->m_ucLittleBigEndian=*((NetLib_tducBigLittleEndian*)p_OriginData);
p_OriginData = p_OriginData + sizeof(NetLib_tducBigLittleEndian);
gs_p_stPreSessionPlayerInfo->m_bOverInternet=*p_OriginData;
/* Check if the game accept the connection process : */
if ((g_pfn_ePlayerConnectionRequestFilter) &&
(g_pfn_ePlayerConnectionRequestFilter(gs_p_stPreSessionPlayerInfo,&lParam)!=
NetLib_E_es_True))
{
/* the game refused the connection :*/
vFree(gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
vFree(pstMes);
pstMes = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(long));
if(pstMes)
{
pstMes->eMessageType = E_Net_mt_SysConnectDeny;
pstMes->uwMessageSizeInBytes = sizeof(long);
pstMes->uxRecipientId = uxSenderId;
pstMes->uxSenderId = NetLib_uxGetOwnPlayerId();
pstMes->uxPriority = NetLib_C_uxNoPriority;
pstMes->uxReplaceType = 0;
pstMes->uxReplace = 0;
pstMes->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* and now the body :*/
p_OriginData = (tdpPointer)(pstMes + 1);
*((long*)p_OriginData) = lParam;
if((eErrorReturned = eLevel1SendMessage(pstMes,eProt,uwChannel))!=NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
else return NetLib_E_es_NotEnoughMemory;
}
/* initialise the gs_tdePreSessionPlayerStatus */
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_DOING;
/* Initialise the timeout :*/
if(g_pfn_ulNetGetTimeInfo) gs_tm_ulPreSessionPlayerTimer = (*g_pfn_ulNetGetTimeInfo)();
else gs_tm_ulPreSessionPlayerTimer = 0;
/* Inform the level1 of the connection request :*/
if (((eErrorReturned = eLevel1HandleSysMsgConnectRequest(pstMes,eProt,uwChannel)) != NetLib_E_es_NoError)
&&(eErrorReturned !=NetLib_E_es_IdAlreadyInRouteTable))
{/* Level 1 failure */
vFree(gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
/* Close the connection with the player :*/
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
/* Free memory :*/
vFree(pstMes);
return eErrorReturned;
}
p_stMessageReturned = (tdstNetMessage*)pMalloc(
sizeof(tdstNetMessage) + /* for the message */
sizeof(unsigned short)+ /* for the number of players in the session*/
sizeof(NetLib_tduxPlayerId)*gs_stCurrentSession.uwNumberOfPlayers+ /* for the ids of each player*/
sizeof(char)); /* the "over internet" mark */
if(!p_stMessageReturned)
{
/* not enough memory to process the msg :*/
/* So clear data...*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
/* Close the connection with the player :*/
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
vFree(pstMes);
return NetLib_E_es_NotEnoughMemory;
}
/* Send an agreement message :*/
/*
Body of the message :
->Number of players
->Player 1 Id
...
->Player n Id
*/
p_stMessageReturned->eMessageType = E_Net_mt_SysConnectAgreement;
p_stMessageReturned->uxRecipientId=uxSenderId;
p_stMessageReturned->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stMessageReturned->uwMessageSizeInBytes = sizeof(unsigned short)
+ sizeof(NetLib_tduxPlayerId)*gs_stCurrentSession.uwNumberOfPlayers
+ sizeof(char);
p_stMessageReturned->uxPriority = NetLib_C_uxMaxPriority;
p_stMessageReturned->uxReplaceType = 0;
p_stMessageReturned->uxReplace = 0;
p_stMessageReturned->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* Builds the body of the message :*/
p_OriginData = (tdpPointer)(p_stMessageReturned+1);
*((unsigned short*)p_OriginData) = gs_stCurrentSession.uwNumberOfPlayers;
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
for(c_uwCount = 0;c_uwCount <gs_stCurrentSession.uwMaxNumberOfPlayers; c_uwCount++)
{
if(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount])!=C_uxNetInvalidId)
{
*((NetLib_tduxPlayerId*)p_OriginData)=M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount]);
p_OriginData=(tdpPointer)((NetLib_tduxPlayerId*)p_OriginData + 1);
}
}
(*(char *)p_OriginData) = gs_p_stPreSessionPlayerInfo->m_bOverInternet;
if(gs_ArtificialLatency) eErrorReturned = eInternetSimuSendMessage(uxSenderId,p_stMessageReturned);
else eErrorReturned = eLevel1SendMessage(p_stMessageReturned,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned != NetLib_E_es_NoError)
{
/* Close the connection with the player : */
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
/* Clear data : */
vFree((tdpPointer)p_stMessageReturned);
p_stMessageReturned = (tdstNetMessage*)C_pNull;
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
/* Not necessary :
gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData = (tdpPointer)C_pNull; */
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
}
vFree(pstMes);
return eErrorReturned;
}/* end of if(gs_p_stPreSessionPlayerInfo == C_pNull)*/
/*------------------------------------------------------------
A CONNECTION IS ALREADY IN PROGRESS :
------------------------------------------------------------ */
/* check if it is the same player that sends this connection msg :*/
if(uxSenderId != M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo))
{ /* a new player asks for connection */
vFree(pstMes);
pstMes = (tdstNetMessage*)pMalloc(sizeof(tdstNetMessage));
if(pstMes)
{
pstMes->eMessageType = E_Net_mt_SysWaitBusy;
pstMes->uxRecipientId = uxSenderId;
pstMes->uxSenderId = NetLib_uxGetOwnPlayerId();
pstMes->uwMessageSizeInBytes = 0;
pstMes->uxPriority = NetLib_C_uxNoPriority;
pstMes->uxReplaceType = 0;
pstMes->uxReplace = 0;
pstMes->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
eErrorReturned = eLevel1SendMessage(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
else
{
vFree(pstMes);
return NetLib_E_es_NotEnoughMemory;
}
}
/* The sender is the same as the one in the buffer*/
/* check if the local player is the recipient of the message :*/
if(uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the local player is not the recipient : so route message */
/* set the "via internet" mark of the message */
/* sets p_OriginData at the begining of the body of the message :*/
p_OriginData = (tdpPointer)(pstMes + 1);
/* retrieves the length of the player description :*/
uxPlayerDescriptionLength = *((NetLib_tduxDescriptionLength*)p_OriginData);
/* skip all data before the "via internet" mark */
p_OriginData = (tdpPointer)(p_OriginData +
sizeof(NetLib_tduxDescriptionLength) +
uxPlayerDescriptionLength +
sizeof(NetLib_tducBigLittleEndian));
/* eventually set the mark */
if(eLevel1GoesToIP(uxRecipientId)) *((char *)p_OriginData)=1;
/* route the message */
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/* the local player is the recipient*/
eLevel1HandleSysMsgConnectRequest(pstMes,eProt,uwChannel);
/* We do not need p_stIOSystCell any more :*/
vFree(pstMes);
p_stMessageReturned=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(unsigned short)+
sizeof(NetLib_tduxPlayerId)*gs_stCurrentSession.uwNumberOfPlayers);
if(!p_stMessageReturned) return NetLib_E_es_NotEnoughMemory; /* not enough memory to process the message*/
p_stMessageReturned->eMessageType = E_Net_mt_SysConnectAgreement;
p_stMessageReturned->uxRecipientId=uxSenderId;
p_stMessageReturned->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stMessageReturned->uwMessageSizeInBytes=sizeof(unsigned short)
+sizeof(NetLib_tduxPlayerId)*gs_stCurrentSession.uwNumberOfPlayers;
p_stMessageReturned->uxPriority = NetLib_C_uxMaxPriority;
p_stMessageReturned->uxReplaceType = 0;
p_stMessageReturned->uxReplace = 0;
p_stMessageReturned->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* Builds the body of the message :*/
p_OriginData = (tdpPointer)(p_stMessageReturned + 1);
*((unsigned short*)p_OriginData) = gs_stCurrentSession.uwNumberOfPlayers;
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
for(c_uwCount = 0;c_uwCount <gs_stCurrentSession.uwMaxNumberOfPlayers; c_uwCount++)
{
if(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount]) != C_uxNetInvalidId)
{
*((NetLib_tduxPlayerId*)p_OriginData) = M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCount]);
p_OriginData =(tdpPointer)((NetLib_tduxPlayerId*)p_OriginData + 1);
}
}
if(gs_ArtificialLatency) eErrorReturned = eInternetSimuSendMessage(uxSenderId,p_stMessageReturned);
else eErrorReturned = eLevel1SendMessage(p_stMessageReturned,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned!=NetLib_E_es_NoError) vFree((tdpPointer)p_stMessageReturned);
/* we choose to restart the timer */
gs_tm_ulPreSessionPlayerTimer = (*g_pfn_ulNetGetTimeInfo)();
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectCancel(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message ConnectCancel
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectCancel(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the message must be routed*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/* the local player is the recipient */
if ((gs_p_stPreSessionPlayerInfo)
&&(pstMes->uxSenderId == M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo)))
{
/*The player cancels its connection request*/
/* Close the communication medium :*/
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
/*Clear the information about the player*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
}
else
{
/* no one made a connection. Check if it not a player already in the game :*/
if(uwNetGetPlayerIndex(pstMes->uxSenderId)!=NetLib_C_uwInvalidPosition)
{
if(g_pfn_vDisconnectCallBack)
(*g_pfn_vDisconnectCallBack)(pstMes->uxSenderId);
eNetRemoveRemotePlayer(pstMes->uxSenderId);
}
}
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectAcknowledgement(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Connect acknowledgement
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectAcknowledgement(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tdstListenDesc stListenDesc;
char flagDirect; /* Direct route flag. */
flagDirect=*((char *)(pstMes+1));
if(pstMes->uxRecipientId == NetLib_uxGetOwnPlayerId())
{/* the local player is the recipient */
if((gs_p_stPreSessionPlayerInfo) &&
(pstMes->uxSenderId == M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo)))
{/*The player confirms its connection request*/
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_DONE;
if (flagDirect==0) vLevel1AddBroadcastPath(NetLib_uxGetOwnPlayerId(),pstMes->uxSenderId);
if(gs_ucAcceptWithoutListening==NetLib_C_ucAcceptWithoutListening)
{
stListenDesc.m_ulMaxWaitingTime = 0;
stListenDesc.m_pPlayerDescriptionData = C_pNull;
NetLib_eListenForRequest(&stListenDesc);
}
}
/*
else
somone different from the player who asked for the connection
confirms a connection. There is nothing to do.
*/
vFree(pstMes);
return NetLib_E_es_NoError;
}
/* the message must be routed*/
*((char *)(pstMes+1))=1; /* Set the route flag (message not direct).*/
vLevel1AddBroadcastPath(pstMes->uxSenderId,pstMes->uxRecipientId);
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes); /* Erase data*/
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eSwapLittleBigEndianSysMsgConnectAgreement
swap the system message Connect agreement
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body :
-> uwNbrOfPlayers
-> ulPlayer1Id
-> .
-> .
-> .
-> ulPlayernId
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgConnectAgreement(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
unsigned short uwCount;
unsigned short uwNbrOfPlayers;
tdpPointer pOriginData;
pOriginData = (tdpPointer)(pstMes+1);
uwNbrOfPlayers = *((unsigned short*)pOriginData) =
M_NET_uwSwapLittleBigEndian(*((unsigned short*)pOriginData));
pOriginData = (tdpPointer)((unsigned short *)pOriginData +1);
for(uwCount = 0;uwCount < uwNbrOfPlayers;uwCount++)
{
pOriginData = (tdpPointer)((NetLib_tduxPlayerId*)pOriginData+1);
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectAgreement(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Connect agreement
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectAgreement(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
NetLib_tduxPlayerId *d_ulIdPlayerArray;
unsigned short c_uwCount;
unsigned short c_uwCount2;
unsigned short uwNumberOfPlayers;
unsigned short uwSenderIndex;
unsigned char b_ucDifferent;
tdpPointer p_OriginData;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the local player is not the recipient :*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/* The local player is the recipient */
if(!gs_p_stConnectRequestSessionInfo)
{/* It should not occured but...*/
vFree(pstMes);
return NetLib_E_es_UnknownError;
}/* end of else (gs_p_stConnectRequestSessionInfo != C_pNull)*/
/*
found the index of the sender
*/
uwSenderIndex = 0;
while ((uwSenderIndex<gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
&&(pstMes->uxSenderId!=
M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[uwSenderIndex])))
{
uwSenderIndex++;
}
if(uwSenderIndex >=gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers )
{/* It should not occured but...*/
vFree(pstMes);
return NetLib_E_es_UnknownError;
}/* end of else (gs_p_stConnectRequestSessionInfo != C_pNull)*/
/* Check the intergity of the session information with the message sent*/
/* Sets p_OriginData at the begining of the message body :*/
p_OriginData = (tdpPointer)(pstMes + 1);
/* Retireves the number of players*/
uwNumberOfPlayers = *((unsigned short*)p_OriginData);
p_OriginData = (tdpPointer)((unsigned short*)p_OriginData + 1);
/* Retrieves the array of player ids*/
d_ulIdPlayerArray = (NetLib_tduxPlayerId *)p_OriginData;
if(gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers != uwNumberOfPlayers)
{/* The numbers of players are different..............*/
gs_d_tdeConnectRequestStatusArray[uwSenderIndex] = E_Net_ConReqSta_SessionChanged;
vFree(pstMes);
return NetLib_E_es_NoError;
}
/* The number of players are equals, but are they the same ?????*/
c_uwCount = 0;
b_ucDifferent = 0;
while((c_uwCount < uwNumberOfPlayers)&&(!b_ucDifferent))
{
c_uwCount2 = 0;
while((c_uwCount2<uwNumberOfPlayers)&&(d_ulIdPlayerArray[c_uwCount] != M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount2])))
{
c_uwCount2++;
}/*End of while((C_uwCount2 <...*/
if(c_uwCount2 >=uwNumberOfPlayers) b_ucDifferent = 1;
c_uwCount++;
}/* End of while((c_uwCount < uwNumberOfPlayers)&&(b_ucDifferent == 0)...*/
vFree(pstMes);
if(b_ucDifferent != 0)
{
gs_d_tdeConnectRequestStatusArray[uwSenderIndex] = E_Net_ConReqSta_SessionChanged;
return NetLib_E_es_NoError;
}
/* The list are equals*/
/* rembember the "over internet" mark */
p_OriginData = p_OriginData + uwNumberOfPlayers*sizeof(NetLib_tduxPlayerId);
gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[uwSenderIndex].m_bOverInternet=*p_OriginData;
gs_d_tdeConnectRequestStatusArray[uwSenderIndex] = E_Net_ConReqSta_Done;
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : eSwapLittleBigEndianSysMsgConnectDeny
swap the system message Connect deny
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body :
->lParam -> swap
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgConnectDeny(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
*((long*)(pstMes+1))=M_NET_ulSwapLittleBigEndian(*((long*)(pstMes+1)));
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectDeny(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Connect deny
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Improvement :
Check that the sender of the message belongs to the session where the connection
has been done.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectDeny(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
unsigned short c_uwCount;
tdpPointer p_MsgData;
/* Cancel the conection :*/
if(pstMes->uxRecipientId == NetLib_uxGetOwnPlayerId())
{/* the local player is the recipient*/
p_MsgData = (tdpPointer) (pstMes + 1);
gs_lConDenyParam = *((long*)p_MsgData);
if(gs_p_stConnectRequestSessionInfo)
{
c_uwCount = 0;
while(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
if (M_ulNetPlayerIdSlot(&(gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]))
== pstMes->uxSenderId)
{
gs_d_tdeConnectRequestStatusArray[c_uwCount] = E_Net_ConReqSta_Refused;
c_uwCount = gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers+1;
}
else c_uwCount++;
}
}
else return NetLib_E_es_ShouldNotReach;
vFree(pstMes);
return NetLib_E_es_NoError;
}
else
{/* the local player is not the recipient :*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgConnectListened(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Connect agreement
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 10,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgConnectListened(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
unsigned short c_uwCount;
NetLib_tdeErrorStatus eErrorReturned;
char flagDirect; /* Direct route flag. */
flagDirect=*((char *)(pstMes+1));
/* Check if the message is for the local player :*/
if(pstMes->uxRecipientId !=NetLib_uxGetOwnPlayerId())
{/* the local player is not the recipient :*/
*((char *)(pstMes+1))=1; /* Set the route flag (message not direct).*/
vLevel1AddBroadcastPath(pstMes->uxSenderId,pstMes->uxRecipientId);
if((eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel))!=NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
/* The local player is the recipient :*/
if(!gs_p_stConnectRequestSessionInfo) return NetLib_E_es_ShouldNotReach;
/* finding the appropriate player :*/
c_uwCount = 0;
while ((c_uwCount<gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)&&
(M_ulNetPlayerIdSlot(&gs_p_stConnectRequestSessionInfo->d_stPlayerInfo[c_uwCount]) !=
pstMes->uxSenderId))
c_uwCount++;
if(c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers)
{
if (flagDirect==0) vLevel1AddBroadcastPath(NetLib_uxGetOwnPlayerId(),pstMes->uxSenderId);
gs_d_tdeConnectRequestStatusArray[c_uwCount] = E_Net_ConReqSta_Listened;
vFree(pstMes);
return NetLib_E_es_NoError;
}
else
{
vFree(pstMes);
return NetLib_E_es_UnknownPlayerId;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eHandleNetSysMsgWaitFollow(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Wait follow
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgWaitFollow(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the local player is not the recipient :*/
if((eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel))!=NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
if(!gs_p_stConnectRequestSessionInfo)
{
vFree(pstMes);
return NetLib_E_es_ShouldNotReach;
}
/* Frees the memory : */
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_tdeErrorStatus eHandleNetSysMsgWaitBusy(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message wait busy
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgWaitBusy(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
unsigned short c_uwCount;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the local playr is not the recipient*/
if((eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel))!=NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
if (!gs_p_stConnectRequestSessionInfo)
{
vFree(pstMes);
return NetLib_E_es_ShouldNotReach;
}
/* Cancel the conection :*/
for(c_uwCount = 0; c_uwCount < gs_p_stConnectRequestSessionInfo->uwNumberOfPlayers;c_uwCount++)
gs_d_tdeConnectRequestStatusArray[c_uwCount] = E_Net_ConReqSta_WaitBusy;
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_tdeErrorStatus eHandleNetSysMsgDisconnection(tdstNetIOSystemCell*p_stIOSystCell)
Handle of the system message Disconnect
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
NetLib_E_es_ShouldNotReach the message should not reach this function
////////////////////////////////////////////////////////////////////////////////
Creation date : April 4,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgDisconnection(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
if ((pstMes->uxSessionId == gs_stCurrentSession.uxSessionId) &&
(pstMes->eMessageType ==E_Net_mt_SysDisconnection))
{
if(pstMes->uxRecipientId == NetLib_uxGetOwnPlayerId())
{/* the local player is the recipient*/
if ((gs_p_stPreSessionPlayerInfo)&&
(pstMes->uxSenderId == M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo)))
{
/*The player cancels its connection request*/
/* Close the communication medium :*/
eLevel1DisconnectRemotePlayer(M_ulNetPlayerIdSlot(gs_p_stPreSessionPlayerInfo));
/*Clear the information about the player*/
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo->pPlayerDescriptionData);
vFree((tdpPointer)gs_p_stPreSessionPlayerInfo);
gs_p_stPreSessionPlayerInfo = (NetLib_tdstPlayerInfo*)C_pNull;
gs_tdePreSessionPlayerStatus = E_Net_ConRecSta_NONE;
}
else
{
if (uwNetGetPlayerIndex(pstMes->uxSenderId) != NetLib_C_uwInvalidPosition)
{
eNetDisconnectPlayer(pstMes->uxSenderId, 1);
}
}
vFree(pstMes);
return NetLib_E_es_NoError;
}
else
{/* the local player is not the recipient*/
if((eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel))!=NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
}
else
{/* The message has a bad type ?*/
vFree(pstMes);
return NetLib_E_es_ShouldNotReach;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgTimeDeltaRequest
Swap a E_Net_mt_SysTimeDeltaRequest msg and a E_Net_mt_SysTimeDeltaReply msg
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,1996
Author : Albert PAIS
////////////////////////////////////////////////////////////////////////////////
Message body : a tdstNetPingMessage
-> ulTimeOfSender ->swap
-> ulTimeOfRecipient ->swap
-> ulScaleOfRecipient ->swap
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgTimeDeltaRequest(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdstNetPingMessage *p_stPingMsg;
p_stPingMsg = (tdstNetPingMessage *)(pstMes+1);
p_stPingMsg->ulTimeOfSender = M_NET_ulSwapLittleBigEndian(p_stPingMsg->ulTimeOfSender);
p_stPingMsg->ulTimeOfRecipient = M_NET_ulSwapLittleBigEndian(p_stPingMsg->ulTimeOfRecipient);
p_stPingMsg->ulScaleOfRecipient = M_NET_ulSwapLittleBigEndian(p_stPingMsg->ulScaleOfRecipient);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_tdeErrorStatus eHandleNetSysMsgTimeDeltaRequest(tdstNetIOSystemCell*p_stIOSystCell)
Handles a timer value request
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
another error condition if the reply could not be sent back
////////////////////////////////////////////////////////////////////////////////
Creation date : June 20,1996
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgTimeDeltaRequest(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eReturnValue;
tdstNetMessage *p_stRequestMessage;
unsigned short c_uwCurrentIndex;
/* retrieve the message itself */
p_stRequestMessage=pstMes;
/* Retrieves the index of the sender:*/
c_uwCurrentIndex = 0;
while ((c_uwCurrentIndex < gs_stCurrentSession.uwMaxNumberOfPlayers) &&
(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[c_uwCurrentIndex])!=p_stRequestMessage->uxSenderId))
{
c_uwCurrentIndex ++;
}
/* If the local player is the recipient and the sender exists in the current session*/
if ((c_uwCurrentIndex < gs_stCurrentSession.uwMaxNumberOfPlayers)
&&(p_stRequestMessage->uxRecipientId == NetLib_uxGetOwnPlayerId()))
{
tdstNetPingMessage *p_stRepliedPing=(tdstNetPingMessage *)(p_stRequestMessage+1);
/* add our local time and scale in the body of the message, after the local time of the sender.
* we have to scale the time by the number of total expected retries of the caller because of
* the very large values the timer function can return. */
p_stRepliedPing->ulTimeOfRecipient=ulTimeInfoToLagUnits(g_pfn_ulNetGetTimeInfo(),gs_ulLocalTimeScale);
p_stRepliedPing->ulScaleOfRecipient=gs_ulLocalTimeScale;
/* the message is a reply to the request */
p_stRequestMessage->eMessageType=E_Net_mt_SysTimeDeltaReply;
p_stRequestMessage->uxRecipientId=p_stRequestMessage->uxSenderId;
p_stRequestMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stRequestMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stRequestMessage->uxReplaceType = 0;
p_stRequestMessage->uxReplace = 1;
p_stRequestMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
/* try to send the message */
if(gs_ArtificialLatency)
eReturnValue = eInternetSimuSendMessage(p_stRequestMessage->uxSenderId, p_stRequestMessage);
else
eReturnValue = eLevel1SendMessage(p_stRequestMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eReturnValue==NetLib_E_es_NoError)
{
#if defined(NET_USE_DEBUG)
vDebugSI(Net_C_Debug_NetSer,"request recvd, reply sent, time",p_stRepliedPing->ulTimeOfRecipient);
#endif /* NET_USE_DEBUG */
}
/* if it failed, free the message */
if (eReturnValue != NetLib_E_es_NoError) vFree((tdpPointer) p_stRequestMessage);
/* return the error status */
return eReturnValue;
}
else /* route the message, because it is not ours */
{
eReturnValue = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eReturnValue != NetLib_E_es_NoError) vFree(pstMes);
return eReturnValue;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description :NetLib_tdeErrorStatus eHandleNetSysMsgTimeDeltaReply(tdstNetIOSystemCell*p_stIOSystCell)
Handles a timer value reply
////////////////////////////////////////////////////////////////////////////////
Input : a tdstNetIOSystemCell that contains the information about the message
////////////////////////////////////////////////////////////////////////////////
Output : NetLib_E_es_NoError if no error occured
////////////////////////////////////////////////////////////////////////////////
Creation date : June 20,1996
Author : Benoit Germain
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgTimeDeltaReply(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
tdstNetMessage *p_stReplyMessage;
unsigned short uwTimedPlayerIndex;
unsigned long ulReceptionDate;
unsigned long ulHalfPingDelay;
tdstNetTimeDelta *pTimeDelta;
/* retrieve the message itself */
p_stReplyMessage = pstMes;
/* Retrieves the index of the sender :*/
uwTimedPlayerIndex = 0;
while ((uwTimedPlayerIndex < gs_stCurrentSession.uwMaxNumberOfPlayers) &&
(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[uwTimedPlayerIndex])!=p_stReplyMessage->uxSenderId))
{
uwTimedPlayerIndex ++;
}
/* If the local player is the recipient and the sender exists in the current session*/
if ((uwTimedPlayerIndex < gs_stCurrentSession.uwMaxNumberOfPlayers)
&& (p_stReplyMessage->uxRecipientId == NetLib_uxGetOwnPlayerId()))
{
tdstNetPingMessage *p_stRepliedPing=(tdstNetPingMessage *)(p_stReplyMessage+1);
/* no handling if the delay calibration was not properly set up
* or if the reply arrives after the timeout */
if (!gs_d_stTimeDeltas || !gs_b_ucDeltaCalibrationIsEnabled) return NetLib_E_es_ShouldNotReach;
/* when did I get the answer back (expressed in universal lag units) ? */
ulReceptionDate=ulTimeInfoToLagUnits(g_pfn_ulNetGetTimeInfo(),gs_ulLocalTimeScale);
/* look for the related player delay */
for (uwTimedPlayerIndex=0;uwTimedPlayerIndex<gs_stCurrentSession.uwMaxNumberOfPlayers;uwTimedPlayerIndex++)
{
/* if we found the sender in the array of delays we are trying to compute */
if (gs_d_stTimeDeltas[uwTimedPlayerIndex].ulPlayerId == p_stReplyMessage->uxSenderId)
{
pTimeDelta=gs_d_stTimeDeltas+uwTimedPlayerIndex;
/* forth and back took that long (in universal lag units) */
ulHalfPingDelay=(ulReceptionDate - p_stRepliedPing->ulTimeOfSender)/2;
/* we got one more reply */
pTimeDelta->NumberOfRetries++;
/* store the latency we got (in universal lag units) */
pTimeDelta->ulLatency += ulHalfPingDelay;
/* we add the delay for a future average computation (keep it in universal lag units) */
pTimeDelta->dDeltaWithLocal+=((double)ulHalfPingDelay + (double)p_stRepliedPing->ulTimeOfSender - (double)p_stRepliedPing->ulTimeOfRecipient);
/* here is the total number of replies we got */
pTimeDelta->ulScaleOfRecipient = p_stRepliedPing->ulScaleOfRecipient;
#if defined(NET_USE_DEBUG)
vDebugSISISISI(Net_C_Debug_NetSer,"NumPing",p_stRepliedPing->numPing,
"TimRec",ulReceptionDate,"Half Ping",ulHalfPingDelay,
"TimRem",p_stRepliedPing->ulTimeOfRecipient);
vDebugSISI(Net_C_Debug_NetSer,"Delta",(ulHalfPingDelay + p_stRepliedPing->ulTimeOfSender - p_stRepliedPing->ulTimeOfRecipient),
"E-Md",p_stRepliedPing->ulTimeOfRecipient-p_stRepliedPing->ulTimeOfSender);
#endif /* NET_USE_DEBUG */
pTimeDelta->LastRetries=p_stRepliedPing->numPing;
break;
}
}
/* free the message because we no longer need it */
vFree((tdpPointer) p_stReplyMessage);
return NetLib_E_es_NoError;
}
else /* route the message, because it is not ours */
{
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eSwapLittleBigEndianSysMsgDisconnectRemotePlayer
Swap E_Net_mt_SysDisconnectRemotePlayer message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body : -> ulPlayerId -> swap
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgDisconnectRemotePlayer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgDisconnectRemotePlayer
Handle a E_Net_mt_SysDisconnectRemotePlayer message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : September 16,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgDisconnectRemotePlayer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tduxPlayerId ulPlayerId;
NetLib_tdstDoForAllDesc stDoForAllDesc;
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the message must be routed*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
/* Check if the player belongs to the session :*/
if(uwNetGetPlayerIndex(pstMes->uxSenderId)==NetLib_C_uwInvalidPosition)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
/* Retrieve the player concerned :*/
ulPlayerId = *((NetLib_tduxPlayerId*)(pstMes + 1));
vFree(pstMes);
if(uwNetGetPlayerIndex(ulPlayerId)!=NetLib_C_uwInvalidPosition)
{
/* If somebody disconnects us from the session, quit it :*/
/* that is call the callback for all players */
if(NetLib_uxGetOwnPlayerId()==ulPlayerId)
{
stDoForAllDesc.m_pfn_eForAll = eNetDisconnectPlayer;
stDoForAllDesc.m_lParameter = 1;
stDoForAllDesc.m_eGoOnCondition = NetLib_E_es_NoError;
stDoForAllDesc.m_ucIncludeLocal = NetLib_C_ucNotIncludeLocalPlayer;
eErrorReturned = NetLib_eDoForAllPlayers(&stDoForAllDesc);
if (gs_uwMode==NetLib_Mode_Direct) vNetSetSessionId(M_ulNetPlayerIdSlot(&gs_stCurrentSession.d_stPlayerInfo[gs_stCurrentSession.uwIndexOfLocalPlayer]));
}
/* call the callback for the disconnected player (possibly the local player) ...*/
eErrorReturned=eNetDisconnectPlayer(ulPlayerId, 1);
return NetLib_E_es_NoError;
}
return NetLib_E_es_UnknownPlayerId;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eSwapLittleBigEndianSysMsgReadReceipt
Swap E_Net_mt_ReadReceipt message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 23,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body : -> ulReadReceiptId -> swap
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgReadReceipt(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
*((unsigned long *)(pstMes+1))=
M_NET_ulSwapLittleBigEndian(*((unsigned long *)(pstMes+1)));
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgReadReceipt
Handle E_Net_mt_ReadReceipt message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 17,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgReadReceipt(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tduxPlayerId uxSenderId;
NetLib_uxReadReceiptId ulReadReceiptId;
tdstNetInternalReadReceiptDesc *p_stInternalReadReceiptDesc;
tdstNetIter stIter;
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{/* the message must be routed*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError)
vFree(pstMes);
return eErrorReturned;
}
/* retrieve the read-receipt and sender id :*/
uxSenderId = pstMes->uxSenderId;
ulReadReceiptId = *((NetLib_uxReadReceiptId*)(pstMes + 1));
p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)
pNetList2IterInit(&stIter,&gs_stReadReceiptList);
while (p_stInternalReadReceiptDesc)
{
if ((p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_uxReadReceiptId == ulReadReceiptId)
&&(p_stInternalReadReceiptDesc->m_p_stMessage->uxRecipientId == uxSenderId))
{ /* we have found the player :*/
/* call the callback with the success flag*/
if(p_stInternalReadReceiptDesc->m_stReadReceiptDesc.p_fnv_ReadReceiptCallback)
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.p_fnv_ReadReceiptCallback(uxSenderId,
ulReadReceiptId,NetLib_C_ucReadReceiptSuccess,
p_stInternalReadReceiptDesc->m_stReadReceiptDesc.m_lCallbackParam);
/* remove the message :*/
eNetEraseInternalReadReceiptDesc(p_stInternalReadReceiptDesc);
pNetList2DeleteElem(&stIter);
break;
}
else p_stInternalReadReceiptDesc=(tdstNetInternalReadReceiptDesc*)pNetList2Next(&stIter);
}
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eSwapLittleBigEndianSysMsgMaxNbrOfPlayers
Swap E_Net_mt_MaxNbrOfPlayers message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 28,96
Author : Albert Pais
////////////////////////////////////////////////////////////////////////////////
Message body : -> uwNewNbrMax -> swap
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgMaxNbrOfPlayers(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
*((unsigned short*)(pstMes+1))=M_NET_uwSwapLittleBigEndian(*((unsigned short*)(pstMes+1)));
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgMaxNbrOfPlayers
Handles E_Net_mt_MaxNbrOfPlayers message
////////////////////////////////////////////////////////////////////////////////
Input : a pointer to the tdstNetIOSystemCell
////////////////////////////////////////////////////////////////////////////////
Output : A NetLib_tdeErrorStatus
////////////////////////////////////////////////////////////////////////////////
Creation date : October 28,96
Author : Albert Pais
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgMaxNbrOfPlayers(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
NetLib_tdeErrorStatus eErrorReturned;
if(pstMes->uxRecipientId != NetLib_uxGetOwnPlayerId())
{ /* the message must be routed*/
eErrorReturned = eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
if(eErrorReturned != NetLib_E_es_NoError) vFree(pstMes);
return eErrorReturned;
}
eErrorReturned = eNetInternalChangeMaxNbrOfPlayers(*((unsigned short*)(pstMes+1)));
if ((pstMes->m_uxReadReceiptId!=NetLib_C_ucNoReadReceipt)
&&(eErrorReturned == NetLib_E_es_NoError))
/* if read-receipt required :*/
eNetSendReadReceiptMessage(pstMes);
vFree(pstMes);
return eErrorReturned;
}
/*
------------------------------------------------------------------------------------------
INTERNET SIMULATION DELAY
------------------------------------------------------------------------------------------
*/
NetLib_tdeErrorStatus eInternetSimuSendMessage(NetLib_tduxPlayerId uxRecipientId,tdstNetMessage *pstMessage)
{
tdstMsgInfo *p_stNewMsg;
tdstNetIter stIter;
pNetList2IterInit(&stIter,&gs_stPlayerSendingList);
vNetList2ToEnd(&stIter);
p_stNewMsg=(tdstMsgInfo *)pNetList2ReservElem(&stIter,sizeof(tdstMsgInfo));
if(!p_stNewMsg) return NetLib_E_es_NotEnoughMemory;
p_stNewMsg->m_ulSendingTime = g_pfn_ulNetGetTimeInfo()+gs_ulInternetDelay+g_pfn_ulNetRandom()%(gs_ulInternetRandom+1);
p_stNewMsg->m_p_stMessage = pstMessage;
p_stNewMsg->m_ulPlayerId = uxRecipientId;
return NetLib_E_es_NoError;
}
NetLib_tdeErrorStatus eNetManageInternetDelay(void)
{
tdstMsgInfo *p_stNewMsg;
tdstNetIter stIter;
p_stNewMsg=(tdstMsgInfo *)pNetList2IterInit(&stIter,&gs_stPlayerSendingList);
while (p_stNewMsg)
{
if(g_pfn_ulNetGetTimeInfo() >= p_stNewMsg->m_ulSendingTime)
{
/* Its time to send the message :*/
eLevel1SendMessage(p_stNewMsg->m_p_stMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
p_stNewMsg=(tdstMsgInfo *)pNetList2DeleteElem(&stIter);
}
else p_stNewMsg=(tdstMsgInfo *)pNetList2Next(&stIter);
}
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
TCP reconection.
////////////////////////////////////////////////////////////////////////////////
Creation date : 24/1/97
Author : David Fournier
//////////////////////////////////////////////////////////////////////////////*/
static tdstTCPReconnectInterface gs_stReconnectInterface;
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus vNetInitTCPReconnect(void)
Initialize TCP reconnect interface.
//////////////////////////////////////////////////////////////////////////////*/
void vNetInitTCPReconnect(void)
{
gs_stReconnectInterface.pfn_eTCPReconnect=NULL;
gs_stReconnectInterface.pfn_eTCPGetPortAndAddress=NULL;
gs_stReconnectInterface.pfn_vTCPNewRouteKnown=NULL;
gs_stReconnectInterface.pfn_uwTCPGetNewReconnectChannel=NULL;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : tdstTCPReconnectInterface *pstNetGetTCPReconnectInterface(void)
Return TCP reconnect interface for initialisation.
//////////////////////////////////////////////////////////////////////////////*/
tdstTCPReconnectInterface *pstNetGetTCPReconnectInterface(void)
{
return &gs_stReconnectInterface;
}
#pragma pack(push)
#pragma pack(1)
typedef struct
{
unsigned long AdrIP;
unsigned short NumPort;
}tdstTCPAddress;
#pragma pack(pop)
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eNetSendTCPAddress(void)
Sends own TCP adresse to other players for they can reconect us directly.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetSendTCPAddress(void)
{
tdstNetMessage *p_stMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdstTCPAddress localTCPAddress;
if (!gs_stReconnectInterface.pfn_eTCPGetPortAndAddress) return NetLib_E_es_NoError;
if (gs_stReconnectInterface.pfn_eTCPGetPortAndAddress(&localTCPAddress.NumPort,&localTCPAddress.AdrIP)==NetLib_E_es_NoError)
{
if (localTCPAddress.NumPort!=0)
{
p_stMessage=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(tdstTCPAddress));
if(!p_stMessage) return NetLib_E_es_NotEnoughMemory;
p_stMessage->eMessageType = E_Net_mt_TCPAddress;
p_stMessage->uxRecipientId=C_uxNetBroadcastId;
p_stMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stMessage->uwMessageSizeInBytes = sizeof(tdstTCPAddress);
p_stMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stMessage->uxReplaceType = 0;
p_stMessage->uxReplace = 0;
p_stMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
*((tdstTCPAddress *)(p_stMessage+1))=localTCPAddress;
if(gs_ArtificialLatency) eErrorReturned=eInternetSimuSendMessage(C_uxNetBroadcastId,p_stMessage);
else eErrorReturned=eLevel1SendMessage(p_stMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned!=NetLib_E_es_NoError) vFree((tdpPointer)p_stMessage);
}
}
eErrorReturned=NetLib_E_es_NoError;
return eErrorReturned;
}
#pragma pack(push)
#pragma pack(1)
typedef struct
{
NetLib_tduxPlayerId IdPlayer;
char First;
}tdstTCPIsMe;
#pragma pack(pop)
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eNetSendTCPIsMe(void)
Send own Id on the new chanel for the remote player can update his rout table.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetSendTCPIsMe(tduwNetChannel uwChannel,char First)
{
tdstNetMessage *p_stMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdstTCPIsMe IsMe;
IsMe.First=First;
IsMe.IdPlayer=NetLib_uxGetOwnPlayerId();
p_stMessage=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(tdstTCPIsMe));
if(!p_stMessage) return NetLib_E_es_NotEnoughMemory;
p_stMessage->eMessageType = E_Net_mt_TCPIsMe;
p_stMessage->uwMessageSizeInBytes = sizeof(tdstTCPIsMe);
p_stMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stMessage->uxReplaceType = 0;
p_stMessage->uxReplace = 0;
p_stMessage->uxSenderId=IsMe.IdPlayer;
p_stMessage->uxRecipientId=C_uxNetBroadcastId;
p_stMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
*((tdstTCPIsMe *)(p_stMessage+1))=IsMe;
eErrorReturned=eLevel1SendMessage(p_stMessage,E_Net_pr_Windows95TCPProtocol,uwChannel);
if(eErrorReturned!=NetLib_E_es_NoError)
{
vFree((tdpPointer)p_stMessage);
}
return eErrorReturned;
}
#pragma pack(push)
#pragma pack(1)
typedef struct
{
NetLib_tduxPlayerId IdSource;
NetLib_tduxPlayerId IdDest;
}tdstTCPSupRoute;
#pragma pack(pop)
/*//////////////////////////////////////////////////////////////////////////////
Description : NetLib_tdeErrorStatus eNetSendTCPSupRoute(void)
Supprim a path in the broadcast table of all remote players.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus eNetSendTCPSupRoute(NetLib_tduxPlayerId IdSource,NetLib_tduxPlayerId IdDest)
{
tdstNetMessage *p_stMessage;
NetLib_tdeErrorStatus eErrorReturned;
tdstTCPSupRoute *pSupRout;
p_stMessage=(tdstNetMessage*)pMalloc(sizeof(tdstNetMessage)+sizeof(tdstTCPSupRoute));
if(!p_stMessage) return NetLib_E_es_NotEnoughMemory;
p_stMessage->eMessageType = E_Net_mt_TCPSupRoute;
p_stMessage->uxRecipientId=C_uxNetBroadcastId;
p_stMessage->uxSenderId=NetLib_uxGetOwnPlayerId();
p_stMessage->uwMessageSizeInBytes = sizeof(tdstTCPSupRoute);
p_stMessage->uxPriority = NetLib_C_uxMaxPriority;
p_stMessage->uxReplaceType = 0;
p_stMessage->uxReplace = 0;
p_stMessage->m_uxReadReceiptId = NetLib_C_ucNoReadReceipt;
pSupRout=(tdstTCPSupRoute *)(p_stMessage+1);
pSupRout->IdSource=IdSource;
pSupRout->IdDest=IdDest;
if(gs_ArtificialLatency) eErrorReturned=eInternetSimuSendMessage(C_uxNetBroadcastId,p_stMessage);
else eErrorReturned=eLevel1SendMessage(p_stMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
if(eErrorReturned!=NetLib_E_es_NoError) vFree((tdpPointer)p_stMessage);
return eErrorReturned;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgTCPAddress
Recept a demand of reconection direct with a TCP adress.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgTCPAddress(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdstTCPAddress *remoteTCPAddress;
if (!gs_stReconnectInterface.pfn_eTCPReconnect)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
if (vLevel1ExistBroadcastPath(NetLib_uxGetOwnPlayerId(),pstMes->uxSenderId))
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
remoteTCPAddress=(tdstTCPAddress *)(pstMes+1);
gs_stReconnectInterface.pfn_eTCPReconnect(remoteTCPAddress->NumPort,remoteTCPAddress->AdrIP);
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgTCPIsMe
Recept a demand of update the rout table for a player.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgTCPIsMe(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdstTCPIsMe *pIsMe;
if (!gs_stReconnectInterface.pfn_vTCPNewRouteKnown)
{
vFree(pstMes);
return NetLib_E_es_NoError;
}
pIsMe=(tdstTCPIsMe *)(pstMes+1);
eLevel1UpdateRouteOfPlayer(pstMes,eProt,uwChannel);
eNetSendTCPSupRoute(NetLib_uxGetOwnPlayerId(),pIsMe->IdPlayer);
if (pIsMe->First) eNetSendTCPIsMe(uwChannel,0);
if (gs_uwMode==NetLib_Mode_UBI) gs_stReconnectInterface.pfn_vTCPNewRouteKnown(uwChannel);
vFree(pstMes);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description :eHandleNetSysMsgTCPSupRoute
Supprim a broadcast path in the broadcast table.
//////////////////////////////////////////////////////////////////////////////*/
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgTCPSupRoute(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
{
tdstTCPSupRoute *pSupRout;
pSupRout=(tdstTCPSupRoute *)(pstMes+1);
vLevel1SupBroadcastPath(pSupRout->IdSource,pSupRout->IdDest);
return NetLib_E_es_NoError;
}
/*//////////////////////////////////////////////////////////////////////////////
Description : iNetEngineTCPReconect
Engine function : Handles getactive sessions.
//////////////////////////////////////////////////////////////////////////////*/
int _NET_CALLING_CONV_ iNetEngineTCPReconect(void)
{
tduwNetChannel uwChannel;
if (!gs_stReconnectInterface.pfn_uwTCPGetNewReconnectChannel) return 0;
uwChannel=gs_stReconnectInterface.pfn_uwTCPGetNewReconnectChannel();
if (uwChannel!=C_uwNetInvalidChannel) eNetSendTCPIsMe(uwChannel,1);
return 0;
}