1380 lines
49 KiB
C
1380 lines
49 KiB
C
/*
|
||
* universal multiplayer library level 0 implementation file
|
||
* transport layer: UDP PC-windows 95
|
||
*/
|
||
|
||
/*
|
||
* Author: Christophe Roguet after Benoit GERMAIN
|
||
*
|
||
* Modification Date: 24/04/96 first draft : I consider that the datagram delivery is completely reliable ...
|
||
* which might be right on a local ethernet with low load and small datagrams...
|
||
*/
|
||
|
||
#include "warnings.h"
|
||
|
||
#if defined(_MSC_VER)
|
||
#pragma warning(disable : 4306)
|
||
#endif
|
||
|
||
#include "NetSock.h"
|
||
|
||
/*
|
||
* we need this one to fill the interface structure
|
||
* with pointers to the correct functions
|
||
*/
|
||
#include "Privl0UDP.h"
|
||
#include "PrivNetDef.h"
|
||
#include "L0GlDef.h"
|
||
#include "NetMemCo.h"
|
||
#include "NetEnd.h"
|
||
#include <NET\NetDebug.h>
|
||
|
||
/* array of descriptors to access a physical channel. */
|
||
static tdstL0PCWin95UDPChannel gs_a_stL0PCWin95UDPChannels[C_ucL0MaxNumberOfUDPChannels];
|
||
|
||
/* the IP adress of the computer the application is running on, in network order */
|
||
static struct in_addr gs_stMyAddress;
|
||
|
||
/* the global socket descriptor used for all net operations */
|
||
static int gs_iSD;
|
||
static unsigned short gs_uwNumberOfPort;
|
||
|
||
static char gs_bL0PCWin95UDPInitState;
|
||
|
||
static tdstWinSockFunc *gs_p_stUDPWinSocDesc;
|
||
static char gs_cIsWinsocDescInit = 0;
|
||
|
||
#define DLL_FD_ISSET(fd, set) ((gs_p_stUDPWinSocDesc->m_pfn_i_WSAFDIsSet)((SOCKET)(fd), (fd_set *)(set)))
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPGetChannel
|
||
*
|
||
* look up the channel associated to a particular remote address
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: inet address to look up
|
||
*
|
||
* Output: identification of the channel
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: June 6, 1996 Author: Christophe ROGUET
|
||
* take the 'broadcast channel' flag into account, in order to be able to use
|
||
* the library with a direct connection over internet
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPGetChannel(struct sockaddr_in *Key)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
for(uwCurrentChannel=0; uwCurrentChannel<C_ucL0MaxNumberOfUDPChannels; uwCurrentChannel++)
|
||
if(
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse==1
|
||
&& !gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsBroadcast
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].stRemoteAddr.sin_addr.s_addr==Key->sin_addr.s_addr
|
||
)
|
||
return uwCurrentChannel;
|
||
|
||
return C_uwNetInvalidChannel; /* Error invalid channel ?*/
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPOpenChannel
|
||
*
|
||
* returns the identification number of an unused slot in the channel table
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: inet address to bind to the channel,
|
||
* port number in a net format
|
||
*
|
||
* Output: identification of the channel
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
static tduwNetChannel uwL0PCWin95UDPOpenChannel(struct sockaddr_in *pRemoteAddr,unsigned short uwPortNumber)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the channel table until we find an unused slot */
|
||
for(uwCurrentChannel=0;
|
||
uwCurrentChannel<C_ucL0MaxNumberOfUDPChannels;
|
||
uwCurrentChannel++)
|
||
if(gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse == 0)
|
||
{
|
||
/* set the use mark */
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse =1;
|
||
/* set the remote address */
|
||
g_pfn_vNetMemcpy
|
||
(
|
||
&gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].stRemoteAddr.sin_addr,
|
||
&pRemoteAddr->sin_addr,
|
||
sizeof (pRemoteAddr->sin_addr)
|
||
);
|
||
/* Sets the port :*/
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].stRemoteAddr.sin_port=uwPortNumber;
|
||
/* set the ring to empty */
|
||
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].p_FirstDataCell=
|
||
(tdstNetDataCell *)C_pNull;
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/* there are no free channels */
|
||
return C_uwNetInvalidChannel; /* Error invalid channel ?*/
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: vL0PCWin95UDPCloseChannel
|
||
*
|
||
* frees a slot in the channel table
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: identifier of the channel
|
||
*
|
||
* Output: none
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
static void vL0PCWin95UDPCloseChannel(tduwNetChannel uwChannel)
|
||
{
|
||
tdstNetDataCell *p_DataCellNext;
|
||
tdstNetDataCell *p_DataCellCur;
|
||
|
||
/* broadcast channels should never be closed */
|
||
if(gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsBroadcast)
|
||
return;
|
||
/* clear the use mark */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsSlotInUse=0;
|
||
/* set the destination adress to none (let's be cautious) */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].stRemoteAddr.sin_addr.s_addr=
|
||
gs_p_stUDPWinSocDesc->m_pfn_ul_htonl(INADDR_NONE);
|
||
p_DataCellCur = p_DataCellNext =
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].p_FirstDataCell;
|
||
|
||
while(p_DataCellNext/*(tdstNetMessageCell *)!=()C_pNull*/)
|
||
{
|
||
p_DataCellNext = p_DataCellCur->p_stNextDataCell;
|
||
vFree((tdpPointer)p_DataCellCur->pData);
|
||
vFree((tdpPointer)p_DataCellCur);
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPInsertMessage
|
||
*
|
||
* insert a message at the end of a channel's queue
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: channel identifier, pointer to a message
|
||
*
|
||
* Output: error status
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPInsertMessage(tduwNetChannel uwChannel, tdpPointer pData)
|
||
{
|
||
tdstNetDataCell *p_DataCellNew;
|
||
|
||
p_DataCellNew = (tdstNetDataCell*)pMalloc(sizeof(tdstNetDataCell));
|
||
/* are we out of space ? */
|
||
if(!p_DataCellNew)
|
||
return NetLib_E_es_NotEnoughMemory;/* error: the ring is full */
|
||
|
||
/* no, store the message at the head of the ring */
|
||
p_DataCellNew->pData =pData;
|
||
p_DataCellNew->p_stNextDataCell =
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].p_FirstDataCell;
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].p_FirstDataCell =
|
||
p_DataCellNew;
|
||
|
||
return NetLib_E_es_NoError; /* no error */
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPRemoveMessage
|
||
*
|
||
* remove the first message of a channel's queue
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: channel identifier, address of a pointer to a message
|
||
*
|
||
* Output: error status
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPRemoveMessage(tduwNetChannel uwChannel, tdpPointer *ppData)
|
||
{
|
||
tdstL0PCWin95UDPChannel *p_stChSlot; /* a reference to the Channel slot */
|
||
tdstNetDataCell *p_DataCellCur;
|
||
tdstNetDataCell *p_DataCellPrev;
|
||
|
||
p_stChSlot=&gs_a_stL0PCWin95UDPChannels[uwChannel];
|
||
/* is there anything in the ring ? */
|
||
if(!p_stChSlot->p_FirstDataCell)
|
||
return NetLib_E_es_FIFOIsEmpty; /* error: the ring is empty */
|
||
|
||
/* yes, return message at the tail of the ring */
|
||
p_DataCellPrev = p_DataCellCur = p_stChSlot->p_FirstDataCell;
|
||
while(p_DataCellCur->p_stNextDataCell)
|
||
{
|
||
p_DataCellPrev = p_DataCellCur;
|
||
p_DataCellCur = p_DataCellCur->p_stNextDataCell;
|
||
}
|
||
|
||
*ppData= p_DataCellCur->pData;
|
||
if(p_stChSlot->p_FirstDataCell != p_DataCellCur )
|
||
{
|
||
vFree((tdpPointer)p_DataCellCur);
|
||
p_DataCellPrev->p_stNextDataCell = (tdstNetDataCell*)C_pNull;
|
||
}
|
||
else
|
||
p_stChSlot->p_FirstDataCell = (tdstNetDataCell*)C_pNull;
|
||
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPMessageAvailable
|
||
*
|
||
* test the availability of a message on the socket
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: none
|
||
*
|
||
* Output:
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPMessageAvailable(void)
|
||
{
|
||
static fd_set readfds;
|
||
static struct timeval timeout = { 0, 0 };
|
||
int ok;
|
||
|
||
FD_ZERO(&readfds);
|
||
FD_SET(gs_iSD, &readfds);
|
||
|
||
if((ok=gs_p_stUDPWinSocDesc->m_pfn_i_select(0, &readfds, NULL, NULL, &timeout))==SOCKET_ERROR)
|
||
{
|
||
return NetLib_E_es_SelectSocketFailure;
|
||
}
|
||
|
||
/* return TRUE iff there's something waiting to be read from our socket*/
|
||
if(ok!=0 && DLL_FD_ISSET(gs_iSD, &readfds))
|
||
return NetLib_E_es_True;
|
||
else
|
||
return NetLib_E_es_False;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPGetMessage
|
||
*
|
||
* Get one message from the socket and insert it in a channel
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: none
|
||
*
|
||
* Output: identifier of the channel associated to the remote end from which the message originates
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log: Adding check sum information
|
||
*
|
||
* Date: July 9,1996 Author: Albert Pais
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPGetMessage(void)
|
||
{
|
||
struct sockaddr_in s_stExpAddr; /* address of the expeditor of the received message */
|
||
int iNameLength; /* length of the above structure */
|
||
tdstNetMessage stMsgHeader; /* header of the incoming message */
|
||
unsigned long ulMsgSize; /* length of the incoming message (header included) */
|
||
tduwNetChannel uwChannel; /* channel in which to insert the incoming message */
|
||
tduwNetChannel uwReturnChannel; /* channel number to return */
|
||
tdpPointer pData; /* address of the block where the incoming message gets copied */
|
||
unsigned char ucLoopbackMessage; /* does the incoming message come from us */
|
||
|
||
pData=NULL;
|
||
iNameLength = sizeof s_stExpAddr;
|
||
do
|
||
{
|
||
/* is there anything to read from the socket ? */
|
||
if(eL0PCWin95UDPMessageAvailable()!=NetLib_E_es_True)
|
||
return C_uwNetInvalidChannel; /* error: no message available */
|
||
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_recvfrom(gs_iSD, (char *)&stMsgHeader, sizeof(stMsgHeader), MSG_PEEK,
|
||
(struct sockaddr *)&s_stExpAddr,&iNameLength)
|
||
==SOCKET_ERROR)
|
||
{
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_WSAGetLastError()!=WSAEMSGSIZE)
|
||
{
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
}
|
||
|
||
/* if big/little endian differs, swap the header before anything else*/
|
||
if (stMsgHeader.uxHeadBigEndian!=NetLib_ucGetLittleBigEndian())
|
||
NetLib_eSwapLittleBigEndianMsgHeader(&stMsgHeader);
|
||
|
||
/* check if the header is correct :*/
|
||
if
|
||
(
|
||
(M_uwCheckSumSlot((&stMsgHeader)) != M_uwProcessCheckSum((&stMsgHeader)))||
|
||
(stMsgHeader.eMessageType <= E_Net_mt_InvalidMessage)||
|
||
(stMsgHeader.eMessageType >= E_Net_mt_LastSysMsg)
|
||
)
|
||
{/* the message type is not correct :*/
|
||
/* Purge the message : */
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_recvfrom(gs_iSD, (char*)&stMsgHeader, 0, 0,
|
||
(struct sockaddr *)&s_stExpAddr, &iNameLength);
|
||
/* Return en invalid channel :*/
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
/* allocate a block of the size of the incoming message */
|
||
ulMsgSize=stMsgHeader.uwMessageSizeInBytes + sizeof(tdstNetMessage);
|
||
pData=pMalloc(ulMsgSize);
|
||
|
||
if(pData == C_pNull)
|
||
{/* the pointer couldn't be allocated :*/
|
||
/* Purge the message : */
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_recvfrom(gs_iSD, (char*)&stMsgHeader, 0, 0,
|
||
(struct sockaddr *)&s_stExpAddr, &iNameLength);
|
||
/* Return en invalid channel :*/
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
/* read the message into this block */
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_recvfrom(gs_iSD, pData, ulMsgSize, 0,
|
||
(struct sockaddr *)&s_stExpAddr, &iNameLength)==SOCKET_ERROR)
|
||
{
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISISI(Net_C_Debug_UDP,"Receive Type",stMsgHeader.eMessageType,
|
||
"Size",stMsgHeader.uwMessageSizeInBytes,
|
||
"Source",stMsgHeader.uxSenderId);
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
/* if the message originates from the host, discard it */
|
||
ucLoopbackMessage = s_stExpAddr.sin_addr.s_addr==gs_stMyAddress.s_addr;
|
||
if(ucLoopbackMessage)
|
||
vFree(pData);
|
||
/* loop until we read a 'real' message */
|
||
} while(ucLoopbackMessage);
|
||
|
||
/* does the message come from an already registered channel ? */
|
||
|
||
uwChannel=uwL0PCWin95UDPGetChannel(&s_stExpAddr);
|
||
|
||
if(uwChannel==C_uwNetInvalidChannel)
|
||
{
|
||
/* no, allocate a new channel */
|
||
uwChannel=uwL0PCWin95UDPOpenChannel(&s_stExpAddr,gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_port);
|
||
|
||
/* remember that this channel is new: insert its number into the broadcast channel's queue */
|
||
uwReturnChannel=0; /* zero is the broadcast channel's number */
|
||
eL0PCWin95UDPInsertMessage(uwReturnChannel, (tdpPointer)uwChannel);
|
||
|
||
/* mark the new channel as not readable */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsReadable=0;
|
||
}
|
||
else
|
||
uwReturnChannel=uwChannel;
|
||
|
||
/* insert the message into the associated channel's queue */
|
||
|
||
if(eL0PCWin95UDPInsertMessage(uwChannel, pData)==NetLib_E_es_FIFOIsFull)
|
||
return C_uwNetInvalidChannel;
|
||
|
||
/* return the channel number associated to the incoming message */
|
||
/* i.e. : - if the remote address wasn't already registered, return the broadcast channel's number */
|
||
/* - if it was, return the channel number of the queue in which the message has been inserted */
|
||
return uwReturnChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPStartChannelScan
|
||
*
|
||
* returns the identification number of the first channel for the protocol
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: none
|
||
*
|
||
* Output: identification of the channel
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPStartChannelScan(void)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the array of channel definitions */
|
||
for (uwCurrentChannel = 0; uwCurrentChannel < C_ucL0MaxNumberOfUDPChannels; uwCurrentChannel ++)
|
||
/* if the slot is used, and can transmit data to another individual player */
|
||
if
|
||
(
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsReadable
|
||
)
|
||
/* return its index value */
|
||
return uwCurrentChannel;
|
||
|
||
/* else no slot is in use */
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPNextChannel
|
||
*
|
||
* returns the identification number of the channel following the last
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: uwLastScannedChannel, index returned by the previous call
|
||
*
|
||
* Output: identification of the channel following the specified one
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPNextChannel(tduwNetChannel uwLastScannedChannel)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/*
|
||
* scan the array of channel definitions, starting with the channel following
|
||
* the last channel returned
|
||
*/
|
||
for
|
||
(
|
||
uwCurrentChannel = uwLastScannedChannel + 1;
|
||
uwCurrentChannel < C_ucL0MaxNumberOfUDPChannels;
|
||
uwCurrentChannel ++
|
||
)
|
||
/* if the slot is used, and can transmit data to another individual player */
|
||
if
|
||
(
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsReadable
|
||
)
|
||
/* return its index value */
|
||
return uwCurrentChannel;
|
||
|
||
/* else no slot is in use */
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPStartBroadcastChannelScan
|
||
*
|
||
* returns the identification number of the first broadcast channel
|
||
* for the protocol
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: none
|
||
*
|
||
* Output: identification of the channel
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPStartBroadcastChannelScan(void)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the array of channel definitions */
|
||
for (uwCurrentChannel = 0; uwCurrentChannel < C_ucL0MaxNumberOfUDPChannels; uwCurrentChannel ++)
|
||
/* if the slot is used, and the channel can send broadcast data */
|
||
if
|
||
(
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsBroadcast
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsReadable
|
||
)
|
||
/* return its index value */
|
||
return uwCurrentChannel;
|
||
|
||
/* else no slot is in use */
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95UDPNextBroadcastChannel
|
||
*
|
||
* returns the identification number of the broadcast channel following
|
||
* the specified one
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: uwLastScannedChannel, index returned by the previous call
|
||
*
|
||
* Output: identification of the channel following the specified one
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95UDPNextBroadcastChannel(tduwNetChannel uwLastScannedChannel)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/*
|
||
* scan the array of channel definitions, starting with the channel following
|
||
* the last channel returned
|
||
*/
|
||
for
|
||
(
|
||
uwCurrentChannel = uwLastScannedChannel + 1;
|
||
uwCurrentChannel < C_ucL0MaxNumberOfUDPChannels;
|
||
uwCurrentChannel ++
|
||
)
|
||
/* if the slot is used, and can transmit broadcast data */
|
||
if
|
||
(
|
||
gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsSlotInUse
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsBroadcast
|
||
&& gs_a_stL0PCWin95UDPChannels[uwCurrentChannel].ubf1IsReadable
|
||
)
|
||
/* return its index value */
|
||
return uwCurrentChannel;
|
||
|
||
/* else no slot is in use */
|
||
return C_uwNetInvalidChannel;
|
||
}
|
||
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPReadData
|
||
*
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: p_uwChannel, pointer on a field to store the identification of
|
||
* a new channel in case of access to a newly created broacast channel
|
||
* (irrelevant for the serial layer)
|
||
* ppData, address of the pointer to retrieve a full message if
|
||
* necessary.
|
||
*
|
||
* Output: an error condition.
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 26, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPReadData(tduwNetChannel *p_uwChannel, tdpPointer *ppData)
|
||
{
|
||
tduwNetChannel uwChannel;
|
||
tdpPointer pToBeCast;
|
||
|
||
/* verify the validity of the Channel */
|
||
if(*p_uwChannel>=C_ucL0MaxNumberOfUDPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[*p_uwChannel].ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[*p_uwChannel].ubf1IsReadable)
|
||
/* is it worth a new error code ? */
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
||
|
||
/* differenciate broadcast channel and normal channels */
|
||
|
||
if(gs_a_stL0PCWin95UDPChannels[*p_uwChannel].ubf1IsBroadcast)
|
||
{
|
||
/* is there already a message in the broadcast queue ? */
|
||
if(eL0PCWin95UDPRemoveMessage(*p_uwChannel, &pToBeCast)==NetLib_E_es_FIFOIsEmpty)
|
||
{
|
||
/* no : try to get a message from the socket */
|
||
do
|
||
{
|
||
/* read the first message available from the socket */
|
||
uwChannel=uwL0PCWin95UDPGetMessage();
|
||
/* until we get a message for the broadcast channel */
|
||
} while(uwChannel != *p_uwChannel && uwChannel != C_uwNetInvalidChannel);
|
||
|
||
if(uwChannel==C_uwNetInvalidChannel)
|
||
return NetLib_E_es_FIFOIsEmpty; /* error: no message available */
|
||
|
||
eL0PCWin95UDPRemoveMessage(uwChannel, &pToBeCast); /* normally this call produces no error */
|
||
}
|
||
|
||
uwChannel=(tduwNetChannel)pToBeCast;
|
||
/* we retrieved a channel number, now mark the channel as readable */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsReadable=1;
|
||
/* and retrieve the actual message from this channel*/
|
||
if(eL0PCWin95UDPRemoveMessage(uwChannel, ppData)==NetLib_E_es_FIFOIsEmpty)
|
||
return NetLib_E_es_ShouldNotReach; /* paranoid: there should be at least one message in the channel */
|
||
|
||
/* tell the caller which channel this message comes from */
|
||
*p_uwChannel=uwChannel;
|
||
|
||
return NetLib_E_es_NoError; /* no error */
|
||
}
|
||
|
||
/* the channel is not a broadcast channel */
|
||
|
||
/* is there already a message in the incoming queue ? */
|
||
|
||
if(eL0PCWin95UDPRemoveMessage(*p_uwChannel, ppData)==NetLib_E_es_NoError)
|
||
return NetLib_E_es_NoError; /* no error */
|
||
|
||
/* no : try to get a message from the socket */
|
||
|
||
do
|
||
{
|
||
/* read the first message available from the socket */
|
||
uwChannel=uwL0PCWin95UDPGetMessage();
|
||
/* until we get a message for the requested channel */
|
||
} while(uwChannel != *p_uwChannel && uwChannel != C_uwNetInvalidChannel);
|
||
|
||
/* if(uwChannel == C_uwNetInvalidChannel)*/
|
||
/* return NetLib_E_es_FIFOIsEmpty; /* error: no message available */
|
||
|
||
/* if(eL0PCWin95UDPRemoveMessage(uwChannel, ppData)==NetLib_E_es_FIFOIsEmpty)*/
|
||
return eL0PCWin95UDPRemoveMessage(*p_uwChannel, ppData);
|
||
/* return NetLib_E_es_ShouldNotReach; /* paranoid: there should be at least one message in the channel */
|
||
|
||
/* return NetLib_E_es_NoError; /* no error */
|
||
}
|
||
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPSendData
|
||
*
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: uwChannel, channel to send the message into.
|
||
* pData, pointer on the block to send
|
||
*
|
||
* Output: an error condition.
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 16, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
*****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPSendData(tduwNetChannel uwChannel, tdpPointer pData)
|
||
{
|
||
unsigned long ulBytestoSend;
|
||
unsigned long ulBytesSent;
|
||
|
||
/* verify the validity of the Channel */
|
||
|
||
if(uwChannel>=C_ucL0MaxNumberOfUDPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsReadable)
|
||
/* is it worth a new error code ? */
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
||
|
||
ulBytestoSend=((tdstNetMessage *) pData)->uwMessageSizeInBytes + sizeof(tdstNetMessage);
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISISI(Net_C_Debug_UDP,"Send Type",((tdstNetMessage *) pData)->eMessageType,
|
||
"Size",((tdstNetMessage *) pData)->uwMessageSizeInBytes,
|
||
"Dest",((tdstNetMessage *) pData)->uxRecipientId);
|
||
#endif /* NET_USE_DEBUG */
|
||
if
|
||
(
|
||
(ulBytesSent=gs_p_stUDPWinSocDesc->m_pfn_i_sendto
|
||
(
|
||
gs_iSD, pData, ulBytestoSend, 0,
|
||
(struct sockaddr *)&gs_a_stL0PCWin95UDPChannels[uwChannel].stRemoteAddr,
|
||
sizeof gs_a_stL0PCWin95UDPChannels[uwChannel].stRemoteAddr
|
||
)
|
||
)==SOCKET_ERROR
|
||
)
|
||
{
|
||
ulBytesSent=gs_p_stUDPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(ulBytesSent==WSAENETDOWN)
|
||
return NetLib_E_es_SendSocketFailure;
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
if(ulBytesSent!=ulBytestoSend)
|
||
return NetLib_E_es_MessagePartlySent;
|
||
|
||
/* if the message has been correctly sent, then the associated cell has to be freed */
|
||
vFree(pData);
|
||
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95UDPQueryChannelStatus
|
||
*
|
||
* returns the current status of the channel
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: uwChannel, channel to query
|
||
*
|
||
* Output: an error condition.
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 16, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPQueryChannelStatus(tduwNetChannel uwChannel)
|
||
{
|
||
/* verify the validity of the Channel */
|
||
if(uwChannel>=C_ucL0MaxNumberOfUDPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!gs_a_stL0PCWin95UDPChannels[uwChannel].ubf1IsReadable)
|
||
/* is it worth a new error code ? */
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
||
|
||
/* what else to report ???? */
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eLevel0InitWin95PCUDP
|
||
*
|
||
* initializes the global socket descriptor used for all channels
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: port number to use
|
||
*
|
||
* Output: an error code
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
|
||
NetLib_tdeErrorStatus eLevel0InitWin95PCUDP(void)
|
||
{
|
||
char ac80HostName[80]; /* the name of the computer the application is running on */
|
||
struct hostent *hp; /* the list of IP<49>adresses associated to the host */
|
||
|
||
/* find the host adress, set the corresponding global variable */
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_gethostname(ac80HostName, sizeof ac80HostName)==SOCKET_ERROR)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
if((hp=gs_p_stUDPWinSocDesc->m_pfn_pst_gethostbyname(ac80HostName))==NULL)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
gs_stMyAddress=*(struct in_addr *)(hp->h_addr_list[0]);
|
||
|
||
gs_bL0PCWin95UDPInitState = gs_bL0PCWin95UDPInitState | 0x02;
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus vL0PCWin95UDPAddPort
|
||
Add a new port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Christophe Roguet
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95UDPAddPort(unsigned short uwPortNumber)
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_UDP,"AddPort",uwPortNumber);
|
||
#endif /* NET_USE_DEBUG */
|
||
return eL0PCWin95DirectUDPAddPort(uwPortNumber, INADDR_BROADCAST);
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95DirectUDPAddPort
|
||
Add a new port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number
|
||
IP address of machine to connect to
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Christophe Roguet
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95DirectUDPAddPort(unsigned short uwPortNumber, long ConnectAddress)
|
||
{
|
||
struct sockaddr_in my_name; /* the address to bind the socket to */
|
||
int iOpt; /* parameter used for socket option setting */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISI(Net_C_Debug_UDP,"DirectAddPort Num",uwPortNumber,"Adress",ConnectAddress);
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
if(uwPortNumber < IPPORT_RESERVED)
|
||
return NetLib_E_es_InvalidPortNumber;
|
||
|
||
/* While we'v got only one socket, close it before opening a new one*/
|
||
if(gs_iSD!=INVALID_SOCKET)
|
||
{
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
||
gs_iSD = INVALID_SOCKET;
|
||
}
|
||
/* open an IP datagram socket */
|
||
gs_iSD = gs_p_stUDPWinSocDesc->m_pfn_ui_socket(PF_INET, SOCK_DGRAM, 0);
|
||
|
||
if(gs_iSD==INVALID_SOCKET)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* bind our socket to our specific port */
|
||
my_name.sin_family = AF_INET;
|
||
my_name.sin_port = gs_p_stUDPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
my_name.sin_addr = gs_stMyAddress;
|
||
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_bind(gs_iSD, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* allow the socket to send broadcast messages */
|
||
iOpt=~0;
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_setsockopt(gs_iSD, SOL_SOCKET, SO_BROADCAST, (char *)&iOpt, sizeof(iOpt))<0)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* initialize channel 0 as broadcast channel */
|
||
/* the broadcast channel is always in use */
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsSlotInUse = 1;
|
||
|
||
/* this is a channel usable to send only broadcast messages */
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsBroadcast = 1;
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsReadable = 1;
|
||
|
||
/* Set the first cell to null :*/
|
||
gs_a_stL0PCWin95UDPChannels[0].p_FirstDataCell = (tdstNetDataCell *)C_pNull;
|
||
|
||
/* set the destination adress */
|
||
gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_family = AF_INET;
|
||
gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_port = gs_p_stUDPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_addr.s_addr=gs_p_stUDPWinSocDesc->m_pfn_ul_htonl(ConnectAddress);
|
||
|
||
/* the channel is working properly */
|
||
gs_a_stL0PCWin95UDPChannels[0].eChannelStatus = E_ts_OK;
|
||
gs_uwNumberOfPort++;
|
||
gs_bL0PCWin95UDPInitState = gs_bL0PCWin95UDPInitState | 0x04;
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95UDPAddPortSym
|
||
Add a new port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number to use
|
||
remote IP address to send 'broadcast' messages to
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Albert Pais
|
||
|
||
modification log:
|
||
|
||
Date: June 6, 1996 Author: Christophe ROGUET
|
||
added the connect address parameter
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95DirectUDPAddPortSym(unsigned short uwPortNumber, char *ConnectAddress)
|
||
{
|
||
unsigned long NumAddr;
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_UDP,"AddPortSym Num",uwPortNumber);
|
||
vDebugSS(Net_C_Debug_UDP,"AddPortSym Adress : ",ConnectAddress);
|
||
#endif /* NET_USE_DEBUG */
|
||
/* WinSock doesn't have inet_aton(), we have to use inet_addr() */
|
||
if((NumAddr=gs_p_stUDPWinSocDesc->m_pfn_ul_inet_addr(ConnectAddress))!=INADDR_NONE)
|
||
return eL0PCWin95DirectUDPAddPort(uwPortNumber, gs_p_stUDPWinSocDesc->m_pfn_ul_ntohl(NumAddr));
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : vL0PCWin95UDPCloseProtocol(void)
|
||
udp-Level 0 closing function
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
void vL0PCWin95UDPCloseProtocol(void)
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_UDP,"Close protocol");
|
||
#endif /* NET_USE_DEBUG */
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
||
|
||
eNetRestoreWinSock();
|
||
gs_cIsWinsocDescInit=0;
|
||
|
||
vLevel1RemoveProtocol(E_Net_pr_Windows95UDPProtocol);
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: vL0PCWin95UDPOpenProtocol
|
||
*
|
||
* initialize the specified interface structure with the correct function
|
||
* pointers to enable a protocol-independent data transmission process.
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input: p_stProtocolInterface, pointer to the interface structure
|
||
*
|
||
* Output: none
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
void _NET_CALLING_CONV_ vL0PCWin95UDPOpenProtocol(void)
|
||
{
|
||
tduwNetChannel uwChannelToInit;
|
||
tdstNetProtocolInterface *p_stProtocolInterface;
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugClear(Net_C_Debug_UDP);
|
||
vDebugS(Net_C_Debug_UDP,"Netlib - Level 0 - UDP WIN95 : Log file");
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
gs_bL0PCWin95UDPInitState = 0x00;
|
||
|
||
/* bind to the DLL if necessary */
|
||
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if(eNetGetWinSockDesc(&gs_p_stUDPWinSocDesc)!=NetLib_E_es_NoError)
|
||
return ;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
/* initialize our socket descriptor */
|
||
|
||
if(eLevel0InitWin95PCUDP()!=NetLib_E_es_NoError)
|
||
return;
|
||
|
||
gs_uwNumberOfPort = 0;
|
||
|
||
p_stProtocolInterface=pstLevel1AddProtocol();
|
||
|
||
/* logical identification of the protocol */
|
||
p_stProtocolInterface->eProtocol = E_Net_pr_Windows95UDPProtocol;
|
||
|
||
/* setup the function pointers */
|
||
p_stProtocolInterface->fn_uwStartChannelScan = uwL0PCWin95UDPStartChannelScan;
|
||
p_stProtocolInterface->fn_uwStartBroadcastChannelScan= uwL0PCWin95UDPStartBroadcastChannelScan;
|
||
p_stProtocolInterface->fn_uwNextChannel= uwL0PCWin95UDPNextChannel;
|
||
p_stProtocolInterface->fn_uwNextBroadcastChannel= uwL0PCWin95UDPNextBroadcastChannel;
|
||
p_stProtocolInterface->fn_eReadData= eL0PCWin95UDPReadData;
|
||
p_stProtocolInterface->fn_eSendData= eL0PCWin95UDPSendData;
|
||
p_stProtocolInterface->fn_eQueryChannelStatus= eL0PCWin95UDPQueryChannelStatus;
|
||
p_stProtocolInterface->fn_vLevel0NetEngine = (void (*)(void))C_pNull;
|
||
p_stProtocolInterface->fn_vCloseChannel = vL0PCWin95UDPCloseChannel;
|
||
p_stProtocolInterface->fn_vLevel0CloseProtocol = vL0PCWin95UDPCloseProtocol;
|
||
p_stProtocolInterface->eIsInternet = 1;
|
||
|
||
|
||
/* initialize all other slots as unused channels */
|
||
|
||
for (uwChannelToInit = 0; uwChannelToInit < C_ucL0MaxNumberOfUDPChannels; uwChannelToInit ++)
|
||
{
|
||
/* the channel is not used yet */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].ubf1IsSlotInUse = 0;
|
||
|
||
/* this is a channel usable to send private messages */
|
||
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].ubf1IsBroadcast = 0;
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].ubf1IsReadable = 0;
|
||
|
||
/* initialize the destination address: */
|
||
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].stRemoteAddr.sin_family=AF_INET;
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].stRemoteAddr.sin_port=0;
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].stRemoteAddr.sin_addr.s_addr=gs_p_stUDPWinSocDesc->m_pfn_ul_htonl(INADDR_NONE);
|
||
|
||
/* the channel is working properly */
|
||
gs_a_stL0PCWin95UDPChannels[uwChannelToInit].eChannelStatus = E_ts_OK;
|
||
}
|
||
gs_iSD = INVALID_SOCKET;
|
||
|
||
gs_bL0PCWin95UDPInitState = gs_bL0PCWin95UDPInitState | 0x01;
|
||
}
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95UDPIsProtocolSet
|
||
Check if the protocol is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_ProtocolNotInitialized : the vLevel0SetupWin95PCUDPInterface has not
|
||
been called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function.
|
||
NetLib_E_es_InitialisationSocketError : the eLevel0InitWin95PCUDP function has not been
|
||
called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function
|
||
NetLib_E_es_NoPortSelected : the eL0PCWin95UDPAddPort has not been called yet. The
|
||
protocol has been correctly initialised, it can be used, but it won't give any
|
||
results since no port is avaible. The application should call it.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 4,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95UDPIsProtocolSet(void)
|
||
{
|
||
if(!(gs_bL0PCWin95UDPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
if(!(gs_bL0PCWin95UDPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
if(!(gs_bL0PCWin95UDPInitState&0x04))
|
||
return NetLib_E_es_NoPortSelected;
|
||
return NetLib_E_es_True;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : vL0PCWin95UDPClosePort
|
||
Close the socket bound with the specified port number
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
The port number to close
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
None
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 25,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
|
||
void _NET_CALLING_CONV_ vL0PCWin95UDPClosePort(unsigned short uwOldPort)
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_UDP,"Close port",uwOldPort);
|
||
#endif /* NET_USE_DEBUG */
|
||
if
|
||
(
|
||
(gs_bL0PCWin95UDPInitState&0x04)&&
|
||
(uwOldPort == gs_p_stUDPWinSocDesc->m_pfn_uw_ntohs(gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_port))
|
||
)
|
||
{
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
||
gs_iSD = INVALID_SOCKET;
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsSlotInUse = 0;
|
||
/* this is a channel usable to send only broadcast messages */
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsBroadcast = 0;
|
||
gs_a_stL0PCWin95UDPChannels[0].ubf1IsReadable = 0;
|
||
|
||
/* the channel is working properly */
|
||
gs_a_stL0PCWin95UDPChannels[0].eChannelStatus = E_ts_Invalid;
|
||
gs_uwNumberOfPort--;
|
||
|
||
gs_bL0PCWin95UDPInitState = gs_bL0PCWin95UDPInitState& ~0x04;
|
||
}
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95UDPIsPortAvailable
|
||
Check if the port is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
A port number to test
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_True if the port is avaible
|
||
NetLib_E_es_PortAlreayUsed if the port is already in use
|
||
An error code otherwise
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 25,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95UDPIsPortAvailable(unsigned short uwPortNumber)
|
||
{
|
||
struct sockaddr_in my_name; /* the address to bind the socket to */
|
||
int iOpt; /* parameter used for socket option setting */
|
||
int iTempSock;
|
||
NetLib_tdeErrorStatus eErrorReturned;
|
||
|
||
/* bind to the DLL if necessary */
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if((eErrorReturned=eNetGetWinSockDesc(&gs_p_stUDPWinSocDesc))!=NetLib_E_es_NoError)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
if(uwPortNumber<IPPORT_RESERVED)
|
||
return NetLib_E_es_InvalidPortNumber;
|
||
|
||
iTempSock = gs_p_stUDPWinSocDesc->m_pfn_ui_socket(PF_INET, SOCK_DGRAM, 0);
|
||
|
||
if(iTempSock==INVALID_SOCKET)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* bind our socket to our specific port */
|
||
my_name.sin_family = AF_INET;
|
||
my_name.sin_port = gs_p_stUDPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
my_name.sin_addr = gs_stMyAddress;
|
||
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_bind(iTempSock, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
||
{
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_WSAGetLastError()==WSAEADDRINUSE)
|
||
eErrorReturned = NetLib_E_es_PortAlreadyUsed;
|
||
else
|
||
eErrorReturned = NetLib_E_es_False;
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
||
return eErrorReturned;
|
||
}
|
||
|
||
/* allow the socket to send broadcast messages */
|
||
iOpt=~0;
|
||
if(gs_p_stUDPWinSocDesc->m_pfn_i_setsockopt(iTempSock, SOL_SOCKET, SO_BROADCAST, (char *)&iOpt, sizeof(iOpt))<0)
|
||
{
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
||
return NetLib_E_es_False;
|
||
}
|
||
gs_p_stUDPWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
||
return NetLib_E_es_True;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95UDPIsProtocolAvailable
|
||
Check if the protocol is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
A port number to test
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_True if the port is avaible
|
||
An error code otherwise
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 25,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95UDPIsProtocolAvailable(void)
|
||
{
|
||
unsigned short uwPortNumberTest;
|
||
NetLib_tdeErrorStatus eErrorReturned;
|
||
|
||
/* bind to the DLL if necessary */
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if((eErrorReturned=eNetGetWinSockDesc(&gs_p_stUDPWinSocDesc))!=NetLib_E_es_NoError)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
uwPortNumberTest = IPPORT_RESERVED+1000;
|
||
while
|
||
(
|
||
((eErrorReturned = eL0PCWin95UDPIsPortAvailable(uwPortNumberTest))==NetLib_E_es_PortAlreadyUsed)&&
|
||
(uwPortNumberTest<IPPORT_RESERVED+1100)
|
||
)
|
||
uwPortNumberTest++;
|
||
return eErrorReturned;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95UDPIsPortOpened
|
||
Returns wether the port is opened or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
A port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
an tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 27,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95UDPIsPortOpened(unsigned short uwPortNumber)
|
||
{
|
||
if(!(gs_bL0PCWin95UDPInitState&0x04))
|
||
return NetLib_E_es_NoPortSelected;
|
||
if(!(uwPortNumber == gs_p_stUDPWinSocDesc->m_pfn_uw_ntohs(gs_a_stL0PCWin95UDPChannels[0].stRemoteAddr.sin_port)))
|
||
return NetLib_E_es_False;
|
||
return NetLib_E_es_True;
|
||
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95UDPMyAddress
|
||
Check if the protocol is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
array of characters to store an alphanumeric name into
|
||
size of the array
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_ProtocolNotInitialized : the vLevel0SetupWin95PCUDPInterface has not
|
||
been called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function.
|
||
NetLib_E_es_InitialisationSocketError : the eLevel0InitWin95PCUDP function has not been
|
||
called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : July 4,96
|
||
Author : Christophe Roguet
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus eL0PCWin95UDPGetMyAddress(char *pcReturnStringAddress, unsigned short Size)
|
||
{
|
||
char LocalStringAddress[80];
|
||
|
||
if(!(gs_bL0PCWin95UDPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
if(!(gs_bL0PCWin95UDPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError ;
|
||
|
||
/* translate the numerical address into an alphabetic string */
|
||
strncpy(LocalStringAddress, gs_p_stUDPWinSocDesc->m_pfn_pc_inet_ntoa(gs_stMyAddress), 80);
|
||
|
||
/* if the address string is too long to fit in the caller's array, return an error value */
|
||
if(strlen(LocalStringAddress)+1>Size)
|
||
{
|
||
memset(pcReturnStringAddress, '\0', Size);
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
strcpy(pcReturnStringAddress, LocalStringAddress);
|
||
return NetLib_E_es_NoError;
|
||
}
|