/********************************************************************************/ /* */ /* 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 #include #endif /*_NO_USE_DEFAULT_NET_FUNCTIONS_*/ #include #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 #include #include /* ------------------------------------------------------------------------------------------ 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 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;uwCurrentPlayerulPlayerId!=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;uwCurrentPlayerm_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 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 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 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ï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 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_uwCountuwNumberOfPlayers) && (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_uwCountuwNumberOfPlayers;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_uwCountuwNumberOfPlayers;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 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_uwCountwNewPlayer=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_ulMaxWaitingTimem_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_uwCountm_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 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_uwCurrentPlayerIndexuwMessageSizeInBytes = 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_uwCurrentPlayerIndexucMaxPlayerInfo?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_uwCurrentuwNumberOfPlayers;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_uwCounteMessageType = 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 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 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 ((uwSenderIndexuwNumberOfPlayers) &&(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_uwCount2d_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_uwCountuwNumberOfPlayers)&& (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;uwTimedPlayerIndexuxSenderId) { 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; }