2666 lines
107 KiB
C
2666 lines
107 KiB
C
/********************************************************************************/
|
|
/* */
|
|
/* NetL1.c */
|
|
/* */
|
|
/* This file defines the level 1 functions */
|
|
/* message routing and queueing */
|
|
/* */
|
|
/********************************************************************************/
|
|
|
|
#include "warnings.h"
|
|
#include "l0gldef.h"
|
|
|
|
#include "PrivNetDef.h"
|
|
#include "NetL1Pri.h"
|
|
#include "NetEnd.h"
|
|
#include "NetMemCo.h"
|
|
#include "NetList2.h"
|
|
#include <NET\NetDebug.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define C_MaxNbrElement 200L
|
|
|
|
typedef struct
|
|
{
|
|
tdeNetProtocol eProtocol;
|
|
tduwNetChannel uwChannel;
|
|
}tdstProtChannel;
|
|
|
|
typedef struct
|
|
{
|
|
tdstNetMessage *pMessage;
|
|
tdstProtChannel *dstTabDest;
|
|
unsigned short uwNbrDest;
|
|
}tdstNetL1Message;
|
|
|
|
/*
|
|
------------------------------------------------------------------------------------------
|
|
DEFINITION OF INTERNAL VARIABLES:
|
|
------------------------------------------------------------------------------------------
|
|
*/
|
|
/*
|
|
* there is one slot per non local player. any invalid identification field
|
|
* marks the slot as free for any incoming player.
|
|
*/
|
|
static tdstRouteCell *gs_d_stRouteTable;
|
|
|
|
static tdstNetList2 gs_stOutgoingMsgList;
|
|
static tdstNetList2 gs_stIncomingSysMsgList;
|
|
static tdstNetList2 gs_stIncomingEngineMsgList;
|
|
|
|
/* Maximum of remote players accepted in the session */
|
|
static unsigned short gs_uwMaxNumberOfRemotePlayers;
|
|
/* identification of the local player */
|
|
static NetLib_tduxPlayerId gs_ulLocalPlayerId;
|
|
/* identification of the session :*/
|
|
static NetLib_tduxSessionId gs_ulSessionId;
|
|
|
|
static short gs_wBroadcastIpx;
|
|
static NetLib_tduwMode gs_uwMode;
|
|
|
|
static unsigned short gs_uwMaxNbrOfMsgPerList;
|
|
static unsigned char *gs_dcRndList;
|
|
|
|
/* list of sessions which answered to our session request
|
|
* message. */
|
|
static tdstSessionCell *gs_p_stSessionCell;
|
|
|
|
/* dynamic array of available protocol identifiers, and the
|
|
* number of such protocols */
|
|
static tdstNetProtocolInterface *gs_d_stAvailableProtocolInterfaces;
|
|
static unsigned short gs_uwNumberOfProtocol;
|
|
|
|
/*
|
|
* Reemission mode
|
|
*/
|
|
static unsigned char gs_ucReemissionMode;
|
|
|
|
/* This type contain the list of player who should receive a broadcast message from a
|
|
player "SourcePlayer". */
|
|
typedef struct
|
|
{
|
|
NetLib_tduxPlayerId SourcePlayer; /* Source player. */
|
|
NetLib_tduxPlayerId NbrDestPlayer; /* Number of players who should receive a broadcast message. */
|
|
NetLib_tduxPlayerId *TabDestPlayer; /* Table of players who should receive a broadcast message. */
|
|
}BroadcastSource;
|
|
|
|
NetLib_tduxPlayerId NbrBroadcastSource; /* Number of source broadcast who must routing. */
|
|
BroadcastSource *TabBroadcastSource; /* Table of source broadcast who must routing. */
|
|
|
|
static NetLib_tdeErrorStatus eNetLevel1InsertNewMsg(tdstNetIter *pstIter,tdstNetL1Message *pstL1Message);
|
|
static NetLib_tdeErrorStatus eLevel1FillMessageHeader(tdstNetMessage *p_stMessage);
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1RandomList
|
|
* Return a random list of n first integer.
|
|
*****************************************************************************
|
|
* Input: Nbr : Number of random integer (should be less than 256).
|
|
* List : Array of integer.
|
|
* Output: none
|
|
****************************************************************************/
|
|
static void vLevel1RandomList(unsigned char Nbr,unsigned char *List)
|
|
{
|
|
int i,v;
|
|
char c;
|
|
for (i=0;i<Nbr;i++) List[i]=i;
|
|
for (i=Nbr-1;i>0;i--)
|
|
{
|
|
v=rand()%(i+1);
|
|
c=List[i];
|
|
List[i]=List[v];
|
|
List[v]=c;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SearchBroadcastSource
|
|
* Search a broadcast source.
|
|
*****************************************************************************/
|
|
static BroadcastSource *vLevel1SearchBroadcastSource(NetLib_tduxPlayerId SourcePlayer)
|
|
{
|
|
NetLib_tduxPlayerId i;
|
|
for (i=0;i<NbrBroadcastSource;i++)
|
|
{
|
|
if (TabBroadcastSource[i].SourcePlayer==SourcePlayer) return TabBroadcastSource+i;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1AddBroadcastSource
|
|
* Add a new broadcast source.
|
|
*****************************************************************************/
|
|
static BroadcastSource *vLevel1AddBroadcastSource(NetLib_tduxPlayerId SourcePlayer)
|
|
{
|
|
BroadcastSource *NewTab;
|
|
NewTab=(BroadcastSource *)pMalloc(sizeof(BroadcastSource)*(NbrBroadcastSource+1));
|
|
if (NewTab)
|
|
{
|
|
memcpy(NewTab,TabBroadcastSource,sizeof(BroadcastSource)*NbrBroadcastSource);
|
|
NewTab[NbrBroadcastSource].SourcePlayer=SourcePlayer;
|
|
NewTab[NbrBroadcastSource].NbrDestPlayer=0;
|
|
NewTab[NbrBroadcastSource].TabDestPlayer=NULL;
|
|
vFree((char *)TabBroadcastSource);
|
|
TabBroadcastSource=NewTab;
|
|
NbrBroadcastSource++;
|
|
return TabBroadcastSource+(NbrBroadcastSource-1);
|
|
}
|
|
else return NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SupBroadcastSource
|
|
* Supprim a broadcast source.
|
|
*****************************************************************************/
|
|
void vLevel1SupBroadcastSource(NetLib_tduxPlayerId SourcePlayer)
|
|
{
|
|
BroadcastSource *NewTab;
|
|
if (vLevel1SearchBroadcastSource(SourcePlayer))
|
|
{
|
|
if (NbrBroadcastSource>1)
|
|
{
|
|
NewTab=(BroadcastSource *)pMalloc(sizeof(BroadcastSource)*(NbrBroadcastSource-1));
|
|
if (NewTab)
|
|
{
|
|
NetLib_tduxPlayerId i,j;
|
|
for (i=0,j=0;i<NbrBroadcastSource;i++)
|
|
{
|
|
if (TabBroadcastSource[i].SourcePlayer==SourcePlayer) vFree((char *)TabBroadcastSource[i].TabDestPlayer);
|
|
else
|
|
{
|
|
NewTab[j]=TabBroadcastSource[i];
|
|
j++;
|
|
}
|
|
}
|
|
vFree((char *)TabBroadcastSource);
|
|
TabBroadcastSource=NewTab;
|
|
NbrBroadcastSource--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vFree((char *)TabBroadcastSource);
|
|
TabBroadcastSource=NULL;
|
|
NbrBroadcastSource=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1AddBroadcastPath
|
|
* Add a path into the broadcast table.
|
|
*****************************************************************************/
|
|
void vLevel1AddBroadcastPath(NetLib_tduxPlayerId SourcePlayer,NetLib_tduxPlayerId DestPlayer)
|
|
{
|
|
BroadcastSource *bs;
|
|
NetLib_tduxPlayerId *NewTab;
|
|
NetLib_tduxPlayerId i;
|
|
bs=vLevel1SearchBroadcastSource(SourcePlayer);
|
|
if (!bs) bs=vLevel1AddBroadcastSource(SourcePlayer);
|
|
if (!bs) return;
|
|
for (i=0;i<bs->NbrDestPlayer;i++)
|
|
{
|
|
if (bs->TabDestPlayer[i]==DestPlayer) return;
|
|
}
|
|
NewTab=(NetLib_tduxPlayerId *)pMalloc(sizeof(NetLib_tduxPlayerId)*(bs->NbrDestPlayer+1));
|
|
if (NewTab)
|
|
{
|
|
memcpy(NewTab,bs->TabDestPlayer,sizeof(NetLib_tduxPlayerId)*bs->NbrDestPlayer);
|
|
NewTab[bs->NbrDestPlayer]=DestPlayer;
|
|
vFree((char *)bs->TabDestPlayer);
|
|
bs->TabDestPlayer=NewTab;
|
|
bs->NbrDestPlayer++;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SupBroadcastPath
|
|
* Supprim a path into the broadcast table.
|
|
*****************************************************************************/
|
|
void vLevel1SupBroadcastPath(NetLib_tduxPlayerId SourcePlayer,NetLib_tduxPlayerId DestPlayer)
|
|
{
|
|
BroadcastSource *bs;
|
|
NetLib_tduxPlayerId *NewTab;
|
|
NetLib_tduxPlayerId i;
|
|
bs=vLevel1SearchBroadcastSource(SourcePlayer);
|
|
if (!bs) return;
|
|
for (i=0;i<bs->NbrDestPlayer;i++)
|
|
{
|
|
if (bs->TabDestPlayer[i]==DestPlayer)
|
|
{
|
|
if (bs->NbrDestPlayer==1) vLevel1SupBroadcastSource(SourcePlayer);
|
|
else
|
|
{
|
|
NewTab=(NetLib_tduxPlayerId *)pMalloc(sizeof(NetLib_tduxPlayerId)*(bs->NbrDestPlayer-1));
|
|
if (NewTab)
|
|
{
|
|
memcpy(NewTab,bs->TabDestPlayer,sizeof(NetLib_tduxPlayerId)*i);
|
|
memcpy(NewTab+i,bs->TabDestPlayer+i+1,sizeof(NetLib_tduxPlayerId)*(bs->NbrDestPlayer-i-1));
|
|
vFree((char *)bs->TabDestPlayer);
|
|
bs->TabDestPlayer=NewTab;
|
|
bs->NbrDestPlayer--;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SupBroadcastDest
|
|
* Supprim a destination into the broadcast table.
|
|
*****************************************************************************/
|
|
void vLevel1SupBroadcastDest(NetLib_tduxPlayerId DestPlayer)
|
|
{
|
|
BroadcastSource *bs;
|
|
NetLib_tduxPlayerId *NewTab;
|
|
NetLib_tduxPlayerId i,SourcePlayer;
|
|
for (SourcePlayer=0;SourcePlayer<NbrBroadcastSource;SourcePlayer++)
|
|
{
|
|
bs=TabBroadcastSource+SourcePlayer;
|
|
for (i=0;i<bs->NbrDestPlayer;i++)
|
|
{
|
|
if (bs->TabDestPlayer[i]==DestPlayer)
|
|
{
|
|
if (bs->NbrDestPlayer==1) vLevel1SupBroadcastSource(SourcePlayer);
|
|
else
|
|
{
|
|
NewTab=(NetLib_tduxPlayerId *)pMalloc(sizeof(NetLib_tduxPlayerId)*(bs->NbrDestPlayer-1));
|
|
if (NewTab)
|
|
{
|
|
memcpy(NewTab,bs->TabDestPlayer,sizeof(NetLib_tduxPlayerId)*i);
|
|
memcpy(NewTab+i,bs->TabDestPlayer+i+1,sizeof(NetLib_tduxPlayerId)*(bs->NbrDestPlayer-i-1));
|
|
vFree((char *)bs->TabDestPlayer);
|
|
bs->TabDestPlayer=NewTab;
|
|
bs->NbrDestPlayer--;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1ExistBroadcastPath
|
|
* Return non zero value if path exist.
|
|
*****************************************************************************/
|
|
int vLevel1ExistBroadcastPath(NetLib_tduxPlayerId SourcePlayer,NetLib_tduxPlayerId DestPlayer)
|
|
{
|
|
BroadcastSource *bs;
|
|
NetLib_tduxPlayerId i;
|
|
bs=vLevel1SearchBroadcastSource(SourcePlayer);
|
|
if (!bs) return 0;
|
|
for (i=0;i<bs->NbrDestPlayer;i++)
|
|
{
|
|
if (bs->TabDestPlayer[i]==DestPlayer) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1GetBroadcastSource
|
|
* Return the table of destination players who should receive a broadcast message
|
|
* from a source player.
|
|
* If no dest, TabDestPlayer is set to NULL, and NbrDestPlayer is set to 0.
|
|
*****************************************************************************/
|
|
static void vLevel1GetBroadcastSource(NetLib_tduxPlayerId SourcePlayer,NetLib_tduxPlayerId **TabDestPlayer,NetLib_tduxPlayerId *NbrDestPlayer)
|
|
{
|
|
BroadcastSource *bs;
|
|
bs=vLevel1SearchBroadcastSource(SourcePlayer);
|
|
if (bs)
|
|
{
|
|
*TabDestPlayer=bs->TabDestPlayer;
|
|
*NbrDestPlayer=bs->NbrDestPlayer;
|
|
}
|
|
else
|
|
{
|
|
*TabDestPlayer=NULL;
|
|
*NbrDestPlayer=0;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1KillBroadcastTab
|
|
* Dereserv the table of broadcast source.
|
|
*****************************************************************************/
|
|
static void vLevel1KillBroadcastTab(void)
|
|
{
|
|
NetLib_tduxPlayerId i;
|
|
for (i=0;i<NbrBroadcastSource;i++)
|
|
{
|
|
vFree((char *)TabBroadcastSource[i].TabDestPlayer);
|
|
}
|
|
vFree((char *)TabBroadcastSource);
|
|
TabBroadcastSource=NULL;
|
|
NbrBroadcastSource=0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description : eLevel1SetBroadcastState
|
|
* Set the broadcast state.
|
|
*****************************************************************************/
|
|
void vLevel1SetBroadcastState(short BroadcastIpx)
|
|
{
|
|
gs_wBroadcastIpx=BroadcastIpx;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1UpdateRouteOfPlayer
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the received message.
|
|
* Output: none
|
|
****************************************************************************/
|
|
void eLevel1UpdateRouteOfPlayer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
short wIndexInRouteTable;
|
|
wIndexInRouteTable = wLevel1IndexInRouteTable(pstMes->uxSenderId);
|
|
if (wIndexInRouteTable>=0)
|
|
{
|
|
gs_d_stRouteTable[wIndexInRouteTable].eProtocol=eProt;
|
|
gs_d_stRouteTable[wIndexInRouteTable].uwChannel=uwChannel;
|
|
vLevel1AddBroadcastPath(gs_ulLocalPlayerId,pstMes->uxSenderId);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SetReemissionMode
|
|
* Sets the reemission mode
|
|
*****************************************************************************
|
|
* Input: ucNewReemissionMode : the new reemission mode
|
|
* -> 0 : the message is not reemited in case of problem
|
|
* -> 1 : the message is reemited in case of problem
|
|
* Output: None.
|
|
*****************************************************************************
|
|
* Creation Date: April 12, 1996 Author: Albert Pais
|
|
*****************************************************************************/
|
|
void vLevel1SetReemissionMode(unsigned char ucNewReemissionMode)
|
|
{
|
|
gs_ucReemissionMode = ucNewReemissionMode;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: ucLevel1GetReemissionMode
|
|
* Gets the reemission mode
|
|
*****************************************************************************
|
|
* Input: None
|
|
* Output: The reemission mode :
|
|
* -> 0 : the message is not reemited in case of problem
|
|
* -> 1 : the message is reemited in case of problem
|
|
*****************************************************************************
|
|
* Creation Date: April 12, 1996 Author: Albert Pais
|
|
*****************************************************************************/
|
|
unsigned char ucLevel1GetReemissionMode(void)
|
|
{
|
|
return gs_ucReemissionMode;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: wLevel1IndexInRouteTable
|
|
* Retrieves the index in the dynamic route table of the route structure
|
|
* for a given player identification.
|
|
*****************************************************************************
|
|
* Input: ulPlayerId, the identification of the specified player.
|
|
* Output: the index in the gs_d_stRouteTable dynamic array if the player
|
|
* has an entry, else -1.
|
|
*****************************************************************************
|
|
* Creation Date: April 2, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 16, 1996 Author: Albert PAIS
|
|
* Comment : if called with C_uxNetInvalidId, returns a free slot
|
|
****************************************************************************/
|
|
short wLevel1IndexInRouteTable(NetLib_tduxPlayerId ulPlayerId)
|
|
{
|
|
short wRouteIndex;
|
|
|
|
/* if the player is not the local player */
|
|
if (ulPlayerId != gs_ulLocalPlayerId)
|
|
{
|
|
/* scan the route table */
|
|
wRouteIndex = gs_uwMaxNumberOfRemotePlayers-1;
|
|
while((wRouteIndex >= 0) && (gs_d_stRouteTable[wRouteIndex].ulPlayerId != ulPlayerId))
|
|
wRouteIndex --;
|
|
/*Tip : if no player was found in the list, wRouteIndex value is -1, that is to
|
|
say the invalid index :*/
|
|
return wRouteIndex;
|
|
}
|
|
return (short)-1;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : NetLib_tdeErrorStatus eLevel1IsSendingListEmpty(NetLib_tduxPlayerId ulPlayerId)
|
|
Tells if the sending list of the player is empty or not
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A player id
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_True if the sending list is empty
|
|
NetLib_E_es_False if not
|
|
NetLib_E_es_UnknownPlayerId if the id is unknown
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : April 15, 96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eLevel1IsSendingListEmpty(NetLib_tduxPlayerId ulPlayerId)
|
|
{
|
|
if (ulNetList2NbrElem(&gs_stOutgoingMsgList)) return NetLib_E_es_False; /* the list is not empty :*/
|
|
else return NetLib_E_es_True; /* the list is empty :*/
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : NetLib_tdeErrorStatus eLevel1IsSendingListOk(NetLib_tduxPlayerId ulPlayerId)
|
|
Tells if the sending list of the player is ok
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A player id
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if the sending list is ok
|
|
NetLib_E_es_UnknownPlayerId if the player is unknown
|
|
an error code otherwise
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : April 15, 96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eLevel1IsSendingListOk(NetLib_tduxPlayerId ulPlayerId)
|
|
{
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: p_stInterfaceOfProtocol
|
|
* scans the protocol interfaces and retrieves the one we want.
|
|
*****************************************************************************
|
|
* Input: eProtocol, the identification of the protocol we need.
|
|
* Output: pointer on the interface structure of this protocol.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
tdstNetProtocolInterface *p_stLevel1GetInterfaceOfProtocol(tdeNetProtocol eProtocol)
|
|
{
|
|
unsigned char ucProtocolIndex;
|
|
|
|
/* scan all protocol interface entries */
|
|
for (ucProtocolIndex=0;ucProtocolIndex<gs_uwNumberOfProtocol;ucProtocolIndex++) {
|
|
/* if we found the one we want */
|
|
if (gs_d_stAvailableProtocolInterfaces[ucProtocolIndex].eProtocol == eProtocol)
|
|
return gs_d_stAvailableProtocolInterfaces+ucProtocolIndex;
|
|
}
|
|
/* else return a C_pNull pointer */
|
|
return (tdstNetProtocolInterface *) C_pNull;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1SendMessage
|
|
* Delivers the given message in the outgoing queue of the recipient.
|
|
*****************************************************************************
|
|
* Input: uxRecipientId, the recipient player's identification number.
|
|
* p_stMessageToSend, a pointer to a message structure followed by
|
|
* the corresponding message body.
|
|
* Output: an error condition depending on the action's result.
|
|
*****************************************************************************
|
|
* Creation Date: April 2, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1SendMessage(tdstNetMessage *p_stMessageToSend,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message stL1Message;
|
|
short wIndexInRouteTable,i,j;
|
|
tdstProtChannel stProtChannel;
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
int bTCP=0;
|
|
|
|
/* if the recipient is in the route table */
|
|
if ((eProt==E_Net_pr_InvalidProtocol) && (uwChannel==C_uwNetInvalidChannel) &&
|
|
(wLevel1IndexInRouteTable(p_stMessageToSend->uxRecipientId)==-1) &&
|
|
(p_stMessageToSend->uxRecipientId != C_uxNetBroadcastId) &&
|
|
(p_stMessageToSend->uxRecipientId != C_uxNetInvalidId))
|
|
/* warn that the recipient is not known */
|
|
return NetLib_E_es_UnknownPlayerId;
|
|
|
|
stL1Message.pMessage=p_stMessageToSend;
|
|
if (p_stMessageToSend->uxRecipientId != C_uxNetBroadcastId)
|
|
{
|
|
stL1Message.uwNbrDest=1;
|
|
stL1Message.dstTabDest=(tdstProtChannel *)pMalloc(stL1Message.uwNbrDest*sizeof(tdstProtChannel));
|
|
if ((eProt!=E_Net_pr_InvalidProtocol) && (uwChannel!=C_uwNetInvalidChannel))
|
|
{
|
|
/*
|
|
CHRISTOPHE
|
|
commented out to allow connection denial messages to be handled properly
|
|
--- but it may have side effects ?
|
|
|
|
p_stMessageToSend->uxRecipientId=C_uxNetInvalidId;
|
|
*/ stL1Message.dstTabDest->eProtocol=eProt;
|
|
stL1Message.dstTabDest->uwChannel=uwChannel;
|
|
}
|
|
else
|
|
{
|
|
wIndexInRouteTable = wLevel1IndexInRouteTable(p_stMessageToSend->uxRecipientId);
|
|
if (wIndexInRouteTable>=0)
|
|
{
|
|
stL1Message.dstTabDest->eProtocol=gs_d_stRouteTable[wIndexInRouteTable].eProtocol;
|
|
stL1Message.dstTabDest->uwChannel=gs_d_stRouteTable[wIndexInRouteTable].uwChannel;
|
|
}
|
|
else return NetLib_E_es_UnknownPlayerId;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NetLib_tduxPlayerId *TabDestPlayer,NbrDestPlayer;
|
|
vLevel1GetBroadcastSource(p_stMessageToSend->uxSenderId,&TabDestPlayer,&NbrDestPlayer);
|
|
if (!NbrDestPlayer)
|
|
{
|
|
vFree(p_stMessageToSend);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
stL1Message.uwNbrDest=0;
|
|
stL1Message.dstTabDest=(tdstProtChannel *)pMalloc(NbrDestPlayer*sizeof(tdstProtChannel));
|
|
if (!stL1Message.dstTabDest) return NetLib_E_es_NotEnoughMemory;
|
|
vLevel1RandomList(NbrDestPlayer,gs_dcRndList);
|
|
if (gs_uwMode==NetLib_Mode_UBI)
|
|
{
|
|
for (i=0;i<NbrDestPlayer;i++)
|
|
{
|
|
wIndexInRouteTable = wLevel1IndexInRouteTable(TabDestPlayer[gs_dcRndList[i]]);
|
|
if (wIndexInRouteTable>=0)
|
|
{
|
|
stProtChannel.eProtocol=gs_d_stRouteTable[wIndexInRouteTable].eProtocol;
|
|
if (stProtChannel.eProtocol==E_Net_pr_Windows95TCPProtocol)
|
|
bTCP=1;
|
|
}
|
|
}
|
|
}
|
|
for (i=0;i<NbrDestPlayer;i++)
|
|
{
|
|
wIndexInRouteTable = wLevel1IndexInRouteTable(TabDestPlayer[gs_dcRndList[i]]);
|
|
if (wIndexInRouteTable>=0)
|
|
{
|
|
stProtChannel.eProtocol=gs_d_stRouteTable[wIndexInRouteTable].eProtocol;
|
|
if ((stProtChannel.eProtocol==E_Net_pr_Windows95IPXProtocol) && gs_wBroadcastIpx)
|
|
{
|
|
p_stProtocolInterface=p_stLevel1GetInterfaceOfProtocol(E_Net_pr_Windows95IPXProtocol);
|
|
stProtChannel.uwChannel=p_stProtocolInterface->fn_uwStartBroadcastChannelScan();
|
|
}
|
|
else stProtChannel.uwChannel=gs_d_stRouteTable[wIndexInRouteTable].uwChannel;
|
|
if ((bTCP) && (stProtChannel.eProtocol==E_Net_pr_Windows95GSUBIProtocol))
|
|
{
|
|
stProtChannel.uwChannel=TabDestPlayer[gs_dcRndList[i]]+2;
|
|
}
|
|
for (j=0;j<stL1Message.uwNbrDest;j++)
|
|
{
|
|
if (memcmp(stL1Message.dstTabDest+j,&stProtChannel,sizeof(tdstProtChannel))==0)
|
|
break;
|
|
}
|
|
if (j==stL1Message.uwNbrDest)
|
|
{
|
|
memcpy(stL1Message.dstTabDest+j,&stProtChannel,sizeof(tdstProtChannel));
|
|
stL1Message.uwNbrDest++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* fill standard slots of the header : */
|
|
eLevel1FillMessageHeader(stL1Message.pMessage);
|
|
pNetList2IterInit(&stIter,&gs_stOutgoingMsgList);
|
|
return eNetLevel1InsertNewMsg(&stIter,&stL1Message);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1GoesToIP
|
|
* tells whether the next step in a route to a player is through an "internet"
|
|
* protocol
|
|
*****************************************************************************
|
|
* Input: uxRecipientId, the recipient player's identification number.
|
|
* Output: an error condition depending on the action's result.
|
|
*****************************************************************************
|
|
* Creation Date: December 17, 1996 Author: Christophe Roguet
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1GoesToIP(NetLib_tduxPlayerId uxRecipientId)
|
|
{
|
|
short wIndexInRouteTable;
|
|
|
|
/* if the recipient is in the route table */
|
|
if ((uxRecipientId == C_uxNetInvalidId) ||
|
|
((wIndexInRouteTable = wLevel1IndexInRouteTable(uxRecipientId)) == -1))
|
|
/* warn that the recipient is not known */
|
|
return NetLib_E_es_UnknownPlayerId;
|
|
|
|
return gs_d_stAvailableProtocolInterfaces[gs_d_stRouteTable[wIndexInRouteTable].eProtocol].eIsInternet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1ReadMessage
|
|
* Retrieves a pointer to the next incoming message addressed to the specified
|
|
* player.
|
|
*****************************************************************************
|
|
* Input: ulPlayerId, identification number of the recipient.
|
|
* pp_stMessage, pointer to the variable that will hold the address
|
|
* of the read message.
|
|
* Output: the location pointed by pp_stMessage is modified to hold the
|
|
* address of the retrieved message. An error condition is returned.
|
|
*****************************************************************************
|
|
* Creation Date: April 2, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1ReadMessage(NetLib_tduxPlayerId ulPlayerId,tdstNetMessage **pp_stMessage,unsigned char bRemoveFromQueue)
|
|
{
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message *pL1Mes;
|
|
pL1Mes=(tdstNetL1Message*)pNetList2IterInit(&stIter,&gs_stIncomingEngineMsgList);
|
|
if (ulPlayerId!=C_uxNetBroadcastId)
|
|
{
|
|
while (pL1Mes)
|
|
{
|
|
if (pL1Mes->pMessage->uxSenderId==ulPlayerId) break;
|
|
pL1Mes=pNetList2Next(&stIter);
|
|
}
|
|
}
|
|
if (pL1Mes)
|
|
{
|
|
*pp_stMessage=pL1Mes->pMessage;
|
|
if (bRemoveFromQueue)
|
|
{
|
|
vFree(pL1Mes->dstTabDest);
|
|
pNetList2DeleteElem(&stIter);
|
|
}
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_FIFOIsEmpty;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1SendSessionRequestMsg
|
|
*****************************************************************************
|
|
* Creation Date: Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 16, 1996 Author: Albert Pais
|
|
* Adding some errors
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1SendSessionRequestMsg(NetLib_tduxDescriptionLength uxMaxPlayerInfo)
|
|
{
|
|
tdstNetMessage *p_stMessage;
|
|
unsigned char ucProtocolIndex;
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
tduwNetChannel uwChannel;
|
|
|
|
/* scan all protocols */
|
|
for (ucProtocolIndex = 0;ucProtocolIndex < gs_uwNumberOfProtocol;ucProtocolIndex ++)
|
|
{
|
|
p_stProtocolInterface = &gs_d_stAvailableProtocolInterfaces[ucProtocolIndex];
|
|
|
|
uwChannel = p_stProtocolInterface->fn_uwStartBroadcastChannelScan();
|
|
|
|
/* scan all broadcast interfaces of the protocol */
|
|
while (uwChannel != C_uwNetInvalidChannel)
|
|
{
|
|
/* allocate and setup a new message with an empty body */
|
|
p_stMessage = (tdstNetMessage *) pMalloc(sizeof(tdstNetMessage)+sizeof(NetLib_tduxDescriptionLength));
|
|
if(p_stMessage == (tdstNetMessage*)C_pNull) return NetLib_E_es_NotEnoughMemory;
|
|
|
|
p_stMessage->eMessageType = E_Net_mt_SysRequestActiveSessions;
|
|
p_stMessage->uxRecipientId = C_uxNetInvalidId;
|
|
p_stMessage->uxSenderId = gs_ulLocalPlayerId;
|
|
p_stMessage->uwMessageSizeInBytes = sizeof(NetLib_tduxDescriptionLength);
|
|
*((NetLib_tduxDescriptionLength*)(p_stMessage+1))=uxMaxPlayerInfo;
|
|
|
|
/* store the message in the outgoing system message queue */
|
|
if (eLevel1SendMessage(p_stMessage,p_stProtocolInterface->eProtocol,uwChannel)!=NetLib_E_es_NoError)
|
|
{/* the last message couldn't be sent, so delete it first*/
|
|
vFree((tdpPointer)p_stMessage);
|
|
p_stMessage = (tdstNetMessage*)C_pNull;
|
|
return NetLib_E_es_FIFOIsFull;
|
|
}
|
|
/* go to next broadcast channel of the protocol */
|
|
uwChannel = p_stProtocolInterface->fn_uwNextBroadcastChannel(uwChannel);
|
|
}/* end of while */
|
|
}
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1HandleSysMsgUnknownSender
|
|
* Handles an incoming message saying that its sender field (which thus does
|
|
* not necessarily specify its effective sender) contains the identification
|
|
* of an invalid player.
|
|
*****************************************************************************
|
|
* Input: p_stMessage, pointer to the incoming message that tells me all
|
|
* about it
|
|
* Output: an error condition depending on the handling's result.
|
|
*****************************************************************************
|
|
* Creation Date: April 2, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1HandleSysMsgUnknownSender(tdstNetMessage *p_stMessage)
|
|
{
|
|
short wIndexInRouteTable;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
/* if the recipient is the local player */
|
|
if (p_stMessage->uxRecipientId == gs_ulLocalPlayerId)
|
|
{
|
|
/* if the sender has an entry in the route table */
|
|
if ((p_stMessage->uxSenderId != C_uxNetInvalidId)&&
|
|
((wIndexInRouteTable = wLevel1IndexInRouteTable(p_stMessage->uxSenderId)) != -1))
|
|
{
|
|
/* free the memory allocated for this message */
|
|
vFree((tdpPointer) p_stMessage);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else
|
|
{/* don't care any more */
|
|
vFree((tdpPointer) p_stMessage);
|
|
return NetLib_E_es_UnknownSenderId;
|
|
}
|
|
}
|
|
/* the recipient is not the local player */
|
|
else
|
|
{
|
|
/* if the recipient has an entry in the route table */
|
|
p_stMessage->uxPriority = NetLib_C_uxMaxPriority;
|
|
p_stMessage->uxReplaceType = 0;
|
|
p_stMessage->uxReplace = 0;
|
|
if((eErrorReturned = eLevel1SendMessage(p_stMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel))
|
|
!=NetLib_E_es_NoError)
|
|
{/* We don't care any more about the message :*/
|
|
vFree((tdpPointer)p_stMessage);
|
|
return eErrorReturned;
|
|
}
|
|
/*else*/
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1HandleSysMsgUnknownRecipient
|
|
* Handles an incoming message saying that the full message its contains has
|
|
* an initial unknown recipient.
|
|
*****************************************************************************
|
|
* Input: p_stMessage, pointer to the message annoucing the information.
|
|
* Output: an error condition depending on the handling's result.
|
|
*****************************************************************************
|
|
* Creation Date: April 2, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1HandleSysMsgUnknownRecipient(tdstNetMessage *p_stMessage)
|
|
{
|
|
tdstNetMessage *p_stReturnedMessage;
|
|
short wIndexInRouteTable;
|
|
|
|
/* if the recipient is the local player */
|
|
if (p_stMessage->uxRecipientId == gs_ulLocalPlayerId)
|
|
{
|
|
/* the message body is in itself a full-fledged message */
|
|
p_stReturnedMessage = p_stMessage + 1;
|
|
/* if the original recipient is in the route table */
|
|
if ((p_stReturnedMessage->uxRecipientId != C_uxNetInvalidId)&&
|
|
((wIndexInRouteTable = wLevel1IndexInRouteTable(p_stReturnedMessage->uxRecipientId)) != -1))
|
|
{
|
|
/* free the memory allocated for this message */
|
|
vFree( (tdpPointer) p_stMessage);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else
|
|
{
|
|
vFree((tdpPointer)p_stMessage);
|
|
return NetLib_E_es_UnknownInitialRecipient;
|
|
}
|
|
}
|
|
/* the recipient is not the local player */
|
|
else
|
|
{
|
|
/* if the recipient is in the route table */
|
|
if ((p_stMessage->uxRecipientId != C_uxNetInvalidId)&&
|
|
((wIndexInRouteTable = wLevel1IndexInRouteTable(p_stMessage->uxRecipientId)) != -1))
|
|
{
|
|
/* queue the full message in his outgoing queue */
|
|
p_stMessage->uxPriority = NetLib_C_uxMaxPriority;
|
|
p_stMessage->uxReplaceType = 0;
|
|
p_stMessage->uxReplace = 0;
|
|
if(eLevel1SendMessage(p_stMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel)!= NetLib_E_es_NoError)
|
|
{
|
|
vFree((tdpPointer)p_stMessage);
|
|
return NetLib_E_es_FIFOIsFull;
|
|
}
|
|
/*else*/
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else
|
|
{
|
|
vFree((tdpPointer)p_stMessage);
|
|
p_stMessage = (tdstNetMessage*)C_pNull;
|
|
return NetLib_E_es_UnknownRecipientId;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1RouteSysMsg
|
|
* route system messages to their proper recipients, or issues adequate
|
|
* system messages to warn in case of internal problem.
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the system message to handle.
|
|
* Output: an error condition depending on the handling's result.
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1RouteSysMsg(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
short wIndexInRouteTable;
|
|
tdstNetMessage *p_stNewMessage;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
if ((pstMes->uxRecipientId == gs_ulLocalPlayerId)&&
|
|
(pstMes->uxSenderId != C_uxNetInvalidId)&&
|
|
(wLevel1IndexInRouteTable(pstMes->uxSenderId) == -1))
|
|
{
|
|
/* return the message to its sender */
|
|
pstMes->eMessageType = E_Net_mt_SysUnknownSender;
|
|
pstMes->uxRecipientId = pstMes->uxSenderId;
|
|
return eLevel1SendMessage(pstMes,eProt,uwChannel);
|
|
}
|
|
|
|
/* if the initial recipient is not the local player */
|
|
if (pstMes->uxRecipientId != gs_ulLocalPlayerId)
|
|
{
|
|
/* if the initial recipient is in the route table */
|
|
if ((pstMes->uxRecipientId != C_uxNetInvalidId)&&
|
|
((wIndexInRouteTable=wLevel1IndexInRouteTable(pstMes->uxRecipientId)) != -1))
|
|
{
|
|
eErrorReturned=eLevel1SendMessage(pstMes,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
|
|
return eErrorReturned;
|
|
}
|
|
/* recipient is not in the route table */
|
|
else
|
|
{
|
|
/* build a new message to return the initial one to its sender */
|
|
p_stNewMessage = (tdstNetMessage *) pMalloc(2 * sizeof(tdstNetMessage) + pstMes->uwMessageSizeInBytes);
|
|
if(p_stNewMessage)
|
|
{
|
|
p_stNewMessage->eMessageType = E_Net_mt_SysUnknownRecipient;
|
|
p_stNewMessage->uxRecipientId = pstMes->uxSenderId;
|
|
p_stNewMessage->uxSenderId = gs_ulLocalPlayerId;
|
|
p_stNewMessage->uxPriority = NetLib_C_uxMaxPriority;
|
|
p_stNewMessage->uxReplaceType = 0;
|
|
p_stNewMessage->uxReplace = 0;
|
|
/* The size of the new message is the old size plus the header size :*/
|
|
p_stNewMessage->uwMessageSizeInBytes = pstMes->uwMessageSizeInBytes + sizeof(tdstNetMessage);
|
|
g_pfn_vNetMemcpy(p_stNewMessage + 1, pstMes, p_stNewMessage->uwMessageSizeInBytes);
|
|
|
|
/* free the old message */
|
|
vFree(pstMes);
|
|
|
|
/* if the recipient (initial sender) is in the route table */
|
|
if ((p_stNewMessage->uxRecipientId != C_uxNetInvalidId)&&
|
|
((wIndexInRouteTable = wLevel1IndexInRouteTable(p_stNewMessage->uxRecipientId)) != -1))
|
|
{
|
|
eErrorReturned = eLevel1SendMessage(p_stNewMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
|
|
if(eErrorReturned != NetLib_E_es_NoError)
|
|
{
|
|
vFree((tdpPointer) p_stNewMessage);
|
|
}
|
|
}
|
|
else
|
|
/* the recipient is not in the route table */
|
|
{
|
|
eErrorReturned = eLevel1SendMessage(p_stNewMessage,eProt,uwChannel);
|
|
if(eErrorReturned != NetLib_E_es_NoError)
|
|
{
|
|
vFree((tdpPointer)p_stNewMessage);
|
|
}
|
|
}
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
}
|
|
else return NetLib_E_es_ShouldNotReach;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1HandleSysMsgFullBuffer
|
|
* Handle an incoming message saying that its body could not be retrieved by
|
|
* its original recipient because of buffer shortage. What we have to do is
|
|
* either reemit the message if we were the initial sender, or route the
|
|
* warning to the initial sender.
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the system message structure.
|
|
* Output: an error condition depending on the handling's result.
|
|
*****************************************************************************
|
|
* Creation Date: April 3, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1HandleSysMsgFullBuffer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
short wIndexInRouteTable;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
/* if the recipient is the local player and the sender is in the route table */
|
|
if ((pstMes->uxRecipientId == gs_ulLocalPlayerId) &&
|
|
((wIndexInRouteTable=wLevel1IndexInRouteTable(pstMes->uxSenderId))!=-1))
|
|
{
|
|
if (gs_ucReemissionMode /* in reemission mode : the message is resent*/)
|
|
{
|
|
/*
|
|
* we have to make sure that the address of the re-sent message is the
|
|
* start address of a memory block, else it would not be freed after
|
|
* being sent (which is of the sending machanism's responsibility).
|
|
* to solve this we can either free the head of the block (which is
|
|
* time consuming), create a new message from scratch (which also
|
|
* requires to copy the full message body), or move the initial message
|
|
* to the top of the memory block, which is much simpler.
|
|
*/
|
|
memmove(pstMes,pstMes+1,sizeof(tdstNetMessage)+pstMes->uwMessageSizeInBytes);
|
|
|
|
pstMes->uxRecipientId = pstMes->uxSenderId;
|
|
pstMes->uxSenderId = gs_ulLocalPlayerId;
|
|
eErrorReturned=eLevel1SendMessage(pstMes,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
|
|
|
|
if (eErrorReturned != NetLib_E_es_NoError)
|
|
{
|
|
/* Free the message */
|
|
vFree(pstMes);
|
|
}
|
|
|
|
return eErrorReturned;
|
|
}
|
|
else
|
|
{ /*gs_ucReemissionMode equals 0 so the message is not reemited*/
|
|
/* we dont care, the message is lost forever... */
|
|
vFree(pstMes);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
}
|
|
else return eLevel1RouteSysMsg(pstMes,eProt,uwChannel);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1FillNewRouteCell
|
|
* Allocate memory and initialize the route structure for a player so that
|
|
* incoming, outgoing and transiting messages can be handled for the specified
|
|
* player.
|
|
*****************************************************************************
|
|
* Input: p_stRouteCell, pointer to the structure to initialize.
|
|
* ulPlayerId, identification of the player.
|
|
* eProtocol, uwChannel, physical route information to know which
|
|
* physical channel is to be used to address this player.
|
|
* Output: an error condition depending on the actions' results.
|
|
*****************************************************************************
|
|
* Creation Date: April 3, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 16, 1996 Author: Albert Pais
|
|
* Adding some errors management
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1FillNewRouteCell(tdstRouteCell *p_stRouteCell,NetLib_tduxPlayerId ulPlayerId,tdeNetProtocol eProtocol,tduwNetChannel uwChannel)
|
|
{
|
|
/* fill the route and identification fields */
|
|
p_stRouteCell->ulPlayerId = ulPlayerId;
|
|
p_stRouteCell->eProtocol = eProtocol;
|
|
p_stRouteCell->uwChannel = uwChannel;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1AddNewSession
|
|
* Adds the session described by the incoming system message in the internal
|
|
* active session database.
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, the incoming message.
|
|
* Output: an error condition.
|
|
*****************************************************************************
|
|
* Creation Date: April 3, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 16, 1996 Author: Albert Pais
|
|
* Adding some error management
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1AddNewSession(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
tdstSessionCell *p_stNewSessionCell, *p_stCurrentSessionCell, *p_stPrevSessionCell;
|
|
NetLib_tduxSessionId ulNewSessionId;
|
|
tdpPointer pMessageBody;
|
|
unsigned short uwIndex;
|
|
|
|
/* read the session identifier from the message body */
|
|
pMessageBody = (tdpPointer) (pstMes + 1);
|
|
ulNewSessionId = *((NetLib_tduxSessionId *)pMessageBody);
|
|
pMessageBody+=sizeof(NetLib_tduxSessionId);
|
|
/*
|
|
* scan all previous answers we got about active sessions.
|
|
* if an answer with the same session id was already received,
|
|
* we simply return an error message.
|
|
*/
|
|
p_stPrevSessionCell = (tdstSessionCell *)C_pNull;
|
|
p_stCurrentSessionCell = gs_p_stSessionCell;
|
|
while (p_stCurrentSessionCell)
|
|
{
|
|
if (p_stCurrentSessionCell->ulSessionId == ulNewSessionId)
|
|
return NetLib_E_es_SessionIdAlreadyAcknowledged;
|
|
|
|
p_stPrevSessionCell = p_stCurrentSessionCell;
|
|
p_stCurrentSessionCell = p_stCurrentSessionCell->p_stNextSessionCell;
|
|
}
|
|
|
|
/*
|
|
* here we know that the session descriptor we just received is
|
|
* not in our internal database.
|
|
*/
|
|
|
|
/* allocate a new session descriptor structure */
|
|
p_stNewSessionCell = (tdstSessionCell *) pMalloc(sizeof(tdstSessionCell));
|
|
if (!p_stNewSessionCell) return NetLib_E_es_NotEnoughMemory;
|
|
|
|
/* and fill it with data we read from the message body */
|
|
p_stNewSessionCell->ulSessionId = ulNewSessionId;
|
|
p_stNewSessionCell->uwMaxNumberOfPlayers = (*((unsigned short *)pMessageBody))-1;
|
|
pMessageBody+=sizeof(unsigned short);
|
|
p_stNewSessionCell->uwNumberOfPlayers = *((unsigned short *)pMessageBody);
|
|
pMessageBody+=sizeof(unsigned short);
|
|
p_stNewSessionCell->d_stRouteCell = (tdstRouteCell*)C_pNull;
|
|
|
|
/* there is no following structure in the linked list */
|
|
p_stNewSessionCell->p_stNextSessionCell = (tdstSessionCell *)C_pNull;
|
|
|
|
/* allocate route info pointer array for the new session's players */
|
|
p_stNewSessionCell->d_stRouteCell=(tdstRouteCell *)pMalloc(p_stNewSessionCell->uwMaxNumberOfPlayers * sizeof(tdstRouteCell));
|
|
if (!(p_stNewSessionCell->d_stRouteCell))
|
|
{
|
|
vFree((tdpPointer) p_stNewSessionCell);
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
|
|
/* and fill it with data from the message body */
|
|
for (uwIndex=0;uwIndex<p_stNewSessionCell->uwNumberOfPlayers;uwIndex++,
|
|
pMessageBody+=sizeof(NetLib_tduxPlayerId))
|
|
{
|
|
/* store the player id */
|
|
if(eLevel1FillNewRouteCell(&p_stNewSessionCell->d_stRouteCell[uwIndex],
|
|
*((NetLib_tduxPlayerId *)pMessageBody),eProt,uwChannel
|
|
) != NetLib_E_es_NoError)
|
|
{
|
|
vFree((tdpPointer)p_stNewSessionCell->d_stRouteCell);
|
|
vFree((tdpPointer)p_stNewSessionCell);
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}/* No more problem */
|
|
}
|
|
|
|
for (uwIndex=p_stNewSessionCell->uwNumberOfPlayers;uwIndex<p_stNewSessionCell->uwMaxNumberOfPlayers;uwIndex++)
|
|
{
|
|
p_stNewSessionCell->d_stRouteCell[uwIndex].ulPlayerId = C_uxNetInvalidId;
|
|
p_stNewSessionCell->d_stRouteCell[uwIndex].eProtocol = E_Net_pr_InvalidProtocol;
|
|
p_stNewSessionCell->d_stRouteCell[uwIndex].uwChannel = C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/* insert the new session cell at the end of the queue */
|
|
p_stNewSessionCell->p_stNextSessionCell = gs_p_stSessionCell;
|
|
gs_p_stSessionCell = p_stNewSessionCell;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1BuildRouteInfo
|
|
* Changes the route information for a player when we receive a message
|
|
* directly from him.
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the received message.
|
|
* Output: an error condition.
|
|
*****************************************************************************
|
|
* Creation Date: April 3, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 16, 1996 Author: Albert Pais
|
|
* Some changes to manage errors and avoid too long debuging
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1BuildRouteInfoOfSessionPlayer(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
unsigned short uwIndex;
|
|
/*
|
|
* scan the player list of this session for the identification number of
|
|
* the sender of this message
|
|
*/
|
|
uwIndex = 0;
|
|
while((uwIndex < gs_uwMaxNumberOfRemotePlayers)&&
|
|
(gs_d_stRouteTable[uwIndex].ulPlayerId!= pstMes->uxSenderId))
|
|
uwIndex++;
|
|
/* if the sender is in the route table of this session */
|
|
if (uwIndex<gs_uwMaxNumberOfRemotePlayers)
|
|
{
|
|
/* update the physical path for this player */
|
|
gs_d_stRouteTable[uwIndex].eProtocol = eProt;
|
|
gs_d_stRouteTable[uwIndex].uwChannel = uwChannel;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
return NetLib_E_es_UnknownSenderId;
|
|
}
|
|
|
|
NetLib_tdeErrorStatus eLevel1BuildRouteInfo(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
tdstSessionCell *p_stCurrentSessionCell;
|
|
NetLib_tduxSessionId ulNewSessionId;
|
|
tdpPointer pMessageBody;
|
|
unsigned short uwIndex;
|
|
|
|
/* read the session identifier from the message body */
|
|
pMessageBody = (tdpPointer) (pstMes + 1);
|
|
ulNewSessionId = *((unsigned char *)pMessageBody);
|
|
|
|
/*
|
|
* scan all previous answers we got about active sessions.
|
|
* if an answer with the same session id was already received,
|
|
* lets stop there.
|
|
*/
|
|
p_stCurrentSessionCell = gs_p_stSessionCell;
|
|
while ((p_stCurrentSessionCell)&&(p_stCurrentSessionCell->ulSessionId != ulNewSessionId))
|
|
{
|
|
p_stCurrentSessionCell = p_stCurrentSessionCell->p_stNextSessionCell;
|
|
}
|
|
|
|
/*
|
|
* if no session information about the session this message describes
|
|
* is found ,this is an error
|
|
*/
|
|
if (!p_stCurrentSessionCell) return NetLib_E_es_UnknownSessionId;
|
|
|
|
/*
|
|
* scan the player list of this session for the identification number of
|
|
* the sender of this message
|
|
*/
|
|
uwIndex = 0;
|
|
while((uwIndex < p_stCurrentSessionCell->uwMaxNumberOfPlayers)&&
|
|
(p_stCurrentSessionCell->d_stRouteCell[uwIndex].ulPlayerId!= pstMes->uxSenderId))
|
|
uwIndex++;
|
|
/* if the sender is in the route table of this session */
|
|
if (uwIndex<p_stCurrentSessionCell->uwMaxNumberOfPlayers)
|
|
{
|
|
/* update the physical path for this player */
|
|
p_stCurrentSessionCell->d_stRouteCell[uwIndex].eProtocol = eProt;
|
|
p_stCurrentSessionCell->d_stRouteCell[uwIndex].uwChannel = uwChannel;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
/* if we arrive here, no entry for this player was found in the session's route */
|
|
return NetLib_E_es_UnknownSenderId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1UpdateRouteInfo
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the received message.
|
|
* Output: an error code
|
|
*****************************************************************************
|
|
* Creation Date: Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1UpdateRouteInfo(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
tdstSessionCell *p_stCurrentSessionCell, *p_stPrevSessionCell;
|
|
NetLib_tduxSessionId ulNewSessionId;
|
|
unsigned short uwNewNumberOfPlayers;
|
|
tdpPointer pMessageBody;
|
|
|
|
/* read the session identifier from the message body */
|
|
pMessageBody = (tdpPointer) (pstMes + 1);
|
|
ulNewSessionId = *((NetLib_tduxSessionId*)pMessageBody);
|
|
pMessageBody+=sizeof(NetLib_tduxSessionId);
|
|
|
|
/* scan all previous answers we got about active sessions.
|
|
* if an answer with the same session id was already received,
|
|
* lets stop there. */
|
|
p_stPrevSessionCell = (tdstSessionCell *)C_pNull;
|
|
p_stCurrentSessionCell = gs_p_stSessionCell;
|
|
while ((p_stCurrentSessionCell)&&(p_stCurrentSessionCell->ulSessionId != ulNewSessionId))
|
|
{
|
|
p_stPrevSessionCell = p_stCurrentSessionCell;
|
|
p_stCurrentSessionCell = p_stCurrentSessionCell->p_stNextSessionCell;
|
|
}
|
|
|
|
/* if no session information about the session this message describes
|
|
* is found ,this is an error */
|
|
if (!p_stCurrentSessionCell) return NetLib_E_es_UnknownSessionId;
|
|
else
|
|
{
|
|
typedef struct tdstPlayerMix_
|
|
{
|
|
NetLib_tduxPlayerId ulPlayerId;
|
|
unsigned short uwIndexInOldRoute;
|
|
unsigned char ucOldNew;
|
|
}tdstPlayerMix;
|
|
|
|
tdstPlayerMix *d_stPlayerMix;
|
|
unsigned short uwNbMixedPlayers, uwOldPlayerIndex, uwNewPlayerIndex, uwRouteIndex;
|
|
unsigned char b_ucInNewList;
|
|
|
|
/* skip max number of players */
|
|
pMessageBody=(tdpPointer)(((unsigned short *)pMessageBody)+1);
|
|
/* read number of players listed in the message */
|
|
uwNewNumberOfPlayers = *((unsigned short*)pMessageBody);
|
|
pMessageBody+=sizeof(unsigned short);
|
|
|
|
/* allocate a few structures... */
|
|
d_stPlayerMix = (tdstPlayerMix *)pMalloc(sizeof(tdstPlayerMix)*(uwNewNumberOfPlayers + p_stCurrentSessionCell->uwNumberOfPlayers));
|
|
if(!d_stPlayerMix) return NetLib_E_es_NotEnoughMemory;
|
|
|
|
/* read the list of player ids in the message */
|
|
for (uwNbMixedPlayers=0;uwNbMixedPlayers < uwNewNumberOfPlayers;uwNbMixedPlayers ++)
|
|
{
|
|
/* read the player id */
|
|
d_stPlayerMix[uwNbMixedPlayers].ulPlayerId = *((NetLib_tduxPlayerId*)pMessageBody);
|
|
pMessageBody+=sizeof(NetLib_tduxPlayerId);
|
|
/* the id was seen in the 'new' list */
|
|
d_stPlayerMix[uwNbMixedPlayers].ucOldNew = 0x0F;
|
|
}
|
|
|
|
/* scan player ids of the 'old' list */
|
|
for (uwOldPlayerIndex=0;uwOldPlayerIndex<p_stCurrentSessionCell->uwNumberOfPlayers;uwOldPlayerIndex ++)
|
|
{
|
|
b_ucInNewList = 0;
|
|
/* look if they appear in the 'new' list */
|
|
for (uwNewPlayerIndex=0;uwNewPlayerIndex<uwNewNumberOfPlayers;uwNewPlayerIndex++)
|
|
{
|
|
if (p_stCurrentSessionCell->d_stRouteCell[uwOldPlayerIndex].ulPlayerId
|
|
== d_stPlayerMix[uwNewPlayerIndex].ulPlayerId)
|
|
{
|
|
/* remember the index of the player id in the old route array */
|
|
d_stPlayerMix[uwNewPlayerIndex].uwIndexInOldRoute = uwOldPlayerIndex;
|
|
/* this entry in the 'new' list is also 'old' */
|
|
d_stPlayerMix[uwNewPlayerIndex].ucOldNew |= 0xF0;
|
|
b_ucInNewList = 1;
|
|
break;
|
|
}
|
|
}
|
|
/* if this 'old' player id is not in the 'new' list */
|
|
if(!b_ucInNewList)
|
|
{
|
|
/* remember the index of the player id in the old route array */
|
|
d_stPlayerMix[uwNbMixedPlayers].uwIndexInOldRoute=uwOldPlayerIndex;
|
|
/* add the entry, saying that this is an 'old' player id */
|
|
d_stPlayerMix[uwNbMixedPlayers].ulPlayerId=p_stCurrentSessionCell->d_stRouteCell[uwOldPlayerIndex].ulPlayerId;
|
|
d_stPlayerMix[uwNbMixedPlayers].ucOldNew = 0xF0;
|
|
uwNbMixedPlayers ++;
|
|
}
|
|
}
|
|
/* now all players, old, new and both are listed in the PlayerMix array.
|
|
* the exclusively new have a ucOldNew = 0x0F
|
|
* the exclusively old have a ucOldNew = 0xF0
|
|
* those is both lists have a ucOldNew = 0xFF */
|
|
|
|
/* scan the mixed list */
|
|
for (uwNewPlayerIndex = 0;uwNewPlayerIndex < uwNbMixedPlayers;uwNewPlayerIndex ++)
|
|
{
|
|
switch (d_stPlayerMix[uwNewPlayerIndex].ucOldNew)
|
|
{
|
|
/* if this is player id was exclusively in the old list */
|
|
case 0xF0:
|
|
p_stCurrentSessionCell->d_stRouteCell[d_stPlayerMix[uwNewPlayerIndex].uwIndexInOldRoute].ulPlayerId = C_uxNetInvalidId;
|
|
p_stCurrentSessionCell->d_stRouteCell[d_stPlayerMix[uwNewPlayerIndex].uwIndexInOldRoute].eProtocol = E_Net_pr_InvalidProtocol;
|
|
break;
|
|
|
|
/* if this is player id was exclusively in the new list */
|
|
case 0x0F:
|
|
/* look for a free slot in the route table of the session */
|
|
for (uwRouteIndex=0;uwRouteIndex<p_stCurrentSessionCell->uwMaxNumberOfPlayers;uwRouteIndex++)
|
|
if (p_stCurrentSessionCell->d_stRouteCell[uwRouteIndex].ulPlayerId == C_uxNetInvalidId)
|
|
{
|
|
/* store the route for the 'new' player in this slot */
|
|
eLevel1FillNewRouteCell(&p_stCurrentSessionCell->d_stRouteCell[uwRouteIndex],
|
|
d_stPlayerMix[uwNewPlayerIndex].ulPlayerId,
|
|
eProt,uwChannel);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* if this is player id was in both lists */
|
|
case 0xFF:
|
|
/* update it */
|
|
p_stCurrentSessionCell->d_stRouteCell[d_stPlayerMix[uwNewPlayerIndex].uwIndexInOldRoute].eProtocol = eProt;
|
|
p_stCurrentSessionCell->d_stRouteCell[d_stPlayerMix[uwNewPlayerIndex].uwIndexInOldRoute].uwChannel = uwChannel;
|
|
break;
|
|
|
|
/* if this player was in none of the lists */
|
|
default:
|
|
/* theoretically impossible... */
|
|
break;
|
|
}
|
|
}
|
|
/* we no longer need the mixed list of player identification structures */
|
|
vFree((tdpPointer) d_stPlayerMix);
|
|
}
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SetPlayerId
|
|
* Sets the internal variable telling the identification of the local player.
|
|
*****************************************************************************
|
|
* Input: ulPlayerId, the new identification of the local player.
|
|
* Output: none.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
void vLevel1SetPlayerId(NetLib_tduxPlayerId ulPlayerId)
|
|
{
|
|
gs_ulLocalPlayerId = ulPlayerId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1SetSessionId
|
|
* Sets the internal variable telling the identification of the session.
|
|
*****************************************************************************
|
|
* Input: ulSessionId, the new identification of the local player.
|
|
* Output: none.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
void vLevel1SetSessionId(NetLib_tduxPlayerId ulSessionId)
|
|
{
|
|
gs_ulSessionId = ulSessionId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1DestroySessionCellList
|
|
* Free all memory used to store information about the routes of the
|
|
* sessions who replied to the presence request.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
void vLevel1DestroySessionCellList(void)
|
|
{
|
|
tdstSessionCell *p_stSessionCell;
|
|
unsigned short uwPlayerIndex;
|
|
|
|
/* while there is a session */
|
|
while (gs_p_stSessionCell)
|
|
{
|
|
/* cut the head from the linked list */
|
|
p_stSessionCell = gs_p_stSessionCell;
|
|
gs_p_stSessionCell = gs_p_stSessionCell->p_stNextSessionCell;
|
|
|
|
/* scan the route table for this session */
|
|
for (uwPlayerIndex=0;uwPlayerIndex<p_stSessionCell->uwMaxNumberOfPlayers;uwPlayerIndex++)
|
|
{
|
|
/* if this slot contains info about a player of the session */
|
|
if (p_stSessionCell->d_stRouteCell[uwPlayerIndex].ulPlayerId != C_uxNetInvalidId)
|
|
{
|
|
/* Close the channel used :*/
|
|
vLevel1NetCloseChannel(p_stSessionCell->d_stRouteCell[uwPlayerIndex].eProtocol,
|
|
p_stSessionCell->d_stRouteCell[uwPlayerIndex].uwChannel,
|
|
p_stSessionCell->d_stRouteCell[uwPlayerIndex].ulPlayerId);
|
|
}
|
|
}
|
|
|
|
/* free the route information array */
|
|
vFree((tdpPointer) p_stSessionCell->d_stRouteCell);
|
|
vFree((tdpPointer)p_stSessionCell);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1StripSessionList
|
|
* Remove all session information but for the session of specified id.
|
|
*****************************************************************************
|
|
* Creation Date: Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1StripSessionList(NetLib_tduxSessionId ulSessionIdToKeep)
|
|
{
|
|
tdstSessionCell *p_stSessionCell, *p_stPrevSessionCell;
|
|
|
|
/* start at the beginning of the linked list */
|
|
p_stPrevSessionCell = (tdstSessionCell*)C_pNull;
|
|
p_stSessionCell = gs_p_stSessionCell;
|
|
|
|
/* scan the list for a session with the specified identification */
|
|
while (p_stSessionCell && p_stSessionCell->ulSessionId != ulSessionIdToKeep)
|
|
{
|
|
/* remember the session we come from */
|
|
p_stPrevSessionCell = p_stSessionCell;
|
|
/* go to the next session */
|
|
p_stSessionCell = p_stSessionCell->p_stNextSessionCell;
|
|
}
|
|
|
|
/* if we found one */
|
|
if (p_stSessionCell)
|
|
{
|
|
/*
|
|
* if it is not the first session in the list, make the previous
|
|
* session skip the one we found, else make the list start at the
|
|
* session following the one we chose.
|
|
*/
|
|
if (p_stPrevSessionCell)
|
|
p_stPrevSessionCell->p_stNextSessionCell = p_stSessionCell->p_stNextSessionCell;
|
|
else
|
|
gs_p_stSessionCell = p_stSessionCell->p_stNextSessionCell;
|
|
|
|
/* keep reference on the session's route table in our internal table */
|
|
if(gs_d_stRouteTable)
|
|
{
|
|
vFree((tdpPointer)gs_d_stRouteTable);
|
|
gs_d_stRouteTable = (tdstRouteCell *)C_pNull;
|
|
}
|
|
gs_d_stRouteTable = p_stSessionCell->d_stRouteCell;
|
|
gs_uwMaxNumberOfRemotePlayers = p_stSessionCell->uwMaxNumberOfPlayers;
|
|
vFree(p_stSessionCell);
|
|
/* now the session we want is no longer in the session list */
|
|
vLevel1DestroySessionCellList();
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_UnknownSessionId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1HandleSysMsgConnectRequest
|
|
* stores information about a player requesting to join the session.
|
|
*****************************************************************************
|
|
* Input: p_stIOSystemCell, pointer to the system message.
|
|
* Output: an error condition.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1HandleSysMsgConnectRequest(tdstNetMessage *pstMes,tdeNetProtocol eProt,tduwNetChannel uwChannel)
|
|
{
|
|
short wFreeSlot;
|
|
|
|
/* if no route info about the sender of the message is found */
|
|
if (wLevel1IndexInRouteTable(pstMes->uxSenderId) == -1)
|
|
{
|
|
/* get a free slot index */
|
|
if ((wFreeSlot = wLevel1IndexInRouteTable(C_uxNetInvalidId)) != -1)
|
|
{
|
|
/* setup the information for this new route info */
|
|
gs_d_stRouteTable[wFreeSlot].ulPlayerId = pstMes->uxSenderId;
|
|
gs_d_stRouteTable[wFreeSlot].eProtocol = eProt;
|
|
gs_d_stRouteTable[wFreeSlot].uwChannel = uwChannel;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_RouteTableIsFull;
|
|
}
|
|
else return NetLib_E_es_IdAlreadyInRouteTable;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1DisconnectRemotePlayer
|
|
* Remove route information about the specified player.
|
|
*****************************************************************************
|
|
* Input: ulRemotePlayerId, identification of the player to disconnect.
|
|
* Output: an error condition.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1DisconnectRemotePlayer(NetLib_tduxPlayerId ulRemotePlayerId)
|
|
{
|
|
short wIndexInRouteTable;
|
|
short wCurrentIndex;
|
|
tdstRouteCell *p_stRouteCell;
|
|
|
|
/* if the remote player is in the route table */
|
|
if ((wIndexInRouteTable = wLevel1IndexInRouteTable(ulRemotePlayerId)) != -1)
|
|
{
|
|
p_stRouteCell = &gs_d_stRouteTable[wIndexInRouteTable];
|
|
|
|
/* Check if no one use any more this protocol :*/
|
|
/* Ask the corresponding protocol to close the channel */
|
|
wCurrentIndex = 0;
|
|
while ((wCurrentIndex<gs_uwMaxNumberOfRemotePlayers)&&
|
|
(gs_d_stRouteTable[wCurrentIndex].eProtocol !=p_stRouteCell->eProtocol)&&
|
|
(gs_d_stRouteTable[wCurrentIndex].uwChannel !=p_stRouteCell->uwChannel))
|
|
wCurrentIndex++;
|
|
|
|
if ((wCurrentIndex>=gs_uwMaxNumberOfRemotePlayers)&&
|
|
(p_stRouteCell->eProtocol != E_Net_pr_InvalidProtocol))
|
|
{
|
|
vLevel1NetCloseChannel(p_stRouteCell->eProtocol,p_stRouteCell->uwChannel,p_stRouteCell->ulPlayerId);
|
|
}
|
|
/* make the route info invalid */
|
|
p_stRouteCell->ulPlayerId = C_uxNetInvalidId;
|
|
p_stRouteCell->eProtocol = E_Net_pr_InvalidProtocol;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_UnknownPlayerId;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1GetSysMsg
|
|
* retrieves the next incoming system message in the system message queue.
|
|
*****************************************************************************
|
|
* Input: pointer to the variable that will store the address of the
|
|
* retrieved message.
|
|
* Output: an error condition depending on the action's success.
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1GetSysMsg(tdstNetMessage **ppstMes,tdeNetProtocol *pProt,tduwNetChannel *pChannel)
|
|
{
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message *pL1Mes;
|
|
pL1Mes=(tdstNetL1Message*)pNetList2IterInit(&stIter,&gs_stIncomingSysMsgList);
|
|
if (pL1Mes)
|
|
{
|
|
*ppstMes=pL1Mes->pMessage;
|
|
if (pL1Mes->dstTabDest)
|
|
{
|
|
*pProt=pL1Mes->dstTabDest->eProtocol;
|
|
*pChannel=pL1Mes->dstTabDest->uwChannel;
|
|
}
|
|
else
|
|
{
|
|
*pProt=E_Net_pr_InvalidProtocol;
|
|
*pChannel=E_Net_pr_InvalidProtocol;
|
|
}
|
|
vFree(pL1Mes->dstTabDest);
|
|
pNetList2DeleteElem(&stIter);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else return NetLib_E_es_FIFOIsEmpty;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eLevel1NetUpdateSendStatus
|
|
Makes the correspondance beetween a NetLib_tdeErrorStatus and a tdeNetTransferStatus
|
|
in order to update a send status
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : NetLib_tdeErrorStatus
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : tdeNetTransferStatus
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : June 17,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
tdeNetTransferStatus eLevel1NetUpdateSendStatus(NetLib_tdeErrorStatus eErrorStatus)
|
|
{
|
|
switch(eErrorStatus)
|
|
{
|
|
case NetLib_E_es_ChannelIsInvalid:
|
|
return E_ts_Invalid;
|
|
case NetLib_E_es_InvalidChannel:
|
|
return E_ts_InvalidChannel;
|
|
case NetLib_E_es_ChannelUninitialized:
|
|
return E_ts_ChannelUnitialized;
|
|
case NetLib_E_es_NoError :
|
|
return E_ts_OK;
|
|
case NetLib_E_es_EmissionInProgress:
|
|
return E_ts_EmissionInProgress;
|
|
case NetLib_E_es_SendSocketFailure :
|
|
case NetLib_E_es_MessagePartlySent :
|
|
return E_ts_PacketFailure;
|
|
default :
|
|
return E_ts_OK;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1OutgoingNetEngine
|
|
* Handles outgoing messages queues. Initiates level 0 emission of a new
|
|
* message if a channel is free.
|
|
* Random version.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
****************************************************************************/
|
|
void vLevel1OutgoingNetEngine(void)
|
|
{
|
|
unsigned short BitProtocol=0,BitAllProt;
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message *pstL1Msg;
|
|
tdstNetMessage *pSndMsgBroad,*pstSndMsg;
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
int bMesSent;
|
|
tdeNetProtocol eProtocol;
|
|
tduwNetChannel uwChannel;
|
|
short i;
|
|
|
|
BitAllProt=(0xFFFF>>(16-gs_uwNumberOfProtocol));
|
|
pstL1Msg=(tdstNetL1Message *)pNetList2IterInit(&stIter,&gs_stOutgoingMsgList);
|
|
while ((pstL1Msg) && (BitProtocol!=BitAllProt))
|
|
{
|
|
pstSndMsg=pstL1Msg->pMessage;
|
|
for (i=0;i<pstL1Msg->uwNbrDest;)
|
|
{
|
|
bMesSent=0;
|
|
eProtocol=pstL1Msg->dstTabDest[i].eProtocol;
|
|
if (!(BitProtocol & (1<<eProtocol)))
|
|
{
|
|
uwChannel=pstL1Msg->dstTabDest[i].uwChannel;
|
|
p_stProtocolInterface=p_stLevel1GetInterfaceOfProtocol(eProtocol);
|
|
eErrorReturned=eLevel1NetUpdateSendStatus(p_stProtocolInterface->fn_eQueryChannelStatus(uwChannel));
|
|
if (eErrorReturned == E_ts_OK)
|
|
{
|
|
pSndMsgBroad=(tdstNetMessage *)pMalloc(sizeof(tdstNetMessage)+pstSndMsg->uwMessageSizeInBytes);
|
|
if (!pSndMsgBroad) break;
|
|
memcpy(pSndMsgBroad,pstSndMsg,sizeof(tdstNetMessage)+pstSndMsg->uwMessageSizeInBytes);
|
|
eErrorReturned=p_stProtocolInterface->fn_eSendData(uwChannel,(tdpPointer)pSndMsgBroad);
|
|
if(eErrorReturned==NetLib_E_es_NoError)
|
|
{
|
|
memmove(pstL1Msg->dstTabDest+i,pstL1Msg->dstTabDest+i+1,
|
|
(pstL1Msg->uwNbrDest-i-1)*sizeof(tdstProtChannel));
|
|
pstL1Msg->uwNbrDest--;
|
|
bMesSent=1;
|
|
}
|
|
else
|
|
{
|
|
vFree(pSndMsgBroad);
|
|
BitProtocol|=(1<<eProtocol);
|
|
}
|
|
}
|
|
}
|
|
if (!bMesSent) i++;
|
|
}
|
|
|
|
if (pstL1Msg->uwNbrDest==0)
|
|
{
|
|
vFree(pstSndMsg);
|
|
vFree(pstL1Msg->dstTabDest);
|
|
pstL1Msg=(tdstNetL1Message *)pNetList2DeleteElem(&stIter);
|
|
}
|
|
else pstL1Msg=(tdstNetL1Message *)pNetList2Next(&stIter);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1BackfireSysMessage
|
|
* puts in the outgoing system message queue a system message of the specified
|
|
* code with a body containing the optional offending game engine message.
|
|
*****************************************************************************
|
|
* Input: eMessageType, type of system message to output.
|
|
* eProtocol, protocol where the offending message came from.
|
|
* uwChannel, channel where the offending message came from.
|
|
* p_stInitialMessage, pointer to the offending incoming message.
|
|
* Output: an error condition depending on the action's results.
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1BackfireSysMessage(tdeNetMessageType eMessageType,tdeNetProtocol eProtocol,tduwNetChannel uwChannel,tdstNetMessage *p_stInitialMessage)
|
|
{
|
|
tdstNetMessage *p_stSysMessage;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
/*
|
|
* allocate a system cell to store the message in the outgoing
|
|
* system message queue.
|
|
*/
|
|
/* prepare the message body to send back the whole incoming message */
|
|
p_stSysMessage = (tdstNetMessage *) pMalloc(2 * sizeof(tdstNetMessage) + p_stInitialMessage->uwMessageSizeInBytes);
|
|
if(!p_stSysMessage)
|
|
{
|
|
vFree((tdpPointer)p_stInitialMessage);
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
|
|
/* fill the system message body */
|
|
p_stSysMessage->eMessageType = eMessageType;
|
|
p_stSysMessage->uxRecipientId = p_stInitialMessage->uxSenderId;
|
|
p_stSysMessage->uwMessageSizeInBytes = sizeof(tdstNetMessage) + p_stInitialMessage->uwMessageSizeInBytes;
|
|
g_pfn_vNetMemcpy(p_stSysMessage + 1, p_stInitialMessage, p_stSysMessage->uwMessageSizeInBytes);
|
|
|
|
/* erase the offending incoming message */
|
|
vFree((tdpPointer) p_stInitialMessage);
|
|
p_stInitialMessage = (tdstNetMessage*)C_pNull;
|
|
|
|
eErrorReturned = eLevel1SendMessage(p_stSysMessage,eProtocol,uwChannel);
|
|
if(eErrorReturned!=NetLib_E_es_NoError) vFree(p_stSysMessage);
|
|
return eErrorReturned;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : vNetL1OrderDest
|
|
When a message "NewL1Mes" replace an other "OldL1Mes", the waiting destinations for
|
|
the old message become prioritary in the new message.
|
|
Return "NetLib_E_es_False" if an old destination is not in the new message.
|
|
Return "NetLib_E_es_True" otherwise.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : Old and new NetL1 message
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
static NetLib_tdeErrorStatus eNetL1OrderDest(tdstNetL1Message *pstNewL1Mes,tdstNetL1Message *pstOldL1Mes)
|
|
{
|
|
int i,j,p=0;
|
|
tdstProtChannel *pstOldProtChannel,*pstNewProtChannel,varswap;
|
|
pstOldProtChannel=pstOldL1Mes->dstTabDest;
|
|
i=pstOldL1Mes->uwNbrDest;
|
|
while (i--)
|
|
{
|
|
pstNewProtChannel=pstNewL1Mes->dstTabDest+p;
|
|
j=pstNewL1Mes->uwNbrDest-p;
|
|
while (j--)
|
|
{
|
|
if ((pstOldProtChannel->eProtocol==pstNewProtChannel->eProtocol) &&
|
|
(pstOldProtChannel->uwChannel==pstNewProtChannel->uwChannel))
|
|
{
|
|
if (j!=p)
|
|
{
|
|
varswap=pstNewL1Mes->dstTabDest[p];
|
|
pstNewL1Mes->dstTabDest[p]=*pstNewProtChannel;
|
|
*pstNewProtChannel=varswap;
|
|
}
|
|
p++;
|
|
break;
|
|
}
|
|
pstNewProtChannel++;
|
|
}
|
|
if (j<0) return NetLib_E_es_False;
|
|
pstOldProtChannel++;
|
|
}
|
|
return NetLib_E_es_True;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eNetLevel1InsertNewMsg
|
|
Insert a new message in the list with priority and replace constraint.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : an iterator and a NetL1 message
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if no error occured
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
static NetLib_tdeErrorStatus eNetLevel1InsertNewMsg(tdstNetIter *pstIter,tdstNetL1Message *pstL1Message)
|
|
{
|
|
long lPosPrior=0;
|
|
tdstNetL1Message *pstL1MsgInt;
|
|
tdstNetMessage *pstInsMsg,*pstCurMsg;
|
|
|
|
pstInsMsg=pstL1Message->pMessage;
|
|
vNetList2ToEnd(pstIter);
|
|
while (!iNetList2IsFirst(pstIter))
|
|
{
|
|
pstL1MsgInt=(tdstNetL1Message *)pNetList2Prev(pstIter);
|
|
pstCurMsg=pstL1MsgInt->pMessage;
|
|
if ((lPosPrior==0) && (pstCurMsg->uxPriority>=pstInsMsg->uxPriority))
|
|
{
|
|
lPosPrior=ulNetList2PosIter(pstIter)+1;
|
|
}
|
|
if ((pstCurMsg->uxReplace) &&
|
|
(pstCurMsg->uxSenderId == pstInsMsg->uxSenderId) &&
|
|
(pstCurMsg->uxRecipientId == pstInsMsg->uxRecipientId) &&
|
|
(pstCurMsg->eMessageType == pstInsMsg->eMessageType) &&
|
|
(pstCurMsg->uxReplaceType == pstInsMsg->uxReplaceType))
|
|
{
|
|
if (pstCurMsg->uxRecipientId!=C_uxNetInvalidId)
|
|
{
|
|
if (eNetL1OrderDest(pstL1Message,pstL1MsgInt)==NetLib_E_es_True)
|
|
{
|
|
vFree(pstL1MsgInt->dstTabDest);
|
|
vFree(pstCurMsg);
|
|
pNetList2DeleteElem(pstIter);
|
|
lPosPrior=ulNetList2PosIter(pstIter);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ulNetList2NbrElemIter(pstIter)>=gs_uwMaxNbrOfMsgPerList)
|
|
{
|
|
if (ulNetList2NbrElemIter(pstIter)<=lPosPrior) return NetLib_E_es_FIFOIsFull;
|
|
else
|
|
{
|
|
pstL1MsgInt=(tdstNetL1Message *)pNetList2ToLast(pstIter);
|
|
vFree(pstL1MsgInt->pMessage);
|
|
pNetList2DeleteElem(pstIter);
|
|
}
|
|
}
|
|
pNetList2SetPos(pstIter,lPosPrior);
|
|
if (!pNetList2InsertElem(pstIter,pstL1Message,sizeof(tdstNetL1Message)))
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
else return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description :eLevel1HandleIncomingMsg
|
|
Handles incoming msg
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
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
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
static NetLib_tdeErrorStatus eLevel1HandleIncomingMsg(tdstNetMessage *p_stReceivedMessage,tdeNetProtocol eProtocol,tduwNetChannel uwChannel)
|
|
{
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message stL1Message;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
if(eNetCheckMessageBody(p_stReceivedMessage)!=NetLib_E_es_NoError)
|
|
{/* An error inside the message :*/
|
|
vFree(p_stReceivedMessage);
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_NetSer, "NetL1: HandleIncomingMsg: bad checksum");
|
|
#endif
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*If the recipient is broadcast, set it to the local player*/
|
|
if(p_stReceivedMessage->uxRecipientId == C_uxNetBroadcastId)
|
|
{
|
|
if (gs_uwMode==NetLib_Mode_Direct)
|
|
{
|
|
NetLib_tduxPlayerId *TabDestPlayer,NbrDestPlayer;
|
|
vLevel1GetBroadcastSource(p_stReceivedMessage->uxSenderId,&TabDestPlayer,&NbrDestPlayer);
|
|
if (NbrDestPlayer)
|
|
{
|
|
tdstNetMessage *pstMes;
|
|
pstMes=(tdstNetMessage *)pMalloc(sizeof(tdstNetMessage)+p_stReceivedMessage->uwMessageSizeInBytes);
|
|
if (pstMes)
|
|
{
|
|
memcpy(pstMes,p_stReceivedMessage,sizeof(tdstNetMessage)+p_stReceivedMessage->uwMessageSizeInBytes);
|
|
eErrorReturned=eLevel1SendMessage(pstMes,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
|
|
if (eErrorReturned!=NetLib_E_es_NoError) vFree(pstMes);
|
|
}
|
|
}
|
|
}
|
|
p_stReceivedMessage->uxRecipientId=gs_ulLocalPlayerId;
|
|
}
|
|
else if(p_stReceivedMessage->eMessageType < E_Net_mt_FirstSysMessage)
|
|
{
|
|
if (p_stReceivedMessage->uxRecipientId!=gs_ulLocalPlayerId)
|
|
{
|
|
if ((p_stReceivedMessage->uxRecipientId != C_uxNetInvalidId) &&
|
|
(wLevel1IndexInRouteTable(p_stReceivedMessage->uxRecipientId) != -1))
|
|
{
|
|
eErrorReturned=eLevel1SendMessage(p_stReceivedMessage,E_Net_pr_InvalidProtocol,C_uwNetInvalidChannel);
|
|
if (eErrorReturned==NetLib_E_es_NoError) return NetLib_E_es_NoError;
|
|
}
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_NetSer, "NetL1: HandleIncomingMsg: unknown recipient");
|
|
#endif
|
|
|
|
/* one could send back an "unknown recipient" system message */
|
|
vFree(p_stReceivedMessage);
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
}
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_NetSer, "NetL1: HandleIncomingMsg: new msg for local host");
|
|
#endif
|
|
|
|
stL1Message.pMessage=p_stReceivedMessage;
|
|
stL1Message.uwNbrDest=1;
|
|
stL1Message.dstTabDest=(tdstProtChannel *)pMalloc(stL1Message.uwNbrDest*sizeof(tdstProtChannel));
|
|
if (!stL1Message.dstTabDest)
|
|
{
|
|
vFree((tdpPointer)p_stReceivedMessage);
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
stL1Message.dstTabDest->eProtocol=eProtocol;
|
|
stL1Message.dstTabDest->uwChannel=uwChannel;
|
|
if(p_stReceivedMessage->eMessageType >= E_Net_mt_FirstSysMessage)
|
|
pNetList2IterInit(&stIter,&gs_stIncomingSysMsgList);
|
|
else pNetList2IterInit(&stIter,&gs_stIncomingEngineMsgList);
|
|
eErrorReturned=eNetLevel1InsertNewMsg(&stIter,&stL1Message);
|
|
if (eErrorReturned!=NetLib_E_es_NoError)
|
|
{
|
|
vFree((tdpPointer)stL1Message.dstTabDest);
|
|
vFree((tdpPointer)p_stReceivedMessage);
|
|
/* send back a "buffer is full" system message*/
|
|
eLevel1BackfireSysMessage(E_Net_mt_SysFullBuffer, eProtocol, uwChannel, p_stReceivedMessage);
|
|
}
|
|
return eErrorReturned;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: vLevel1IncomingNetEngine
|
|
* Reads all incoming messages from the level 0 buffers, and store the full
|
|
* messages in the appropriate incoming queues. Some system messages can
|
|
* also be generated in case of major problem.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: October 1996 Author: Albert PAIS
|
|
* -> All the function has been changed
|
|
****************************************************************************/
|
|
static void vLevel1IncomingNetEngine(void)
|
|
{
|
|
unsigned char ucCurrentProtocolIndex;
|
|
tdeNetProtocol eProtocol;
|
|
tduwNetChannel uwChannel;
|
|
tduwNetChannel uwChannelReturned;
|
|
tdstNetProtocolInterface *p_stCurrentInterface;
|
|
tdstNetMessage *p_stReceivedMessage;
|
|
NetLib_tdeErrorStatus eReadStatus;
|
|
unsigned short uwCountMsg;
|
|
|
|
for (ucCurrentProtocolIndex=0;ucCurrentProtocolIndex<gs_uwNumberOfProtocol;ucCurrentProtocolIndex++)
|
|
{
|
|
p_stCurrentInterface = &gs_d_stAvailableProtocolInterfaces[ucCurrentProtocolIndex];
|
|
/* retrieve protocol identifier */
|
|
eProtocol = p_stCurrentInterface->eProtocol;
|
|
/* ask protocol the first channel identifier */
|
|
uwChannel = p_stCurrentInterface->fn_uwStartChannelScan();
|
|
|
|
/* while there is an available channel for the current protocol */
|
|
while (uwChannel != C_uwNetInvalidChannel)
|
|
{
|
|
/*
|
|
* retreive data that arrived in the specified channel. if these were
|
|
* the last bytes of a message, we get a pointer on the allocated block
|
|
* that contains it.
|
|
*/
|
|
uwCountMsg =0;
|
|
do
|
|
{
|
|
uwChannelReturned = uwChannel;
|
|
eReadStatus = p_stCurrentInterface->fn_eReadData(&uwChannelReturned, (tdpPointer *) &p_stReceivedMessage);
|
|
/* if we got a full message in the level 0 buffer */
|
|
if (eReadStatus == NetLib_E_es_NoError && p_stReceivedMessage)
|
|
{
|
|
eReadStatus = eLevel1HandleIncomingMsg(p_stReceivedMessage,eProtocol,uwChannelReturned);
|
|
#ifdef NET_USE_DEBUG
|
|
vDebugFormat(Net_C_Debug_NetSer, "NetL1: vLevel1IncomingNetEngine: eReadStatus: %ld", eReadStatus);
|
|
#endif
|
|
uwCountMsg++;
|
|
}
|
|
}while (((eReadStatus) == NetLib_E_es_NoError) /*&& (uwCountMsg<5)*/);
|
|
/* Check if no problems occured : */
|
|
/*if(eReadStatus != NetLib_E_es_NoError)*/
|
|
/* treat the error if it can be*/
|
|
|
|
/* proceed to next channel of the current protocol */
|
|
uwChannel = p_stCurrentInterface->fn_uwNextChannel(uwChannel);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: iLevel1NetEngine
|
|
* performs all operations to read, write and route messages.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************
|
|
* Creation Date: April 4, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 4, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: Author:
|
|
****************************************************************************/
|
|
int _NET_CALLING_CONV_ iLevel1NetEngine(void)
|
|
{
|
|
unsigned char ucCurrentProtocolIndex;
|
|
/* Scans all the protocol and call the NetEngine function :*/
|
|
for(ucCurrentProtocolIndex=0;ucCurrentProtocolIndex<gs_uwNumberOfProtocol;ucCurrentProtocolIndex++)
|
|
{
|
|
if(gs_d_stAvailableProtocolInterfaces[ucCurrentProtocolIndex].fn_vLevel0NetEngine)
|
|
gs_d_stAvailableProtocolInterfaces[ucCurrentProtocolIndex].fn_vLevel0NetEngine();
|
|
}
|
|
vLevel1IncomingNetEngine();
|
|
vLevel1OutgoingNetEngine();
|
|
return 0;
|
|
}
|
|
|
|
void vLevel1InitProtocolTable()
|
|
|
|
{
|
|
gs_d_stAvailableProtocolInterfaces=(tdstNetProtocolInterface *)C_pNull;
|
|
gs_uwNumberOfProtocol=0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: pstLevel1AddProtocol
|
|
* setup global variables with safe default values.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: a pointer on the new protocol. Null if not enought memory
|
|
****************************************************************************/
|
|
tdstNetProtocolInterface *pstLevel1AddProtocol(void)
|
|
{
|
|
tdstNetProtocolInterface *dstNewTab;
|
|
|
|
dstNewTab=(tdstNetProtocolInterface *)pRealloc(
|
|
gs_d_stAvailableProtocolInterfaces,
|
|
sizeof(tdstNetProtocolInterface)*(gs_uwNumberOfProtocol+1));
|
|
|
|
if(dstNewTab) {
|
|
gs_d_stAvailableProtocolInterfaces=dstNewTab;
|
|
vNetFillInvalidProtocolInterface(gs_d_stAvailableProtocolInterfaces +
|
|
gs_uwNumberOfProtocol);
|
|
|
|
return gs_d_stAvailableProtocolInterfaces +
|
|
gs_uwNumberOfProtocol++;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
void vLevel1RemoveProtocol(tdeNetProtocol eProtocol)
|
|
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i<gs_uwNumberOfProtocol; i++) {
|
|
if(gs_d_stAvailableProtocolInterfaces[i].eProtocol==eProtocol) {
|
|
|
|
if(gs_uwNumberOfProtocol-i-1>0)
|
|
memmove(&gs_d_stAvailableProtocolInterfaces[i],
|
|
&gs_d_stAvailableProtocolInterfaces[i+1],
|
|
(gs_uwNumberOfProtocol-i-1)*sizeof(tdstNetProtocolInterface));
|
|
|
|
/* one could reallocate d_astAvailableProtocolInterfaces ... */
|
|
|
|
gs_uwNumberOfProtocol--;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void vLevel1DeleteProtocolTable()
|
|
|
|
{
|
|
if(gs_d_stAvailableProtocolInterfaces)
|
|
vFree(gs_d_stAvailableProtocolInterfaces);
|
|
gs_uwNumberOfProtocol=0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eLevel1GlobalSetup
|
|
* setup global variables with safe default values.
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: an error code if an error occures
|
|
*****************************************************************************
|
|
* Creation Date: April 9, 1996 Author: Benoit GERMAIN
|
|
*****************************************************************************
|
|
* Modification log:
|
|
* Date: April 9, 1996 Author: Benoit GERMAIN
|
|
* -> first public release
|
|
* Date: April 15-16, 1996 Author: Albert Pais
|
|
* Adding some initialisations
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eLevel1GlobalSetup(NetLib_tduwMode Mode,short BroadcastIpx)
|
|
{
|
|
gs_wBroadcastIpx=BroadcastIpx;
|
|
gs_uwMode=Mode;
|
|
|
|
/* Initialise route table :*/
|
|
gs_d_stRouteTable = (tdstRouteCell*)C_pNull;
|
|
/* Initialise number of players and max number of players :*/
|
|
gs_uwMaxNumberOfRemotePlayers = 0;
|
|
/* Initialize local player id :*/
|
|
gs_ulLocalPlayerId = C_uxNetInvalidId;
|
|
|
|
NbrBroadcastSource = 0;
|
|
TabBroadcastSource = NULL;
|
|
|
|
gs_dcRndList=NULL;
|
|
|
|
/* initialize the gs_uwMaxNbrOfMsgPerList */
|
|
eLevel1NetSetMaxNbrOfMsgPerList(C_MaxNbrElement);
|
|
|
|
if (iNetList2Init(&gs_stOutgoingMsgList)) return NetLib_E_es_NotEnoughMemory;
|
|
if (iNetList2Init(&gs_stIncomingSysMsgList)) return NetLib_E_es_NotEnoughMemory;
|
|
if (iNetList2Init(&gs_stIncomingEngineMsgList)) return NetLib_E_es_NotEnoughMemory;
|
|
|
|
gs_p_stSessionCell = (tdstSessionCell*)C_pNull;
|
|
gs_ucReemissionMode = 0;
|
|
|
|
NetLib_eProcessLittleBigEndian();
|
|
|
|
vLevel1InitProtocolTable();
|
|
|
|
gs_uwNumberOfProtocol=0;
|
|
gs_d_stAvailableProtocolInterfaces=NULL;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : vLevel1CopyRouteCell
|
|
Copy a route cell
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : Src and dest
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : None
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
void vLevel1CopyRouteCell(tdstRouteCell *p_stDest,tdstRouteCell *p_stSrc)
|
|
{
|
|
p_stDest->ulPlayerId = p_stSrc->ulPlayerId;
|
|
p_stDest->eProtocol = p_stSrc->eProtocol;
|
|
p_stDest->uwChannel = p_stSrc->uwChannel;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : NetLib_tdeErrorStatus eLevel1SetMaxNumberOfRemotePlayers
|
|
Sets the maximum number of players. Initialize data with this information
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : an unsigned short representing the max number of remote players
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if no error occures
|
|
NetLib_E_es_NotEnoughMemory if there was not enough memory to complete the function
|
|
NetLib_E_es_AlreadyTooMuchPlayers if the current number of players in the session
|
|
is larger than the new max number of players
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : April 16, 96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Comment :
|
|
If the functions does not end correctly, either the old data is preserved or
|
|
new data has been built, but only up to the error. It means that the maximum
|
|
number of remote players can be lesser than the one specified by the argument.
|
|
However, the information about remote players effectively in the session is not lost
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eLevel1SetMaxNumberOfRemotePlayers(unsigned short uwNewMaxNumberOfRemotePlayers)
|
|
{
|
|
unsigned short c_uwCurrentRemotePlayer;
|
|
unsigned short c_uwNumberOfRemotePlayerProcessed;
|
|
unsigned short c_uwCurrentNewFreeSlot;
|
|
unsigned short uw_NumberOfRemotePlayer;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
tdstRouteCell *d_stNewRoute;
|
|
tdstRouteCell *p_stDestRoute;
|
|
|
|
if (gs_dcRndList) vFree((tdpPointer)gs_dcRndList);
|
|
gs_dcRndList=(unsigned char*)pMalloc(uwNewMaxNumberOfRemotePlayers);
|
|
|
|
if(gs_d_stRouteTable != (tdstRouteCell *)C_pNull)
|
|
{
|
|
/* Recopy data*/
|
|
if(gs_uwMaxNumberOfRemotePlayers == uwNewMaxNumberOfRemotePlayers)
|
|
return NetLib_E_es_NoError;
|
|
|
|
/* Process the number of remote players :*/
|
|
uw_NumberOfRemotePlayer = 0;
|
|
for(c_uwCurrentRemotePlayer=0;c_uwCurrentRemotePlayer<gs_uwMaxNumberOfRemotePlayers;c_uwCurrentRemotePlayer++)
|
|
{
|
|
if(gs_d_stRouteTable[c_uwCurrentRemotePlayer].ulPlayerId != C_uxNetInvalidId)
|
|
uw_NumberOfRemotePlayer++;
|
|
}
|
|
if(uw_NumberOfRemotePlayer > uwNewMaxNumberOfRemotePlayers)
|
|
/* In that case, changing anything could induce lost of data, so return an error code */
|
|
return NetLib_E_es_AlreadyTooMuchPlayers;
|
|
|
|
/* Reallocate a new array of route and copy data of the previous one */
|
|
if((d_stNewRoute = (tdstRouteCell *)pMalloc(sizeof(tdstRouteCell)*uwNewMaxNumberOfRemotePlayers))
|
|
==(tdstRouteCell *)C_pNull)
|
|
/* Not enough memory to create the new array :*/
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
|
|
c_uwCurrentRemotePlayer = 0;
|
|
c_uwNumberOfRemotePlayerProcessed = 0;
|
|
c_uwCurrentNewFreeSlot = uw_NumberOfRemotePlayer;
|
|
|
|
while ((c_uwCurrentRemotePlayer < gs_uwMaxNumberOfRemotePlayers)&&
|
|
((c_uwCurrentNewFreeSlot < uwNewMaxNumberOfRemotePlayers)||
|
|
(c_uwNumberOfRemotePlayerProcessed < uw_NumberOfRemotePlayer)))
|
|
{
|
|
if(gs_d_stRouteTable[c_uwCurrentRemotePlayer].ulPlayerId != C_uxNetInvalidId)
|
|
{/* A player has been found...
|
|
So initialize the new entry with old data */
|
|
p_stDestRoute = &d_stNewRoute[c_uwNumberOfRemotePlayerProcessed];
|
|
c_uwNumberOfRemotePlayerProcessed++;
|
|
}
|
|
else
|
|
{/* A free entry has been found in the old array : */
|
|
if(c_uwCurrentNewFreeSlot < uwNewMaxNumberOfRemotePlayers)
|
|
{/* Free entries remain in the new array, so initialize it with free entry of the old array*/
|
|
p_stDestRoute = &d_stNewRoute[c_uwCurrentNewFreeSlot];
|
|
c_uwCurrentNewFreeSlot ++;
|
|
}
|
|
else
|
|
{/* No more free entry in the new array, so trash old entry */
|
|
p_stDestRoute = (tdstRouteCell*)C_pNull;
|
|
}
|
|
}
|
|
|
|
if(p_stDestRoute != (tdstRouteCell*)C_pNull)
|
|
{/* Data at the current entry of the old array must be retrieved :*/
|
|
vLevel1CopyRouteCell(p_stDestRoute,&gs_d_stRouteTable[c_uwCurrentRemotePlayer]);
|
|
}
|
|
c_uwCurrentRemotePlayer++;
|
|
}/* End of while */
|
|
if(gs_uwMaxNumberOfRemotePlayers > uwNewMaxNumberOfRemotePlayers)
|
|
{/* Destroy the end of the old list :*/
|
|
vFree((tdpPointer)gs_d_stRouteTable);
|
|
/* Initialize global data with new value :*/
|
|
gs_d_stRouteTable = d_stNewRoute;
|
|
gs_uwMaxNumberOfRemotePlayers = uwNewMaxNumberOfRemotePlayers;
|
|
/* returns no error :*/
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
else
|
|
{
|
|
/* Destroy the old array*/
|
|
vFree((tdpPointer)gs_d_stRouteTable);
|
|
gs_d_stRouteTable = d_stNewRoute;
|
|
/* Initialise remaining free entries of the new array */
|
|
eErrorReturned = NetLib_E_es_NoError;
|
|
while((c_uwCurrentNewFreeSlot < uwNewMaxNumberOfRemotePlayers)&&
|
|
(eErrorReturned == NetLib_E_es_NoError))
|
|
{
|
|
d_stNewRoute[c_uwCurrentNewFreeSlot].ulPlayerId = C_uxNetInvalidId;
|
|
d_stNewRoute[c_uwCurrentNewFreeSlot].eProtocol = E_Net_pr_InvalidProtocol;
|
|
d_stNewRoute[c_uwCurrentNewFreeSlot].uwChannel = 0;
|
|
c_uwCurrentNewFreeSlot++;
|
|
}/* End of while */
|
|
gs_uwMaxNumberOfRemotePlayers = c_uwCurrentNewFreeSlot;
|
|
return eErrorReturned;
|
|
}
|
|
}
|
|
else
|
|
{/* First call */
|
|
gs_uwMaxNumberOfRemotePlayers = uwNewMaxNumberOfRemotePlayers;
|
|
gs_d_stRouteTable = (tdstRouteCell *)pMalloc(sizeof(tdstRouteCell)*uwNewMaxNumberOfRemotePlayers);
|
|
if(gs_d_stRouteTable != (tdstRouteCell *)C_pNull)
|
|
{
|
|
eErrorReturned = NetLib_E_es_NoError;
|
|
c_uwCurrentRemotePlayer = 0;
|
|
/* Init the array : */
|
|
while((c_uwCurrentRemotePlayer < uwNewMaxNumberOfRemotePlayers)&&
|
|
(eErrorReturned == NetLib_E_es_NoError))
|
|
{
|
|
gs_d_stRouteTable[c_uwCurrentRemotePlayer].ulPlayerId = C_uxNetInvalidId;
|
|
gs_d_stRouteTable[c_uwCurrentRemotePlayer].eProtocol = E_Net_pr_InvalidProtocol;
|
|
gs_d_stRouteTable[c_uwCurrentRemotePlayer].uwChannel = 0;
|
|
c_uwCurrentRemotePlayer ++;
|
|
}/* end of while */
|
|
if(eErrorReturned != NetLib_E_es_NoError)
|
|
/* An error occured when initializing the c_uwCurrentRemotePlayer-1 entry*/
|
|
gs_uwMaxNumberOfRemotePlayers = c_uwCurrentRemotePlayer - 2;
|
|
return eErrorReturned;
|
|
}
|
|
else
|
|
{
|
|
gs_uwMaxNumberOfRemotePlayers = 0;
|
|
return NetLib_E_es_NotEnoughMemory;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned short uwLevel1GetNumberOfRemotePlayers(void)
|
|
{
|
|
unsigned short c_uwCount;
|
|
unsigned short uwNbrOfPlayers;
|
|
c_uwCount = 0;
|
|
uwNbrOfPlayers = 0;
|
|
while(c_uwCount <gs_uwMaxNumberOfRemotePlayers)
|
|
{
|
|
if(gs_d_stRouteTable[c_uwCount].ulPlayerId!=C_uxNetInvalidId)
|
|
uwNbrOfPlayers++;
|
|
c_uwCount++;
|
|
}
|
|
return uwNbrOfPlayers;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : unsigned short uwLevel1GetMaxNumberOfRemotePlayers(void)
|
|
Retrieves the max number of players in level 1
|
|
(does not include the local player)
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : None
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : An unsigned short representing the number of players, that is to say the number
|
|
of entries in the route table
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : April 16, 96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
unsigned short uwLevel1GetMaxNumberOfRemotePlayers(void)
|
|
{
|
|
return gs_uwMaxNumberOfRemotePlayers;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : void vLevel1CloseLibrary(void)
|
|
Level 1 closing function
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : none
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : none
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : May 6,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
void vLevel1CloseLibrary(void)
|
|
{
|
|
unsigned short c_uwCount;
|
|
|
|
vLevel1KillBroadcastTab();
|
|
if (gs_dcRndList) vFree((tdpPointer)gs_dcRndList);
|
|
|
|
vFree((tdpPointer)gs_d_stRouteTable);
|
|
gs_d_stRouteTable = (tdstRouteCell *)C_pNull;
|
|
gs_uwMaxNumberOfRemotePlayers = 0;
|
|
gs_ulLocalPlayerId = C_uxNetInvalidId;
|
|
/* Close list :*/
|
|
vNetList2Kill(&gs_stIncomingSysMsgList);
|
|
vNetList2Kill(&gs_stIncomingEngineMsgList);
|
|
vNetList2Kill(&gs_stOutgoingMsgList);
|
|
|
|
if(gs_p_stSessionCell) vLevel1DestroySessionCellList();
|
|
gs_p_stSessionCell = (tdstSessionCell *)C_pNull;
|
|
|
|
/* Closing functions for different protocols used :*/
|
|
for(c_uwCount = 0; c_uwCount < gs_uwNumberOfProtocol;c_uwCount++) {
|
|
if(gs_d_stAvailableProtocolInterfaces[c_uwCount].fn_vLevel0CloseProtocol)
|
|
gs_d_stAvailableProtocolInterfaces[c_uwCount].fn_vLevel0CloseProtocol();
|
|
}
|
|
|
|
vLevel1DeleteProtocolTable();
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : vLevel1NetCloseChannel
|
|
Check if there are others players using the same protocol and channel, and if not,
|
|
close the channel
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : the protocol
|
|
the channel
|
|
the player Id
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : None
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : June 26,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
void vLevel1NetCloseChannel(tdeNetProtocol eProtocol,tduwNetChannel uwChannel,NetLib_tduxPlayerId ulOldPlayer)
|
|
{
|
|
unsigned short c_uwCount;
|
|
tdstNetProtocolInterface *p_stProtInter;
|
|
|
|
c_uwCount = 0;
|
|
while ((c_uwCount<gs_uwMaxNumberOfRemotePlayers)&&
|
|
((gs_d_stRouteTable[c_uwCount].ulPlayerId==ulOldPlayer)||
|
|
(gs_d_stRouteTable[c_uwCount].eProtocol != eProtocol)||/*it is not the same player*/
|
|
(gs_d_stRouteTable[c_uwCount].uwChannel != uwChannel)))/* it has the same protocol, but should not have the same channel*/
|
|
c_uwCount++;
|
|
|
|
if(c_uwCount>=gs_uwMaxNumberOfRemotePlayers)
|
|
{
|
|
p_stProtInter = p_stLevel1GetInterfaceOfProtocol(eProtocol);
|
|
if ((p_stProtInter) && (p_stProtInter->fn_vCloseChannel))
|
|
p_stProtInter->fn_vCloseChannel(uwChannel);
|
|
}
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eLevel1FillMessageHeader
|
|
Fills the standart slots in a message header
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A pointer to a tdstNetMessage
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : a NetLib_tdeErrorStatus
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : July 8,96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Warning : Call this function only after having feeled the other slots, because the check
|
|
sum is now evaluated
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
static NetLib_tdeErrorStatus eLevel1FillMessageHeader(tdstNetMessage *p_stMessage)
|
|
{
|
|
p_stMessage->uxSessionId = gs_ulSessionId;
|
|
/* BigEndian : 0xij
|
|
i is used for little(1)/big(0) endian of the sender msg
|
|
j is used along the route */
|
|
if(p_stMessage->uxSenderId==gs_ulLocalPlayerId)
|
|
{
|
|
/*we send a msg :*/
|
|
p_stMessage->uxHeadBigEndian = NetLib_ucGetLittleBigEndian();
|
|
p_stMessage->uxBodyBigEndian = p_stMessage->uxHeadBigEndian;
|
|
}
|
|
else
|
|
{
|
|
/* we route a msg :*/
|
|
p_stMessage->uxHeadBigEndian = NetLib_ucGetLittleBigEndian();
|
|
}
|
|
p_stMessage->ulReserved=M_ulMakeReserved(M_uwProcessCheckSum(p_stMessage),M_uwProcessCheckSumBody(p_stMessage));
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : uwNetProcessCheckSumHeader
|
|
Process the check sum on the header of a message
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A pointer to a tdstNetMessage
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : the check sum
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : August,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
unsigned short Net_uwSumLongByte(unsigned long l)
|
|
{
|
|
unsigned short chk;
|
|
chk=M_NET_ucLOBYTE(M_NET_uwLOWORD(l))
|
|
+M_NET_ucLOBYTE(M_NET_uwHIWORD(l))
|
|
+M_NET_ucHIBYTE(M_NET_uwLOWORD(l))
|
|
+M_NET_ucHIBYTE(M_NET_uwHIWORD(l));
|
|
return chk;
|
|
}
|
|
|
|
unsigned short uwNetProcessCheckSumHeader(tdstNetMessage *p_stMsg)
|
|
{
|
|
unsigned short uwCheckSum;
|
|
/* Header check sum :*/
|
|
uwCheckSum = (unsigned short)
|
|
(
|
|
Net_uwSumLongByte(p_stMsg->uxSessionId)
|
|
+Net_uwSumLongByte(p_stMsg->uxSenderId)
|
|
+Net_uwSumLongByte(p_stMsg->uxRecipientId)
|
|
+Net_uwSumLongByte(p_stMsg->uwMessageSizeInBytes)
|
|
+Net_uwSumLongByte(p_stMsg->eMessageType)
|
|
+Net_uwSumLongByte(p_stMsg->uxHeadBigEndian)
|
|
+Net_uwSumLongByte(p_stMsg->uxBodyBigEndian)
|
|
+Net_uwSumLongByte(p_stMsg->uxPriority)
|
|
+Net_uwSumLongByte(p_stMsg->uxReplaceType)
|
|
+Net_uwSumLongByte(p_stMsg->uxReplace)
|
|
);
|
|
|
|
return uwCheckSum;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : uwNetProcessCheckSumBody
|
|
Process the check sum on the body of a message
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A pointer to a tdstNetMessage
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : the check sum
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : August,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
unsigned short uwNetProcessCheckSumBody(tdstNetMessage *p_stMsg)
|
|
{
|
|
unsigned long ulCount;
|
|
unsigned long ulMax;
|
|
unsigned short uwCheckSum;
|
|
unsigned short *p_uwCurrentWord;
|
|
|
|
p_uwCurrentWord = (unsigned short*)(p_stMsg+1);
|
|
ulMax = p_stMsg->uwMessageSizeInBytes/sizeof(unsigned short);
|
|
uwCheckSum = 0;
|
|
for(ulCount = 0;ulCount < ulMax; ulCount++)
|
|
{
|
|
uwCheckSum += *p_uwCurrentWord;
|
|
p_uwCurrentWord++;
|
|
}
|
|
return uwCheckSum;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eNetCheckMessageBody
|
|
Check if the message is correct
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : A pointer to a tdstNetMessage
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if no error occured
|
|
NetLib_E_es_InvalidMessage otherwise
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : August,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eNetCheckMessageBody(tdstNetMessage *p_stMessage)
|
|
{
|
|
if(M_uwProcessCheckSumBody(p_stMessage)==M_uwCheckSumBodySlot(p_stMessage))
|
|
return NetLib_E_es_NoError;
|
|
else
|
|
return NetLib_E_es_InvalidMessage;
|
|
}
|
|
|
|
NetLib_tdeErrorStatus eLevel1NetSetMaxNbrOfMsgPerList(unsigned short uwNewNbrMsgPerList)
|
|
{
|
|
gs_uwMaxNbrOfMsgPerList = uwNewNbrMsgPerList;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eNetLevel1EraseAllMessages
|
|
Erases all the message for which the callback returns true
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : a player id
|
|
a flag for either incoming or outgoing data
|
|
a pointer to a callback function
|
|
a pointer parameter to this function
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if no error occured
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : August 22,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eNetLevel1EraseAllMessages(NetLib_tduxPlayerId ulPlayerId,unsigned char ucIncomingOrOutgoingFlag,NetLib_tdeErrorStatus (_NET_CALLING_CONV_*pfn_eEraseMessage)(tdstNetMessage*,void*),void *p_vCallBackParam)
|
|
{
|
|
tdstNetIter stIter;
|
|
tdstNetL1Message *pstL1Msg;
|
|
|
|
pstL1Msg=(tdstNetL1Message *)pNetList2IterInit(&stIter,&gs_stOutgoingMsgList);
|
|
while (pstL1Msg)
|
|
{
|
|
if (pfn_eEraseMessage(pstL1Msg->pMessage,p_vCallBackParam)==NetLib_E_es_True)
|
|
{
|
|
vFree(pstL1Msg->pMessage);
|
|
vFree(pstL1Msg->dstTabDest);
|
|
pstL1Msg=(tdstNetL1Message *)pNetList2DeleteElem(&stIter);
|
|
}
|
|
else pstL1Msg=(tdstNetL1Message *)pNetList2Next(&stIter);
|
|
}
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////////
|
|
Description : eLevel1AddNewPlayer
|
|
Add a new player
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input : a pointer to a tdstAddPlayerL1Desc
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output : NetLib_E_es_NoError if no error occured
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : October 21,96
|
|
Author : Albert Pais
|
|
//////////////////////////////////////////////////////////////////////////////*/
|
|
NetLib_tdeErrorStatus eLevel1AddNewPlayer(NetLib_tduxPlayerId ulNewPlayerId,tdstAddPlayerL1Desc *p_stAddPlayerDesc)
|
|
{
|
|
tduwNetChannel uwChannelReturned;
|
|
short wFreeAccess;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
|
|
wFreeAccess = wLevel1IndexInRouteTable(C_uxNetInvalidId);
|
|
if(wFreeAccess == -1) return NetLib_E_es_AlreadyTooMuchPlayers;
|
|
|
|
p_stProtocolInterface = p_stLevel1GetInterfaceOfProtocol(p_stAddPlayerDesc->m_eProtocol);
|
|
if(!p_stProtocolInterface) return NetLib_E_es_InvalidProtocol;
|
|
|
|
if (!(p_stProtocolInterface->fn_eAddNewPlayer)) return NetLib_E_es_ServiceNotYetProvided;
|
|
|
|
if((eErrorReturned = p_stProtocolInterface->fn_eAddNewPlayer(&uwChannelReturned,p_stAddPlayerDesc->m_vL0Param))
|
|
!=NetLib_E_es_NoError) return eErrorReturned;
|
|
|
|
if((eErrorReturned=eLevel1FillNewRouteCell(&gs_d_stRouteTable[wFreeAccess],ulNewPlayerId,
|
|
p_stAddPlayerDesc->m_eProtocol,
|
|
uwChannelReturned))!=0)
|
|
{
|
|
p_stProtocolInterface->fn_vCloseChannel(uwChannelReturned);
|
|
return eErrorReturned;
|
|
}
|
|
|
|
vLevel1AddBroadcastPath(gs_ulLocalPlayerId,ulNewPlayerId);
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|