331 lines
12 KiB
C
331 lines
12 KiB
C
/********************************************************************************/
|
|
/* */
|
|
/* NetSynch.c */
|
|
/* */
|
|
/* This file defines the synchronisation API */
|
|
/* */
|
|
/********************************************************************************/
|
|
|
|
|
|
/* Author: David Fournier
|
|
*
|
|
* Creation Date: 10/04/97
|
|
*/
|
|
|
|
|
|
#include "warnings.h"
|
|
#include "NetMemCo.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "Privnetser.h"
|
|
#include "PrivNetSynch.h"
|
|
|
|
typedef struct
|
|
{
|
|
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
|
|
unsigned long ulSizeMes; /* Size of message. */
|
|
}NetLib_tdstMesSynchro;
|
|
|
|
typedef struct _stRecSynchro
|
|
{
|
|
NetLib_tduxPlayerId PId; /* Player Id. */
|
|
struct _stRecSynchro *pNext; /* Next synchro message receipt. */
|
|
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
|
|
unsigned long ulSizeMes; /* Size of message. */
|
|
}NetLib_tdstRecSynchro;
|
|
|
|
typedef struct
|
|
{
|
|
NetLib_uxSynchroId uxSyncId; /* Synchro Id. */
|
|
NetLib_tduxPlayerId *pMarkPlayer; /* Array of players mark. */
|
|
NetLib_tduxPlayerId NbrPlayer; /* Number of remote player. */
|
|
NetLib_tdstRecSynchro *pRecSync; /* Array of synchro receipt. */
|
|
NetLib_tdulTimeInfo ulTimeEnd; /* Time of end process (begin + time out). */
|
|
NetLib_tdfnvSynchroCallback tdfnvCallback; /* CallBack for remote sync message. */
|
|
}NetLib_tdstInfoSynchro;
|
|
|
|
static NetLib_tdstInfoSynchro gs_tdstInfoSynchro; /* Informations of the current synchro. */
|
|
|
|
/*****************************************************************************
|
|
* Description: vNetLibInitSynchro
|
|
* Initialyze synchro module.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************/
|
|
void _NET_CALLING_CONV_ vNetLibInitSynchro(void)
|
|
{
|
|
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
|
|
gs_tdstInfoSynchro.pMarkPlayer=NULL;
|
|
gs_tdstInfoSynchro.ulTimeEnd=0;
|
|
gs_tdstInfoSynchro.pRecSync=NULL;
|
|
gs_tdstInfoSynchro.tdfnvCallback=NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eNetLibFreeSynchro
|
|
* Free synchro module.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************/
|
|
void _NET_CALLING_CONV_ vNetLibFreeSynchro(void)
|
|
{
|
|
NetLib_tdstRecSynchro *pRecSync,*pNext;
|
|
vFree(gs_tdstInfoSynchro.pMarkPlayer);
|
|
gs_tdstInfoSynchro.pMarkPlayer=NULL;
|
|
pRecSync=gs_tdstInfoSynchro.pRecSync;
|
|
while (pRecSync)
|
|
{
|
|
pNext=pRecSync->pNext;
|
|
vFree(pRecSync);
|
|
pRecSync=pNext;
|
|
}
|
|
gs_tdstInfoSynchro.pRecSync=NULL;
|
|
gs_tdstInfoSynchro.tdfnvCallback=NULL;
|
|
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eNetLibTestSynchro
|
|
* Return the synchro state.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus eNetLibTestSynchro(int bWithoutAck,NetLib_tduxPlayerId ucMaster)
|
|
{
|
|
NetLib_tduxPlayerId i;
|
|
NetLib_tdstRecSynchro *pRecSync;
|
|
if (!bWithoutAck)
|
|
{
|
|
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
|
|
{
|
|
if (gs_tdstInfoSynchro.pMarkPlayer[i]==C_uxNetInvalidId)
|
|
{
|
|
return NetLib_E_es_SynchroNoAck;
|
|
}
|
|
}
|
|
}
|
|
if (ucMaster==C_uxNetInvalidId)
|
|
{
|
|
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
|
|
{
|
|
pRecSync=gs_tdstInfoSynchro.pRecSync;
|
|
while (pRecSync)
|
|
{
|
|
if ((pRecSync->uxSyncId==gs_tdstInfoSynchro.uxSyncId) &&
|
|
(pRecSync->PId==gs_tdstInfoSynchro.pMarkPlayer[i])) break;
|
|
pRecSync=pRecSync->pNext;
|
|
}
|
|
if (!pRecSync) return NetLib_E_es_SynchroNoSync;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRecSync=gs_tdstInfoSynchro.pRecSync;
|
|
while (pRecSync)
|
|
{
|
|
if ((pRecSync->uxSyncId==gs_tdstInfoSynchro.uxSyncId) &&
|
|
(pRecSync->PId==ucMaster)) break;
|
|
pRecSync=pRecSync->pNext;
|
|
}
|
|
if (!pRecSync) return NetLib_E_es_SynchroNoSync;
|
|
}
|
|
return NetLib_E_es_SynchroOk;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vNetLib_AckSynchro
|
|
* Aknowledgment of a synchro message.
|
|
*****************************************************************************/
|
|
static void _NET_CALLING_CONV_ vNetLib_AckSynchro(NetLib_tduxPlayerId PId,
|
|
NetLib_uxReadReceiptId AId,NetLib_ucReadReceiptFlag Flag,long Param)
|
|
{
|
|
NetLib_tduxPlayerId i;
|
|
if ((Flag==NetLib_C_ucReadReceiptSuccess) && (AId==gs_tdstInfoSynchro.uxSyncId))
|
|
{
|
|
for (i=0;i<gs_tdstInfoSynchro.NbrPlayer;i++)
|
|
{
|
|
if (gs_tdstInfoSynchro.pMarkPlayer[i]==C_uxNetInvalidId)
|
|
{
|
|
gs_tdstInfoSynchro.pMarkPlayer[i]=PId;
|
|
break;
|
|
}
|
|
else if (gs_tdstInfoSynchro.pMarkPlayer[i]==PId) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: MemSwap
|
|
* Swap memory.
|
|
*****************************************************************************/
|
|
static void MemSwap(void *p,unsigned long s)
|
|
{
|
|
char *p1,*p2,c;
|
|
p1=(char *)p;
|
|
p2=p1+s;
|
|
s/=2;
|
|
while (s--)
|
|
{
|
|
c=*p1;
|
|
*(p1++)=*(--p2);
|
|
*p2=c;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eSwapLittleBigEndianSysMsgSynchro
|
|
* Swap synchro message.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eSwapLittleBigEndianSysMsgSynchro(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
NetLib_tdstMesSynchro *pMessage;
|
|
pMessage=(NetLib_tdstMesSynchro *)(pstMes+1);
|
|
MemSwap(&(pMessage->ulSizeMes),sizeof(unsigned long));
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eHandleNetSysMsgSynchro
|
|
* Receive a synchro message.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eHandleNetSysMsgSynchro(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
NetLib_tdstMesSynchro *pMessage;
|
|
NetLib_tdstRecSynchro **ppRecSync,*pRecSync,*pF;
|
|
|
|
if(pstMes->m_uxReadReceiptId!=C_uxNetInvalidId)
|
|
eNetSendReadReceiptMessage(pstMes);
|
|
|
|
pMessage=(NetLib_tdstMesSynchro *)(pstMes+1);
|
|
ppRecSync=&(gs_tdstInfoSynchro.pRecSync);
|
|
while (*ppRecSync)
|
|
{
|
|
pRecSync=*ppRecSync;
|
|
if ((pRecSync->uxSyncId==pMessage->uxSyncId) && (pRecSync->PId==pstMes->uxSenderId))
|
|
{ /* If an old synchro with same Id and same player */
|
|
pF=*ppRecSync; /* is already in the file, delete it. */
|
|
*ppRecSync=(*ppRecSync)->pNext;
|
|
vFree(pF);
|
|
}
|
|
else ppRecSync=&((*ppRecSync)->pNext);
|
|
}
|
|
pRecSync=(NetLib_tdstRecSynchro *)pMalloc(sizeof(NetLib_tdstRecSynchro)+pMessage->ulSizeMes);
|
|
pRecSync->PId=pstMes->uxSenderId;
|
|
pRecSync->pNext=NULL;
|
|
pRecSync->uxSyncId=pMessage->uxSyncId;
|
|
pRecSync->ulSizeMes=pMessage->ulSizeMes;
|
|
memcpy(pRecSync+1,pMessage+1,pMessage->ulSizeMes);
|
|
*ppRecSync=pRecSync;
|
|
vFree(pstMes);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eNetLibWaitSynchro
|
|
* Send a synchro message and wait synchro messages from all other players or from master.
|
|
*****************************************************************************
|
|
* Input: uxSyncId = Synchro id
|
|
* ulTimeOut = when time elapsed, function return NetLib_E_es_SynchroNoAck or NetLib_E_es_SynchroNoSync.
|
|
* pBufMes = Adress of the send message.
|
|
* ulSizeMes = Size of the send message.
|
|
* tdfnvCallback = CallBack for receipt remote player message.
|
|
* bWithoutAck = true (!=0) if send without acknoledment.
|
|
* ucMaster = Id of master if the synchro is master/slave.
|
|
* C_uxNetInvalidId if no master.
|
|
* Output: An error code.
|
|
* NetLib_E_es_SynchroWait : Synchro not finish.
|
|
* NetLib_E_es_SynchroOk : Synchro ok. All synchro messages players receipt
|
|
* and all player receive our message.
|
|
* NetLib_E_es_SynchroNoAck : Time out, acknoledgment missing for one or many players,
|
|
* NetLib_E_es_SynchroNoSync : or one or many synchro message missing.
|
|
* NetLib_E_es_NotEnoughMemory : Not enough memory for perform synchro.
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eNetLibWaitSynchro(NetLib_uxSynchroId uxSyncId,
|
|
NetLib_tdulTimeInfo ulTimeOut,void *pBufMes,unsigned long ulSizeMes,
|
|
NetLib_tdfnvSynchroCallback tdfnvCallback,int bWithoutAck,
|
|
NetLib_tduxPlayerId ucMaster)
|
|
{
|
|
NetLib_tduxPlayerId PId,OwnId;
|
|
NetLib_tdstSendDesc tdstSendDesc;
|
|
NetLib_tdstMesSynchro *pMessage;
|
|
NetLib_tdeErrorStatus eStatus;
|
|
NetLib_tdstRecSynchro *pRecSync;
|
|
|
|
if (gs_tdstInfoSynchro.uxSyncId!=uxSyncId)
|
|
{
|
|
gs_tdstInfoSynchro.uxSyncId=NetLib_C_InvalidSynchroId;
|
|
vFree(gs_tdstInfoSynchro.pMarkPlayer);
|
|
gs_tdstInfoSynchro.NbrPlayer=NetLib_uwGetTotalNumberPlayer()-1;
|
|
OwnId=NetLib_uxGetOwnPlayerId();
|
|
if (gs_tdstInfoSynchro.NbrPlayer==0) return NetLib_E_es_SynchroOk;
|
|
gs_tdstInfoSynchro.pMarkPlayer=pMalloc(sizeof(NetLib_tduxPlayerId)*gs_tdstInfoSynchro.NbrPlayer);
|
|
if (!gs_tdstInfoSynchro.pMarkPlayer) return NetLib_E_es_NotEnoughMemory;
|
|
pMessage=(NetLib_tdstMesSynchro *)pMalloc(ulSizeMes+sizeof(NetLib_tdstMesSynchro));
|
|
if (!pMessage)
|
|
{
|
|
vFree(gs_tdstInfoSynchro.pMarkPlayer);
|
|
gs_tdstInfoSynchro.pMarkPlayer=NULL;
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
if (OwnId==ucMaster) ucMaster=C_uxNetInvalidId;
|
|
for (PId=0;PId<gs_tdstInfoSynchro.NbrPlayer;PId++)
|
|
{
|
|
gs_tdstInfoSynchro.pMarkPlayer[PId]=C_uxNetInvalidId;
|
|
}
|
|
pMessage->uxSyncId=uxSyncId;
|
|
pMessage->ulSizeMes=ulSizeMes;
|
|
memcpy(pMessage+1,pBufMes,ulSizeMes);
|
|
|
|
gs_tdstInfoSynchro.uxSyncId=uxSyncId;
|
|
gs_tdstInfoSynchro.ulTimeEnd=GetTickCount()+ulTimeOut;
|
|
gs_tdstInfoSynchro.tdfnvCallback=tdfnvCallback;
|
|
if (ucMaster==C_uxNetInvalidId) tdstSendDesc.m_tduxRecipientId=C_uxNetBroadcastId;
|
|
else tdstSendDesc.m_tduxRecipientId=ucMaster;
|
|
tdstSendDesc.m_ulMaxWaitingTime=0;
|
|
tdstSendDesc.m_pMessageData=(char*)pMessage;
|
|
tdstSendDesc.m_uwMessageLength=ulSizeMes+sizeof(NetLib_tdstMesSynchro);
|
|
tdstSendDesc.m_uxPriority=0;
|
|
tdstSendDesc.m_uxReplaceType=0;
|
|
tdstSendDesc.m_uxReplaceFlag=NetLib_C_uxNoReplace;
|
|
if (!bWithoutAck)
|
|
{
|
|
tdstSendDesc.m_ucReadReceiptFlag=NetLib_C_ucReadReceiptRequired;
|
|
tdstSendDesc.m_stReadReceiptDesc.m_ulMaxWaitingTime=ulTimeOut;
|
|
tdstSendDesc.m_stReadReceiptDesc.m_ulReemitFreq=250;
|
|
tdstSendDesc.m_stReadReceiptDesc.m_uxReadReceiptId=uxSyncId;
|
|
tdstSendDesc.m_stReadReceiptDesc.m_lCallbackParam=uxSyncId;
|
|
tdstSendDesc.m_stReadReceiptDesc.p_fnv_ReadReceiptCallback=vNetLib_AckSynchro;
|
|
}
|
|
else
|
|
{
|
|
tdstSendDesc.m_ucReadReceiptFlag=NetLib_C_ucNoReadReceipt;
|
|
}
|
|
eNetInternalSendMessage(&tdstSendDesc,E_Net_mt_SysSynchro);
|
|
vFree(pMessage);
|
|
}
|
|
NetLib_vEngine();
|
|
eStatus=eNetLibTestSynchro(bWithoutAck,ucMaster);
|
|
if ((eStatus!=NetLib_E_es_SynchroOk) && (GetTickCount()<gs_tdstInfoSynchro.ulTimeEnd))
|
|
{
|
|
eStatus=NetLib_E_es_SynchroWait;
|
|
}
|
|
if (eStatus!=NetLib_E_es_SynchroWait)
|
|
{
|
|
if (tdfnvCallback)
|
|
{
|
|
pRecSync=gs_tdstInfoSynchro.pRecSync;
|
|
while (pRecSync)
|
|
{
|
|
if (pRecSync->uxSyncId==uxSyncId)
|
|
{
|
|
tdfnvCallback(pRecSync->PId,pRecSync->uxSyncId,pRecSync+1,pRecSync->ulSizeMes);
|
|
}
|
|
pRecSync=pRecSync->pNext;
|
|
}
|
|
}
|
|
vNetLibFreeSynchro();
|
|
}
|
|
return eStatus;
|
|
}
|
|
|