1487 lines
55 KiB
C
1487 lines
55 KiB
C
/*
|
|
* universal multiplayer library level 0 implementation file
|
|
* transport layer: IPX datagrams PC-windows 95
|
|
*/
|
|
|
|
/*
|
|
* Author: Christophe Roguet after Benoit GERMAIN
|
|
*
|
|
* Creation Date: 03/05/96
|
|
*
|
|
* this file is extremely similar with the UDP version: only the parts that are bound to the address structure change
|
|
* and parts where socket options that work with UDP don't with IPX (MSG_PEEK, FIONREAD ...)
|
|
*/
|
|
|
|
/* with a non blocking socket */
|
|
|
|
#include "warnings.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4306)
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include "Privl0ipx.h"
|
|
#include "PrivNetDef.h"
|
|
#include "l0GlDef.h"
|
|
#include "NetMemCo.h"
|
|
#include "NetSock.h"
|
|
#include "NetEnd.h"
|
|
#include <NET\Netdebug.h>
|
|
|
|
/* array of descriptors to access a physical channel. */
|
|
static tdstL0PCWin95IPXChannel gs_a_stL0PCWin95IPXChannels[C_ucL0MaxNumberOfIPXChannels];
|
|
|
|
/* the IPX adress of the computer the application is running on, in network order */
|
|
|
|
static SOCKADDR_IPX gs_stMyAddress;
|
|
|
|
/* the global socket descriptor used for all net operations */
|
|
|
|
static int gs_iSD;
|
|
|
|
static char gs_bL0PCWin95IPXInitState;
|
|
|
|
static tdstWinSockFunc *gs_p_stIPXWinSocDesc;
|
|
static char gs_cIsWinsocDescInit = 0;
|
|
|
|
#define DLL_FD_ISSET(fd, set) ((gs_p_stIPXWinSocDesc->m_pfn_i_WSAFDIsSet)((SOCKET)(fd), (fd_set *)(set)))
|
|
|
|
/* Flot control */
|
|
static int gs_iNbSendByNetEngine;
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: uwL0PCWin95IPXGetChannel
|
|
*
|
|
* look up the channel associated to a particular remote address
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: inet address to look up
|
|
*
|
|
* Output: identification of the channel
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXGetChannel(SOCKADDR_IPX *p_stKey)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
for
|
|
(
|
|
uwCurrentChannel=0;
|
|
uwCurrentChannel<C_ucL0MaxNumberOfIPXChannels;
|
|
uwCurrentChannel++
|
|
)
|
|
if(
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse==1
|
|
/*&&!memcmp(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum,
|
|
p_stKey->sa_netnum,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum)
|
|
*/&&!memcmp(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_nodenum,
|
|
p_stKey->sa_nodenum,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_nodenum))
|
|
return uwCurrentChannel;
|
|
|
|
return C_uwNetInvalidChannel; /* Error invalid channel ?*/
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: uwL0PCWin95IPXOpenChannel
|
|
*
|
|
* returns the identification number of an unused slot in the channel table
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: inet address to bind to the channel
|
|
*
|
|
* Output: identification of the channel
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXOpenChannel(SOCKADDR_IPX *p_stRemoteAddr, unsigned short uwPortNumber)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
/* scan the channel table until we find an unused slot */
|
|
|
|
for
|
|
(
|
|
uwCurrentChannel=0;
|
|
uwCurrentChannel<C_ucL0MaxNumberOfIPXChannels;
|
|
uwCurrentChannel++
|
|
)
|
|
|
|
if(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse == 0)
|
|
{
|
|
/* set the use mark */
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse =1;
|
|
|
|
/* set the remote address */
|
|
/*memcpy(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum,
|
|
p_stRemoteAddr->sa_netnum,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum);*/
|
|
memset(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum,
|
|
0,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_netnum);
|
|
memcpy(gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_nodenum,
|
|
p_stRemoteAddr->sa_nodenum,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_nodenum);
|
|
/* remark: the socket number in RemoteAddr might be a local, system allocated socket number */
|
|
/* (I am not sure of this), so we don't copy the whole SOCKADDR_IPX structure, but only */
|
|
/* the previous two fields. The socket number has been set to the right value */
|
|
/* for all channels in the call to vLevel0InitWin95PCIPX() (and the address family as well).*/
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].stRemoteAddr.sa_socket=uwPortNumber;
|
|
|
|
/* set the ring to empty */
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ucHead=
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ucTail=0;
|
|
|
|
return uwCurrentChannel;
|
|
}
|
|
|
|
/* there are no free channels */
|
|
|
|
return C_uwNetInvalidChannel; /* Error invalid channel ?*/
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXCloseAndResetChannel
|
|
*
|
|
* Close properluy the corresponding channel
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: identifier of the channel
|
|
*
|
|
* Output: none
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXCloseAndResetChannel(tduwNetChannel uwChannel)
|
|
{
|
|
tdpPointer p_Msg;
|
|
|
|
if(uwChannel>=C_ucL0MaxNumberOfIPXChannels)
|
|
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsSlotInUse)
|
|
return NetLib_E_es_NoError; /* the slot is not initialized for use */
|
|
|
|
/* clear the use mark */
|
|
while(eL0PCWin95IPXRemoveMessage(uwChannel,&p_Msg)==NetLib_E_es_NoError)
|
|
{
|
|
vFree(p_Msg);
|
|
}
|
|
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsSlotInUse=0;
|
|
|
|
/* set the destination adress to none (let's be cautious) */
|
|
memset(gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr.sa_netnum, 0,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr.sa_netnum);
|
|
memset(gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr.sa_nodenum, 0,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr.sa_nodenum);
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr.sa_socket =0;
|
|
|
|
/* the channel is working properly */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].eChannelStatus = E_ts_Invalid;
|
|
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: vL0PCWin95IPXCloseChannel
|
|
*
|
|
* frees a slot in the channel table
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: identifier of the channel
|
|
*
|
|
* Output: none
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
void vL0PCWin95IPXCloseChannel(tduwNetChannel uwChannel)
|
|
{
|
|
/* broadcast channels should never be closed */
|
|
if(gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsBroadcast)
|
|
return;
|
|
|
|
eL0PCWin95IPXCloseAndResetChannel(uwChannel);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXInsertMessage
|
|
*
|
|
* insert a message at the end of a channel's queue
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: channel identifier, pointer to a message
|
|
*
|
|
* Output: error status
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXInsertMessage(tduwNetChannel uwChannel, tdpPointer pData)
|
|
{
|
|
/* are we out of space ? */
|
|
if((1+gs_a_stL0PCWin95IPXChannels[uwChannel].ucHead)%C_ucL0MaxNumberOfMsgPerChannel
|
|
== gs_a_stL0PCWin95IPXChannels[uwChannel].ucTail)
|
|
return NetLib_E_es_FIFOIsFull; /* error: the ring is full */
|
|
|
|
/* no, store the message at the head of the ring */
|
|
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].apMsgQueue[gs_a_stL0PCWin95IPXChannels[uwChannel].ucHead]=pData;
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].ucHead=(++gs_a_stL0PCWin95IPXChannels[uwChannel].ucHead)%C_ucL0MaxNumberOfMsgPerChannel;
|
|
|
|
return NetLib_E_es_NoError; /* no error */
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXRemoveMessage
|
|
*
|
|
* remove the first message of a channel's queue
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: channel identifier, address of a pointer to a message
|
|
*
|
|
* Output: error status
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXRemoveMessage(tduwNetChannel uwChannel, tdpPointer *ppData)
|
|
{
|
|
/* is there anything in the ring ? */
|
|
if(gs_a_stL0PCWin95IPXChannels[uwChannel].ucTail==gs_a_stL0PCWin95IPXChannels[uwChannel].ucHead)
|
|
return NetLib_E_es_FIFOIsEmpty; /* error: the ring is empty */
|
|
|
|
/* yes, return message at the tail of the ring */
|
|
*ppData=gs_a_stL0PCWin95IPXChannels[uwChannel].apMsgQueue[gs_a_stL0PCWin95IPXChannels[uwChannel].ucTail];
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].ucTail=
|
|
(++gs_a_stL0PCWin95IPXChannels[uwChannel].ucTail)%C_ucL0MaxNumberOfMsgPerChannel;
|
|
|
|
return NetLib_E_es_NoError;
|
|
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXMessageAvailable
|
|
*
|
|
* test the availability of a message on the socket
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: none
|
|
*
|
|
* Output:
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXMessageAvailable(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_stIPXWinSocDesc->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: uwL0PCWin95IPXGetMessage
|
|
*
|
|
* Get one message from the socket and insert it in a channel
|
|
*
|
|
* remark: Due to a bug (?) in wsock32.dll for win95, we can't perform a recvfrom
|
|
* in MSG_PEEK mode, as we do with UDP.
|
|
*****************************************************************************
|
|
*
|
|
* Input: none
|
|
*
|
|
* Output: identifier of the channel associated to the remote end from which the message originates
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXGetMessage(void)
|
|
{
|
|
SOCKADDR_IPX s_stExpAddr; /* address of the expeditor of the received message */
|
|
int iNameLength; /* length of the above structure */
|
|
unsigned long ulMsgSize; /* length of the incoming message (header included) */
|
|
long lReceivedBytes;
|
|
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 ucDiscardMessage; /* the incoming message comes from ourself, or it is a wrong one */
|
|
tdstNetMessage *p_stMsgReceived;
|
|
|
|
pData=NULL;
|
|
|
|
iNameLength=sizeof s_stExpAddr;
|
|
|
|
do
|
|
{
|
|
/* is there anything to read from the socket ? */
|
|
|
|
if(eL0PCWin95IPXMessageAvailable()!=NetLib_E_es_True)
|
|
return C_uwNetInvalidChannel; /* error: no message available */
|
|
|
|
/* read the size of datagram waiting to be read */
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_ioctlsocket(gs_iSD, FIONREAD, &ulMsgSize)==SOCKET_ERROR)
|
|
return C_uwNetInvalidChannel;
|
|
|
|
/* allocate a block of the size of the message */
|
|
pData=pMalloc(ulMsgSize);
|
|
|
|
if(pData==C_pNull)
|
|
return C_uwNetInvalidChannel; /* no memory left */
|
|
|
|
/* read the message into this block */
|
|
if((lReceivedBytes=gs_p_stIPXWinSocDesc->m_pfn_i_recvfrom(gs_iSD, pData, ulMsgSize, 0,
|
|
(struct sockaddr *)&s_stExpAddr, &iNameLength))==SOCKET_ERROR) {
|
|
vFree(pData);
|
|
return C_uwNetInvalidChannel; /* the socket can't be read ? */
|
|
}
|
|
|
|
/* if the received datagram is smaller than a header then this can't be one of our messages */
|
|
/* and , if the message originates from the host, discard it */
|
|
ucDiscardMessage = lReceivedBytes < sizeof(tdstNetMessage)
|
|
|| (/*!memcmp(s_stExpAddr.sa_netnum, gs_stMyAddress.sa_netnum, sizeof s_stExpAddr.sa_netnum)
|
|
&& */!memcmp(s_stExpAddr.sa_nodenum, gs_stMyAddress.sa_nodenum, sizeof s_stExpAddr.sa_nodenum));
|
|
|
|
if(!ucDiscardMessage) {
|
|
/* at least we have a block of data that can be a header : test this */
|
|
|
|
p_stMsgReceived = (tdstNetMessage*)pData;
|
|
/* if big/little endian differs, swap the header before anything else*/
|
|
if (p_stMsgReceived->uxHeadBigEndian!=NetLib_ucGetLittleBigEndian())
|
|
NetLib_eSwapLittleBigEndianMsgHeader(p_stMsgReceived);
|
|
|
|
ucDiscardMessage =
|
|
(M_uwCheckSumSlot(p_stMsgReceived)!=M_uwProcessCheckSum(p_stMsgReceived))||
|
|
(p_stMsgReceived->eMessageType <=E_Net_mt_InvalidMessage)||
|
|
(p_stMsgReceived->eMessageType >=E_Net_mt_LastSysMsg)||
|
|
/* verify that the data block has the size indicated in the header */
|
|
(p_stMsgReceived->uwMessageSizeInBytes + sizeof(tdstNetMessage) != (unsigned long)lReceivedBytes);
|
|
}
|
|
|
|
if(ucDiscardMessage)
|
|
{
|
|
/* Either an incorrect msg was read or the message came from this machine*/
|
|
/* free the allocated block */
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSI(Net_C_Debug_IPX,"GetMessage(): msg discarded",lReceivedBytes);
|
|
#endif /* NET_USE_DEBUG */
|
|
vFree(pData);
|
|
} else {
|
|
|
|
/* reallocate a block of the right size (FIONREAD should return the size of the next datagram, */
|
|
/* but instead it returns the total size of all datagrams waiting to be read, so the actual */
|
|
/* datagram is eventually smaller than what FIONREAD gave) */
|
|
|
|
p_stMsgReceived=(tdstNetMessage *)pData;
|
|
if(ulMsgSize!=sizeof(tdstNetMessage) + p_stMsgReceived->uwMessageSizeInBytes) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISI(Net_C_Debug_IPX,"GetMessage(): real size",
|
|
sizeof(tdstNetMessage) + p_stMsgReceived->uwMessageSizeInBytes,
|
|
"not",ulMsgSize);
|
|
#endif /* NET_USE_DEBUG */
|
|
ulMsgSize=sizeof(tdstNetMessage) + p_stMsgReceived->uwMessageSizeInBytes;
|
|
pData=pMalloc(ulMsgSize);
|
|
if(pData==C_pNull) {
|
|
vFree((tdpPointer)p_stMsgReceived);
|
|
return C_uwNetInvalidChannel; /* no memory left */
|
|
/* remark: we could continue with p_stMsgReceived */
|
|
}
|
|
memcpy(pData, p_stMsgReceived, ulMsgSize);
|
|
vFree((tdpPointer)p_stMsgReceived);
|
|
}
|
|
}
|
|
|
|
/* loop until we read a 'real' message */
|
|
} while(ucDiscardMessage);
|
|
|
|
/* does the message come from an already registered channel ? */
|
|
|
|
uwChannel=uwL0PCWin95IPXGetChannel(&s_stExpAddr);
|
|
|
|
if(uwChannel==C_uwNetInvalidChannel)
|
|
{
|
|
/* no, allocate a new channel */
|
|
uwChannel=uwL0PCWin95IPXOpenChannel(&s_stExpAddr,gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_socket);
|
|
if(uwChannel==C_uwNetInvalidChannel) { /* can't allocate a new channel */
|
|
vFree(pData); /* the message gets lost ... */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/* remember that this channel is new: insert its number into the broadcast channel's queue */
|
|
uwReturnChannel=0; /* zero is the broadcast channel's number */
|
|
|
|
if(eL0PCWin95IPXInsertMessage(uwReturnChannel, (tdpPointer)uwChannel)!=NetLib_E_es_NoError) {
|
|
/* there is no room left to store the channel number in the broadcast channel */
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_IPX,"GetMessage(): msg lost: broadcast table full");
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
vFree(pData); /* the message gets lost ... */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/* mark the new channel as not readable */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsReadable=0;
|
|
}
|
|
else
|
|
uwReturnChannel=uwChannel;
|
|
|
|
/* insert the message into the associated channel's queue */
|
|
if(eL0PCWin95IPXInsertMessage(uwChannel, pData)!=NetLib_E_es_NoError) {
|
|
/* there is no room left to store the message in the channel */
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSIS(Net_C_Debug_IPX,"GetMessage(): msg lost: channel",uwChannel,"table full");
|
|
#endif /* NET_USE_DEBUG */
|
|
vFree(pData); /* the message gets lost */
|
|
}
|
|
|
|
/* 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: uwL0PCWin95IPXStartChannelScan
|
|
*
|
|
* returns the identification number of the first channel for the protocol
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: none
|
|
*
|
|
* Output: identification of the channel
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXStartChannelScan(void)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
/* scan the array of channel definitions */
|
|
for (uwCurrentChannel = 0; uwCurrentChannel < C_ucL0MaxNumberOfIPXChannels; uwCurrentChannel ++)
|
|
/* if the slot is used, and can transmit data to another individual player */
|
|
if
|
|
(
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsReadable
|
|
)
|
|
/* return its index value */
|
|
return uwCurrentChannel;
|
|
|
|
/* else no slot is in use */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: uwL0PCWin95IPXNextChannel
|
|
*
|
|
* 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: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXNextChannel(tduwNetChannel uwLastScannedChannel)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
/*
|
|
* scan the array of channel definitions, starting with the channel following
|
|
* the last channel returned
|
|
*/
|
|
for
|
|
(
|
|
uwCurrentChannel = (tduwNetChannel)(uwLastScannedChannel + 1);
|
|
uwCurrentChannel < C_ucL0MaxNumberOfIPXChannels;
|
|
uwCurrentChannel ++
|
|
)
|
|
/* if the slot is used, and can transmit data to another individual player */
|
|
if
|
|
(
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsReadable
|
|
)
|
|
/* return its index value */
|
|
return uwCurrentChannel;
|
|
|
|
/* else no slot is in use */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: uwL0PCWin95IPXStartBroadcastChannelScan
|
|
*
|
|
* returns the identification number of the first broadcast channel
|
|
* for the protocol
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: none
|
|
*
|
|
* Output: identification of the channel
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXStartBroadcastChannelScan(void)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
/* scan the array of channel definitions */
|
|
for (uwCurrentChannel = 0; uwCurrentChannel < C_ucL0MaxNumberOfIPXChannels; uwCurrentChannel ++)
|
|
/* if the slot is used, and the channel can send broadcast data */
|
|
if
|
|
(
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsBroadcast
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsReadable
|
|
)
|
|
/* return its index value */
|
|
return uwCurrentChannel;
|
|
|
|
/* else no slot is in use */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: uwL0PCWin95IPXNextBroadcastChannel
|
|
*
|
|
* 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: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
tduwNetChannel uwL0PCWin95IPXNextBroadcastChannel(tduwNetChannel uwLastScannedChannel)
|
|
{
|
|
tduwNetChannel uwCurrentChannel;
|
|
|
|
/*
|
|
* scan the array of channel definitions, starting with the channel following
|
|
* the last channel returned
|
|
*/
|
|
for
|
|
(
|
|
uwCurrentChannel = (tduwNetChannel)(uwLastScannedChannel + 1);
|
|
uwCurrentChannel < C_ucL0MaxNumberOfIPXChannels;
|
|
uwCurrentChannel ++
|
|
)
|
|
/* if the slot is used, and can transmit broadcast data */
|
|
if
|
|
(
|
|
gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsSlotInUse
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsBroadcast
|
|
&& gs_a_stL0PCWin95IPXChannels[uwCurrentChannel].ubf1IsReadable
|
|
)
|
|
/* return its index value */
|
|
return uwCurrentChannel;
|
|
|
|
/* else no slot is in use */
|
|
return C_uwNetInvalidChannel;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXReadData
|
|
*
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* 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: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXReadData(tduwNetChannel *p_uwChannel, tdpPointer *ppData)
|
|
{
|
|
tduwNetChannel uwChannel;
|
|
tdpPointer pToBeCast;
|
|
|
|
/* verify the validity of the Channel */
|
|
|
|
if(*p_uwChannel>=C_ucL0MaxNumberOfIPXChannels)
|
|
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[*p_uwChannel].ubf1IsSlotInUse)
|
|
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[*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_stL0PCWin95IPXChannels[*p_uwChannel].ubf1IsBroadcast)
|
|
{
|
|
/* is there already a message in the broadcast queue ? */
|
|
if(eL0PCWin95IPXRemoveMessage(*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=uwL0PCWin95IPXGetMessage();
|
|
/* 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 */
|
|
|
|
if(eL0PCWin95IPXRemoveMessage(uwChannel, &pToBeCast)!=NetLib_E_es_NoError) { /* normally this call produces no error */
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_IPX,"ReadData(): RemoveMessage() should not reach 1");
|
|
#endif /* NET_USE_DEBUG */
|
|
}
|
|
}
|
|
|
|
uwChannel=(tduwNetChannel)pToBeCast;
|
|
/* we retrieved a channel number, now mark the channel as readable */
|
|
|
|
gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsReadable=1;
|
|
|
|
/* and retrieve the actual message from this channel*/
|
|
|
|
if(eL0PCWin95IPXRemoveMessage(uwChannel, ppData)==NetLib_E_es_FIFOIsEmpty) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_IPX,"ReadData(): RemoveMessage() should not reach 2");
|
|
#endif /* NET_USE_DEBUG */
|
|
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;
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISISI(Net_C_Debug_IPX,"ReadData1 channel",uwChannel,
|
|
"msg type",((tdstNetMessage*)(*ppData))->eMessageType,
|
|
"size",((tdstNetMessage*)(*ppData))->uwMessageSizeInBytes);
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
return NetLib_E_es_NoError; /* no error */
|
|
}
|
|
|
|
/* the channel is not a broadcast channel */
|
|
|
|
/* is there already a message in the incoming queue ? */
|
|
|
|
if(eL0PCWin95IPXRemoveMessage(*p_uwChannel, ppData)==NetLib_E_es_NoError) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISISI(Net_C_Debug_IPX,"ReadData2 channel",*p_uwChannel,
|
|
"msg type",((tdstNetMessage*)(*ppData))->eMessageType,
|
|
"size",((tdstNetMessage*)(*ppData))->uwMessageSizeInBytes);
|
|
#endif /* NET_USE_DEBUG */
|
|
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=uwL0PCWin95IPXGetMessage();
|
|
/* 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(eL0PCWin95IPXRemoveMessage(uwChannel, ppData)==NetLib_E_es_FIFOIsEmpty) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_IPX,"ReadData(): RemoveMessage() should not reach 3");
|
|
#endif /* NET_USE_DEBUG */
|
|
return NetLib_E_es_ShouldNotReach; /* paranoid: there should be at least one message in the channel */
|
|
}
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISISI(Net_C_Debug_IPX,"ReadData3 channel",uwChannel,
|
|
"msg type",((tdstNetMessage*)(*ppData))->eMessageType,
|
|
"size",((tdstNetMessage*)(*ppData))->uwMessageSizeInBytes);
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
return NetLib_E_es_NoError; /* no error */
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXSendData
|
|
*
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: uwChannel, channel to send the message into.
|
|
* pData, pointer on the block to send
|
|
*
|
|
* Output: an error condition.
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log: Flot control.
|
|
*
|
|
* Date: 07/04/97 Author: David FOURNIER
|
|
*
|
|
*****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXSendData(tduwNetChannel uwChannel, tdpPointer pData)
|
|
{
|
|
unsigned long ulBytestoSend;
|
|
unsigned long ulBytesSent;
|
|
|
|
/* verify the validity of the Channel */
|
|
|
|
if(uwChannel>=C_ucL0MaxNumberOfIPXChannels)
|
|
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsSlotInUse)
|
|
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsReadable)
|
|
/* is it worth a new error code ? */
|
|
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
|
|
|
if (gs_iNbSendByNetEngine++>=5) return NetLib_E_es_BufferIsFull; /* Flot control. */
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISISI(Net_C_Debug_IPX,"SendData channel",uwChannel,
|
|
"msg type",((tdstNetMessage*)pData)->eMessageType,
|
|
"size",((tdstNetMessage*)pData)->uwMessageSizeInBytes);
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
ulBytestoSend=((tdstNetMessage *) pData)->uwMessageSizeInBytes + sizeof(tdstNetMessage);
|
|
|
|
/* send the message */
|
|
|
|
if((ulBytesSent=gs_p_stIPXWinSocDesc->m_pfn_i_sendto(gs_iSD, pData, ulBytestoSend, 0,
|
|
(struct sockaddr *)&gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwChannel].stRemoteAddr))==SOCKET_ERROR)
|
|
{
|
|
ulBytesSent=gs_p_stIPXWinSocDesc->m_pfn_i_WSAGetLastError();
|
|
|
|
if(ulBytesSent==WSAEWOULDBLOCK) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugS(Net_C_Debug_IPX,"SendData(): sendto(): would block");
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
return NetLib_E_es_EmissionInProgress;
|
|
}
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSI(Net_C_Debug_IPX,"SendData(): sendto(): error",ulBytesSent);
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
if(ulBytesSent==WSAENETDOWN)
|
|
return NetLib_E_es_SendSocketFailure;
|
|
return NetLib_E_es_UnknownError;
|
|
}
|
|
|
|
if(ulBytesSent!=ulBytestoSend) {
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSISI(Net_C_Debug_IPX,"SendData(): msg partly sent. Bytes Sent", ulBytesSent,"BytestoSend",ulBytestoSend);
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
return NetLib_E_es_MessagePartlySent;
|
|
}
|
|
/* free the message buffer */
|
|
vFree(pData);
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugSIS(Net_C_Debug_IPX,"SendData()", uwChannel," msg correctly sent");
|
|
#endif /* NET_USE_DEBUG */
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXQueryChannelStatus
|
|
*
|
|
* returns the current status of the channel
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: uwChannel, channel to query
|
|
*
|
|
* Output: an error condition.
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXQueryChannelStatus(tduwNetChannel uwChannel)
|
|
{
|
|
/* verify the validity of the Channel */
|
|
|
|
if(uwChannel>=C_ucL0MaxNumberOfIPXChannels)
|
|
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[uwChannel].ubf1IsSlotInUse)
|
|
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
|
|
|
if(!gs_a_stL0PCWin95IPXChannels[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: eL0PCWin95IPXInit
|
|
*
|
|
* initializes the global socket descriptor used for all channels
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: port number to use
|
|
*
|
|
* Output: none
|
|
*
|
|
* Remark: Due to a bug in wsock32.dll for win95, we can't enumerate the IPX
|
|
* addresses of the host, so we bind the socket to our port and then read the
|
|
* address at which the system has bound our socket. This might not be reliable.
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log: separating initialisation of socket library
|
|
* from initialisation of global socket. Use a temporary socket
|
|
* in order to obtain the adress of the machine
|
|
*
|
|
* Date: May,7 1996 Author: Albert Pais
|
|
*
|
|
****************************************************************************/
|
|
|
|
NetLib_tdeErrorStatus eL0PCWin95IPXInit(unsigned short uwPortNumber)
|
|
{
|
|
SOCKADDR_IPX my_name; /* the address to bind the socket to */
|
|
int iAddrLength; /* length of the address structure */
|
|
int iTempSock;
|
|
|
|
/* open an IPX datagram socket */
|
|
iTempSock = gs_p_stIPXWinSocDesc->m_pfn_ui_socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
|
|
if(iTempSock==INVALID_SOCKET)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
|
|
/* bind our socket to our specific port */
|
|
my_name.sa_family = AF_IPX;
|
|
my_name.sa_socket = gs_p_stIPXWinSocDesc->m_pfn_uw_htons(uwPortNumber); /* htons() is intended for IP socket numbers, but should work with IPX socket numbers as well */
|
|
|
|
/* clear the address fields */
|
|
memset(my_name.sa_netnum, 0, sizeof my_name.sa_netnum);
|
|
memset(my_name.sa_nodenum, 0, sizeof my_name.sa_nodenum);
|
|
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_bind(iTempSock, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
/* now that the socket is bound, read our address and store it in our global variable */
|
|
memset(&gs_stMyAddress, 0, sizeof (SOCKADDR_IPX));
|
|
iAddrLength=sizeof (SOCKADDR_IPX);
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_getsockname(iTempSock, (struct sockaddr *)&gs_stMyAddress, &iAddrLength)==SOCKET_ERROR)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(iTempSock)==SOCKET_ERROR)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
|
|
gs_bL0PCWin95IPXInitState = gs_bL0PCWin95IPXInitState |(char)0x02;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: eL0PCWin95IPXAddPort
|
|
*
|
|
* Creates a new port
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Input: New port number
|
|
*
|
|
* Output: a NetLib_tdeErrorStatus
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Albert PAIS
|
|
* Comment : code from old function eLevel0InitWin95PCIPX developped
|
|
* by Christophe ROGUET
|
|
****************************************************************************/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95IPXAddPort(unsigned short uwPortNumber)
|
|
{
|
|
SOCKADDR_IPX my_name; /* the address to bind the socket to */
|
|
int iOpt; /* parameter used for socket option setting */
|
|
unsigned long ulOpt; /* parameter used for socket option setting */
|
|
int iErrorCode;
|
|
|
|
/* is the system properly initialized ? */
|
|
|
|
if(!(gs_bL0PCWin95IPXInitState&0x01))
|
|
return NetLib_E_es_ProtocolNotInitialized;
|
|
|
|
if(!(gs_bL0PCWin95IPXInitState&0x02))
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
|
|
/* if a previous socket is opened, clear it :*/
|
|
if(gs_iSD!=INVALID_SOCKET)
|
|
{
|
|
vL0PCWin95IPXClosePort(gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_socket);
|
|
}
|
|
|
|
/* open an IPX datagram socket */
|
|
gs_iSD=gs_p_stIPXWinSocDesc->m_pfn_ui_socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
|
|
if(gs_iSD==INVALID_SOCKET)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
|
|
/* bind our socket to our specific port */
|
|
my_name.sa_family = AF_IPX;
|
|
my_name.sa_socket = gs_p_stIPXWinSocDesc->m_pfn_uw_htons(uwPortNumber); /* htons() is intended for IP socket numbers, but should work with IPX socket numbers as well */
|
|
|
|
/* clear the address fields */
|
|
memset(my_name.sa_netnum, 0, sizeof my_name.sa_netnum);
|
|
memset(my_name.sa_nodenum, 0, sizeof my_name.sa_nodenum);
|
|
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_bind(gs_iSD, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
|
{
|
|
long lerrorcode;
|
|
lerrorcode=gs_p_stIPXWinSocDesc->m_pfn_i_WSAGetLastError();
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
}
|
|
|
|
/* enable broadcast sends */
|
|
|
|
iOpt=~0;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_setsockopt(gs_iSD, SOL_SOCKET, SO_BROADCAST, (char *)&iOpt, sizeof(iOpt))<0)
|
|
{
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
}
|
|
|
|
/* set non blocking mode on this socket */
|
|
|
|
ulOpt=(unsigned long)~0L;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_ioctlsocket(gs_iSD, FIONBIO, &ulOpt)==SOCKET_ERROR) {
|
|
iErrorCode=gs_p_stIPXWinSocDesc->m_pfn_i_WSAGetLastError();
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
}
|
|
|
|
/* set the size of send and receive buffers */
|
|
|
|
iOpt=1500;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_setsockopt(gs_iSD, SOL_SOCKET, SO_SNDBUF, (char *)&iOpt, sizeof(iOpt))<0)
|
|
{
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
}
|
|
|
|
iOpt=1500;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_setsockopt(gs_iSD, SOL_SOCKET, SO_RCVBUF, (char *)&iOpt, sizeof(iOpt))<0)
|
|
{
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
}
|
|
|
|
/* initialize channel 0 as broadcast channel */
|
|
/* the broadcast channel is always in use */
|
|
gs_a_stL0PCWin95IPXChannels[0].ubf1IsSlotInUse = 1;
|
|
/* this is a channel usable to send only broadcast messages */
|
|
gs_a_stL0PCWin95IPXChannels[0].ubf1IsBroadcast = 1;
|
|
gs_a_stL0PCWin95IPXChannels[0].ubf1IsReadable = 1;
|
|
|
|
/* set the destination adress : broadcast address */
|
|
gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_family = AF_IPX;
|
|
memset(gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_netnum, 0x00,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_netnum);
|
|
memset(gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_nodenum, 0xFF,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_nodenum);
|
|
gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_socket = gs_p_stIPXWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
|
|
|
/**/
|
|
gs_a_stL0PCWin95IPXChannels[0].ucHead = gs_a_stL0PCWin95IPXChannels[0].ucTail = 0;
|
|
|
|
/* the channel is working properly */
|
|
gs_a_stL0PCWin95IPXChannels[0].eChannelStatus = E_ts_OK;
|
|
|
|
gs_bL0PCWin95IPXInitState = gs_bL0PCWin95IPXInitState | (char)0x04;
|
|
return NetLib_E_es_NoError;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : vL0PCWin95IPXCloseProtocol(void)
|
|
ipx-Level 0 closing function
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input :
|
|
none
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output :
|
|
none
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : May 6,96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
void vL0PCWin95IPXCloseProtocol(void)
|
|
{
|
|
if(gs_bL0PCWin95IPXInitState!=0) {
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
gs_bL0PCWin95IPXInitState = 0x00;
|
|
|
|
eNetRestoreWinSock();
|
|
gs_cIsWinsocDescInit=0;
|
|
|
|
vLevel1RemoveProtocol(E_Net_pr_Windows95IPXProtocol);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Description: eL0PCWin95IPXEngine
|
|
*****************************************************************************
|
|
* Input: none
|
|
* Output: none
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: David FOURNIER
|
|
****************************************************************************/
|
|
void vL0PCWin95IPXEngine(void)
|
|
{
|
|
gs_iNbSendByNetEngine=0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Description: vL0PCWin95IPXOpenProtocol
|
|
*
|
|
* 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
|
|
* uwPortNumber, port number to bind the socket to
|
|
*
|
|
* Output: none
|
|
*
|
|
*****************************************************************************
|
|
* Creation Date: May 3, 1996 Author: Christophe ROGUET
|
|
*****************************************************************************
|
|
*
|
|
* Modification log:
|
|
*
|
|
* Date: Author:
|
|
*
|
|
****************************************************************************/
|
|
void _NET_CALLING_CONV_ vL0PCWin95IPXOpenProtocol(void)
|
|
{
|
|
tduwNetChannel uwChannelToInit;
|
|
tdstNetProtocolInterface *p_stProtocolInterface;
|
|
|
|
|
|
#if defined(NET_USE_DEBUG)
|
|
vDebugClear(Net_C_Debug_IPX);
|
|
vDebugS(Net_C_Debug_IPX,"Netlib - Level 0 - IPX WIN95 : Log file");
|
|
#endif /* NET_USE_DEBUG */
|
|
|
|
gs_bL0PCWin95IPXInitState = 0x00;
|
|
|
|
if(!gs_cIsWinsocDescInit) {
|
|
if(eNetGetWinSockDesc(&gs_p_stIPXWinSocDesc)!=NetLib_E_es_NoError)
|
|
return ;
|
|
gs_cIsWinsocDescInit=~0;
|
|
}
|
|
|
|
/* initialize socket library and own adress*/
|
|
if(eL0PCWin95IPXInit(1500)!=NetLib_E_es_NoError)
|
|
return;
|
|
|
|
p_stProtocolInterface=pstLevel1AddProtocol();
|
|
|
|
/* logical identification of the protocol */
|
|
p_stProtocolInterface->eProtocol = E_Net_pr_Windows95IPXProtocol;
|
|
|
|
/* setup the function pointers */
|
|
p_stProtocolInterface->fn_uwStartChannelScan = uwL0PCWin95IPXStartChannelScan;
|
|
p_stProtocolInterface->fn_uwStartBroadcastChannelScan= uwL0PCWin95IPXStartBroadcastChannelScan;
|
|
p_stProtocolInterface->fn_uwNextChannel= uwL0PCWin95IPXNextChannel;
|
|
p_stProtocolInterface->fn_uwNextBroadcastChannel= uwL0PCWin95IPXNextBroadcastChannel;
|
|
p_stProtocolInterface->fn_eReadData= eL0PCWin95IPXReadData;
|
|
p_stProtocolInterface->fn_eSendData= eL0PCWin95IPXSendData;
|
|
p_stProtocolInterface->fn_eQueryChannelStatus= eL0PCWin95IPXQueryChannelStatus;
|
|
p_stProtocolInterface->fn_vLevel0NetEngine = vL0PCWin95IPXEngine;
|
|
p_stProtocolInterface->fn_vCloseChannel = vL0PCWin95IPXCloseChannel;
|
|
p_stProtocolInterface->fn_vLevel0CloseProtocol = vL0PCWin95IPXCloseProtocol;
|
|
p_stProtocolInterface->eIsInternet = 0;
|
|
|
|
/* initialize all other slots as unused channels */
|
|
|
|
for (uwChannelToInit = 0; uwChannelToInit < C_ucL0MaxNumberOfIPXChannels; uwChannelToInit ++)
|
|
{
|
|
/* the channel is not used yet */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].ubf1IsSlotInUse = 0;
|
|
/* this is a channel usable to send private messages */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].ubf1IsBroadcast = 0;
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].ubf1IsReadable = 0;
|
|
|
|
/* initialize the destination address: */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_family=AF_IPX;
|
|
memset(gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_nodenum, 0x00,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_nodenum);
|
|
memset(gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_netnum, 0x00,
|
|
sizeof gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_netnum);
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].stRemoteAddr.sa_socket=0;
|
|
|
|
/* the channel is working properly */
|
|
gs_a_stL0PCWin95IPXChannels[uwChannelToInit].eChannelStatus = E_ts_OK;
|
|
}
|
|
|
|
gs_iSD = INVALID_SOCKET;
|
|
gs_bL0PCWin95IPXInitState = gs_bL0PCWin95IPXInitState | (char)0x01;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : eL0PCWin95IPXIsProtocolSet
|
|
Check if the protocol is correctly initialize or not
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input :
|
|
none
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output :
|
|
NetLib_E_es_ProtocolNotInitialized : the vLevel0SetupWin95PCIPXInterface has not
|
|
been called yet or it has failed, the application should call the level 2
|
|
eInitializeGlobalData function.
|
|
NetLib_E_es_InitialisationSocketError : the eLevel0InitWin95PCIPX function has not been
|
|
called yet or it has failed, the application should call the level 2
|
|
eInitializeGlobalData function
|
|
NetLib_E_es_NoPortSelected : the eL0PCWin95IPXAddPort 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_ eL0PCWin95IPXIsProtocolSet(void)
|
|
{
|
|
if(!(gs_bL0PCWin95IPXInitState&0x01))
|
|
return NetLib_E_es_ProtocolNotInitialized;
|
|
if(!(gs_bL0PCWin95IPXInitState&0x02))
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
if(!(gs_bL0PCWin95IPXInitState&0x04))
|
|
return NetLib_E_es_NoPortSelected;
|
|
return NetLib_E_es_True;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : vL0PCWin95IPXClosePort
|
|
Close the socket bound with the specified port number
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Input :
|
|
The port number to close
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Output :
|
|
None
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : June 24,96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
void _NET_CALLING_CONV_ vL0PCWin95IPXClosePort(unsigned short uwOldPort)
|
|
{
|
|
unsigned short uwCurrentChannel;
|
|
if
|
|
(
|
|
(gs_bL0PCWin95IPXInitState&0x04)&&
|
|
(uwOldPort == gs_p_stIPXWinSocDesc->m_pfn_uw_ntohs(gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_socket))
|
|
)
|
|
{
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(gs_iSD);
|
|
gs_iSD = INVALID_SOCKET;
|
|
/* Closes the channel :*/
|
|
for(uwCurrentChannel = 0;uwCurrentChannel<C_ucL0MaxNumberOfIPXChannels;uwCurrentChannel++)
|
|
{
|
|
eL0PCWin95IPXCloseAndResetChannel(uwCurrentChannel);
|
|
}
|
|
|
|
gs_bL0PCWin95IPXInitState = gs_bL0PCWin95IPXInitState & (char)~0x04;
|
|
}
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : eL0PCWin95IPXIsPortAvailable
|
|
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_PortAlreadyUsed if the port is already in use
|
|
An error code otherwise
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Creation date : June 24,96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95IPXIsPortAvailable(unsigned short uwPortNumber)
|
|
{
|
|
SOCKADDR_IPX my_name; /* the address to bind the socket to */
|
|
int iOpt; /* parameter used for socket option setting */
|
|
int iTempSock; /*temporary socket*/
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
/* bind to the DLL if necessary */
|
|
if(!gs_cIsWinsocDescInit) {
|
|
if((eErrorReturned=eNetGetWinSockDesc(&gs_p_stIPXWinSocDesc))!=NetLib_E_es_NoError)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
gs_cIsWinsocDescInit=~0;
|
|
}
|
|
|
|
/* open an IPX datagram socket */
|
|
iTempSock=gs_p_stIPXWinSocDesc->m_pfn_ui_socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
|
|
|
|
if(iTempSock==INVALID_SOCKET)
|
|
return NetLib_E_es_False;
|
|
|
|
/* bind our socket to our specific port */
|
|
my_name.sa_family = AF_IPX;
|
|
my_name.sa_socket = gs_p_stIPXWinSocDesc->m_pfn_uw_htons(uwPortNumber); /* htons() is intended for IP socket numbers, but should work with IPX socket numbers as well */
|
|
|
|
/* clear the address fields */
|
|
memset(my_name.sa_netnum, 0, sizeof my_name.sa_netnum);
|
|
memset(my_name.sa_nodenum, 0, sizeof my_name.sa_nodenum);
|
|
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_bind(iTempSock, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
|
{
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_WSAGetLastError()==WSAEADDRINUSE)
|
|
eErrorReturned = NetLib_E_es_PortAlreadyUsed;
|
|
else
|
|
eErrorReturned = NetLib_E_es_False;
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
|
return eErrorReturned;
|
|
}
|
|
|
|
iOpt=~0;
|
|
if(gs_p_stIPXWinSocDesc->m_pfn_i_setsockopt(iTempSock, SOL_SOCKET, SO_BROADCAST, (char *)&iOpt, sizeof(iOpt))<0)
|
|
{
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
|
return NetLib_E_es_False;
|
|
}
|
|
/* if we came here, it means that there is no problem with this port number*/
|
|
gs_p_stIPXWinSocDesc->m_pfn_i_closesocket(iTempSock);
|
|
return NetLib_E_es_True;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : eL0PCWin95IPXIsProtocolAvailable
|
|
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 24,96
|
|
Author : Albert Pais
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
*/
|
|
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95IPXIsProtocolAvailable(void)
|
|
{
|
|
unsigned short uwPortNumberTest;
|
|
NetLib_tdeErrorStatus eErrorReturned;
|
|
|
|
/* bind to the DLL if necessary */
|
|
if(!gs_cIsWinsocDescInit) {
|
|
if((eErrorReturned=eNetGetWinSockDesc(&gs_p_stIPXWinSocDesc))!=NetLib_E_es_NoError)
|
|
return NetLib_E_es_InitialisationSocketError;
|
|
gs_cIsWinsocDescInit=~0;
|
|
}
|
|
|
|
uwPortNumberTest = 1000;
|
|
while
|
|
(
|
|
((eErrorReturned = eL0PCWin95IPXIsPortAvailable(uwPortNumberTest))==NetLib_E_es_PortAlreadyUsed)&&
|
|
(uwPortNumberTest<1100)
|
|
)
|
|
uwPortNumberTest++;
|
|
return eErrorReturned;
|
|
}
|
|
|
|
/*
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
Description : eL0PCWin95IPXIsPortOpened
|
|
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_ eL0PCWin95IPXIsPortOpened(unsigned short uwPortNumber)
|
|
{
|
|
if(!(gs_bL0PCWin95IPXInitState&0x04))
|
|
return NetLib_E_es_NoPortSelected;
|
|
|
|
if(!(uwPortNumber == gs_p_stIPXWinSocDesc->m_pfn_uw_ntohs(gs_a_stL0PCWin95IPXChannels[0].stRemoteAddr.sa_socket)))
|
|
return NetLib_E_es_False;
|
|
|
|
return NetLib_E_es_True;
|
|
}
|