1952 lines
69 KiB
C
1952 lines
69 KiB
C
/*
|
||
* universal multiplayer library level 0 implementation file
|
||
* transport layer: TCP PC-windows 95
|
||
*/
|
||
|
||
/*
|
||
* Author: Christophe Roguet after Benoit GERMAIN
|
||
*
|
||
* Modification Date: 07/05/96 first draft
|
||
*
|
||
* 29/10/96 changed the connection process, removed the UDP socket
|
||
*/
|
||
|
||
#include "warnings.h"
|
||
#include "NetSock.h"
|
||
|
||
/*
|
||
* we need this one to fill the interface structure
|
||
* with pointers to the correct functions
|
||
*/
|
||
|
||
#include "Privl0TCP.h"
|
||
#include "PrivNetDef.h"
|
||
#include "L0GlDef.h"
|
||
#include "NetMemCo.h"
|
||
#include "NetEnd.h"
|
||
#include <NET\Netdebug.h>
|
||
|
||
/* size of socket send buffer */
|
||
#define C_iSendBufferSize 666
|
||
|
||
/* array of descriptors to access a physical channel. */
|
||
static tdstL0PCWin95TCPChannel gs_a_stL0PCWin95TCPChannels[C_ucL0MaxNumberOfTCPChannels];
|
||
|
||
/* 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 to listen on our TCP port */
|
||
static SOCKET gs_uiListenSD;
|
||
|
||
static char gs_bL0PCWin95TCPInitState;
|
||
|
||
static tdstWinSockFunc *gs_p_stTCPWinSocDesc;
|
||
static char gs_cIsWinsocDescInit = 0;
|
||
|
||
#define DLL_FD_ISSET(fd, set) ((gs_p_stTCPWinSocDesc->m_pfn_i_WSAFDIsSet)((SOCKET)(fd), (fd_set *)(set)))
|
||
|
||
/* static functions */
|
||
|
||
static tduwNetChannel uwL0PCWin95TCPOpenChannel(SOCKET);
|
||
static void vL0PCWin95TCPCloseChannel(tduwNetChannel);
|
||
static NetLib_tdeErrorStatus eL0PCWin95TCPConfigureSocket(SOCKET);
|
||
|
||
/*****************************************************************************/
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPGetChannel
|
||
*
|
||
* 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 uwL0PCWin95TCPGetChannel(struct sockaddr_in *Key)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
for(uwCurrentChannel=0; uwCurrentChannel<C_ucL0MaxNumberOfTCPChannels; uwCurrentChannel++)
|
||
if(
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse==1
|
||
&& !gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsBroadcast
|
||
&& gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].stRemoteAddr.sin_addr.s_addr==Key->sin_addr.s_addr
|
||
)
|
||
return uwCurrentChannel;
|
||
|
||
return C_uwNetInvalidChannel; /* Error invalid channel ?*/
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPOpenChannel
|
||
*
|
||
* 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: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
static tduwNetChannel uwL0PCWin95TCPOpenChannel(SOCKET uiSD)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the channel table until we find an unused slot */
|
||
for(
|
||
uwCurrentChannel=0;
|
||
uwCurrentChannel<C_ucL0MaxNumberOfTCPChannels;
|
||
uwCurrentChannel++)
|
||
if(gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse == 0)
|
||
{
|
||
/* set the use mark */
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse=1;
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsBroadcast=0;
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsReconnect=0;
|
||
/* set the socket descriptor for this channel */
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].uiSD=uiSD;
|
||
/* the channel isn't connected */
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsConnected=0;
|
||
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/* there are no free channels */
|
||
return C_uwNetInvalidChannel;/* Error invalid channel */
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: vL0PCWin95TCPCloseChannel
|
||
*
|
||
* 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 vL0PCWin95TCPCloseChannel(tduwNetChannel uwChannel)
|
||
{
|
||
tdstL0PCWin95TCPChannel *pstChannel; /* Channel to read from */
|
||
|
||
if(uwChannel>=C_ucL0MaxNumberOfTCPChannels)
|
||
return /*NetLib_E_es_InvalidChannel*/; /* the channel does not exist in the table */
|
||
|
||
pstChannel=&gs_a_stL0PCWin95TCPChannels[uwChannel];
|
||
|
||
if(!pstChannel->ubf1IsSlotInUse)
|
||
return /*NetLib_E_es_ChannelUninitialized*/; /* the slot is not initialized for use */
|
||
|
||
/* clear the use mark */
|
||
pstChannel->ubf1IsSlotInUse=0;
|
||
/* release the socket descriptor for this channel */
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(pstChannel->uiSD);
|
||
/* set the remote address to none */
|
||
pstChannel->stRemoteAddr.sin_addr.s_addr=gs_p_stTCPWinSocDesc->m_pfn_ul_htonl(INADDR_NONE);
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPStartChannelScan
|
||
*
|
||
* 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 uwL0PCWin95TCPStartChannelScan(void)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the array of channel definitions */
|
||
uwCurrentChannel= C_ucL0MaxNumberOfTCPChannels-1;
|
||
while
|
||
(
|
||
(uwCurrentChannel!=C_uwNetInvalidChannel)&&
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse)
|
||
)
|
||
uwCurrentChannel--;
|
||
|
||
/* return its index value */
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPNextChannel
|
||
*
|
||
* 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 uwL0PCWin95TCPNextChannel(tduwNetChannel uwLastScannedChannel)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
/*
|
||
* scan the array of channel definitions, starting with the channel following
|
||
* the last channel returned
|
||
*/
|
||
uwCurrentChannel = (unsigned short)(uwLastScannedChannel-1);
|
||
while
|
||
(
|
||
(uwCurrentChannel!=C_uwNetInvalidChannel)&&
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse)
|
||
)
|
||
uwCurrentChannel--;
|
||
|
||
/* else no slot is in use */
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPStartBroadcastChannelScan
|
||
*
|
||
* 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 uwL0PCWin95TCPStartBroadcastChannelScan(void)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the array of channel definitions */
|
||
uwCurrentChannel= C_ucL0MaxNumberOfTCPChannels-1;
|
||
while
|
||
(
|
||
(uwCurrentChannel!=C_uwNetInvalidChannel)&&
|
||
((!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse)||
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsBroadcast))
|
||
)
|
||
uwCurrentChannel--;
|
||
|
||
/* else no slot is in use */
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPNextBroadcastChannel
|
||
*
|
||
* 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 uwL0PCWin95TCPNextBroadcastChannel(tduwNetChannel uwLastScannedChannel)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
uwCurrentChannel = (unsigned short)(uwLastScannedChannel-1);
|
||
while
|
||
(
|
||
(uwCurrentChannel!=C_uwNetInvalidChannel)&&
|
||
((!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse)||
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsBroadcast))
|
||
)
|
||
uwCurrentChannel--;
|
||
|
||
/* else no slot is in use */
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: uwL0PCWin95TCPGetNewReconnectChannel
|
||
*
|
||
* returns the identification number of a reconnect channel whose connection succeeded
|
||
* returns C_uwNetInvalidChannel if there is no such channel
|
||
*****************************************************************************
|
||
*
|
||
* Input: none
|
||
*
|
||
* Output: identification of the channel
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: January 24, 1997 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
tduwNetChannel uwL0PCWin95TCPGetNewReconnectChannel(void)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* scan the array of channel definitions */
|
||
uwCurrentChannel= C_ucL0MaxNumberOfTCPChannels-1;
|
||
while
|
||
(
|
||
(uwCurrentChannel!=C_uwNetInvalidChannel)&&
|
||
((!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse)||
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsReconnect) ||
|
||
(!gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsConnected))
|
||
)
|
||
uwCurrentChannel--;
|
||
|
||
if(uwCurrentChannel!=C_uwNetInvalidChannel)
|
||
/* if we found a new channel, unmark it */
|
||
gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsReconnect=0;
|
||
|
||
return uwCurrentChannel;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95TCPReadData
|
||
*
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* 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
|
||
* 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: 19/06/96 Author: Christophe ROGUET
|
||
* stopped using ioctlsocket(FIONREAD), which doesn't work as expected and was
|
||
* causing a bug when using the library over internet
|
||
* instead, I now use recv(MSG_PEEK) and test the return value
|
||
* Date: 25/10/96 Author: Christophe ROGUET
|
||
* test the recv() return value for 0 : detects graceful disconnections
|
||
* Date: 29/10/96 Author: Christophe ROGUET
|
||
* no UDP socket/broadcast channel any more
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPReadData(tduwNetChannel *p_uwChannel, tdpPointer *ppData)
|
||
{
|
||
tdstL0PCWin95TCPChannel *pstChannel; /* Channel to read from */
|
||
tdstNetMessage stMsgHeader; /* header of the incoming message */
|
||
unsigned long ulMsgSize; /* length of the incoming message (header included) */
|
||
int iErrorCode;
|
||
long lRecvdBytes;
|
||
|
||
/* verify the validity of the Channel */
|
||
|
||
if(*p_uwChannel>=C_ucL0MaxNumberOfTCPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
pstChannel=&gs_a_stL0PCWin95TCPChannels[*p_uwChannel];
|
||
|
||
if(!pstChannel->ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!pstChannel->ubf1IsConnected)
|
||
/* is it worth a new error code ? */
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
||
|
||
/* try to get a message from the socket */
|
||
/* if no message is being received, try to read a header from the socket and allocate a buffer for the message */
|
||
if(pstChannel->pMsg==C_pNull)
|
||
{
|
||
if((lRecvdBytes=gs_p_stTCPWinSocDesc->m_pfn_i_recv(pstChannel->uiSD,(char *)&stMsgHeader, sizeof stMsgHeader, MSG_PEEK))
|
||
==SOCKET_ERROR)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(iErrorCode==WSAEWOULDBLOCK)
|
||
return NetLib_E_es_FIFOIsEmpty; /* error: no message available */
|
||
if(iErrorCode==WSAECONNRESET)
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"connection reset",pstChannel->uiSD);
|
||
#endif /* NET_USE_DEBUG */
|
||
/* the connection has been broken */
|
||
vL0PCWin95TCPCloseChannel(*p_uwChannel);
|
||
return NetLib_E_es_ChannelIsInvalid;
|
||
}
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
if(lRecvdBytes==0)
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"graceful disconnection",pstChannel->uiSD);
|
||
#endif /* NET_USE_DEBUG */
|
||
/* the connection has been closed by the remote end */
|
||
vL0PCWin95TCPCloseChannel(*p_uwChannel);
|
||
return NetLib_E_es_ChannelIsInvalid;
|
||
}
|
||
|
||
if(lRecvdBytes!=sizeof stMsgHeader)
|
||
{
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"recv MSG_PEEK partiel",pstChannel->uiSD);
|
||
#endif /* NET_USE_DEBUG */
|
||
return NetLib_E_es_FIFOIsEmpty; /* error: header partially available */
|
||
}
|
||
|
||
/* if big/little endian differs, swap the header before anything else*/
|
||
if (stMsgHeader.uxHeadBigEndian!=NetLib_ucGetLittleBigEndian())
|
||
NetLib_eSwapLittleBigEndianMsgHeader(&stMsgHeader);
|
||
|
||
if
|
||
(
|
||
(M_uwCheckSumSlot((&stMsgHeader))!=M_uwProcessCheckSum((&stMsgHeader))) ||
|
||
(stMsgHeader.eMessageType >= E_Net_mt_LastSysMsg)||
|
||
(stMsgHeader.eMessageType <= E_Net_mt_InvalidMessage)
|
||
)
|
||
{
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSDump(Net_C_Debug_TCP,"type de message incorrect",&stMsgHeader, sizeof stMsgHeader);
|
||
#endif /* NET_USE_DEBUG */
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"Read data",pstChannel->uiSD);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tType de message",stMsgHeader.eMessageType);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tTaille du message",stMsgHeader.uwMessageSizeInBytes);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tExpediteur",stMsgHeader.uxSenderId);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tDestinataire",stMsgHeader.uxRecipientId);
|
||
#endif /* NET_USE_DEBUG */
|
||
/* compute the message length */
|
||
ulMsgSize=stMsgHeader.uwMessageSizeInBytes + sizeof(tdstNetMessage);
|
||
pstChannel->pMsg=pMalloc(ulMsgSize);
|
||
if(pstChannel->pMsg == C_pNull)
|
||
{
|
||
/* the pointer couldn't be allocated :*/
|
||
/* Purge the message : DOES THIS WORK FINE WITH A STREAM SOCKET ?????? */
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_recv(pstChannel->uiSD, NULL, ulMsgSize, 0)<0)
|
||
{
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"Read data Error allocation impossible",gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError());
|
||
#endif /* NET_USE_DEBUG */
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
/* Return en invalid channel :*/
|
||
return NetLib_E_es_NotEnoughMemory;
|
||
}
|
||
|
||
/* no bytes of this message have been read yet */
|
||
pstChannel->ulBytesRead=0;
|
||
pstChannel->ulBytesLeft=ulMsgSize;
|
||
}
|
||
else
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISI(Net_C_Debug_TCP,"\t\t recv() msg partiel bytes read",pstChannel->ulBytesRead,
|
||
"bytes left",pstChannel->ulBytesLeft);
|
||
#endif /* NET_USE_DEBUG */
|
||
}
|
||
|
||
if((lRecvdBytes=gs_p_stTCPWinSocDesc->m_pfn_i_recv(pstChannel->uiSD, &pstChannel->pMsg[pstChannel->ulBytesRead], pstChannel->ulBytesLeft, 0))<0)
|
||
{
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"Read data Error",gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError());
|
||
#endif /* NET_USE_DEBUG */
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(iErrorCode==WSAEWOULDBLOCK)
|
||
return NetLib_E_es_FIFOIsEmpty;
|
||
|
||
/* free the message buffer or not ??? */
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
if(pstChannel->ulBytesLeft!=0)
|
||
{
|
||
vDebugSISI(Net_C_Debug_TCP,"\t\t recv() msg partiel bytes read",pstChannel->ulBytesRead,
|
||
"bytes left",pstChannel->ulBytesLeft);
|
||
}
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
pstChannel->ulBytesRead+=lRecvdBytes;
|
||
pstChannel->ulBytesLeft-=lRecvdBytes;
|
||
if(pstChannel->ulBytesLeft>0)
|
||
{ /* has the message been read in whole ??? */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISI(Net_C_Debug_TCP,"\t\t recv() msg partiel bytes read",pstChannel->ulBytesRead,
|
||
"bytes left",pstChannel->ulBytesLeft);
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
return NetLib_E_es_FIFOIsEmpty; /* error: no full message available yet */
|
||
}
|
||
/* return the message */
|
||
*ppData=pstChannel->pMsg;
|
||
pstChannel->pMsg=C_pNull;
|
||
return NetLib_E_es_NoError; /* no error */
|
||
}
|
||
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95TCPSendData
|
||
*
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* 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: October 29, 1996 Author: Christophe ROGUET
|
||
* no more UDP socket/broadcast channel
|
||
*****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPSendData(tduwNetChannel uwChannel, tdpPointer pData)
|
||
{
|
||
unsigned long ulBytestoSend;
|
||
unsigned long ulBytesSent;
|
||
int iErrorCode;
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"Send data",gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tType de message",((tdstNetMessage*)pData)->eMessageType);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tTaille du message",((tdstNetMessage*)pData)->uwMessageSizeInBytes);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tExpediteur",((tdstNetMessage*)pData)->uxSenderId);
|
||
vDebugSI(Net_C_Debug_TCP,"\t\tDestinataire",((tdstNetMessage*)pData)->uxRecipientId);
|
||
#endif /* NET_USE_DEBUG */
|
||
/* verify the validity of the Channel */
|
||
if(uwChannel>=C_ucL0MaxNumberOfTCPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected)
|
||
/* 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);
|
||
|
||
/* connected channel: write the data to the connected socket */
|
||
if((ulBytesSent=gs_p_stTCPWinSocDesc->m_pfn_i_send(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD, pData, ulBytestoSend, 0))==SOCKET_ERROR)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(iErrorCode==WSAECONNRESET)
|
||
{ /* the connection has been closed by the remote side */
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"Send data :connection reset");
|
||
#endif
|
||
vL0PCWin95TCPCloseChannel(uwChannel);
|
||
return NetLib_E_es_ChannelIsInvalid;
|
||
}
|
||
if(iErrorCode==WSAEWOULDBLOCK)
|
||
{ /* the system is blocking */
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"Send data :would block");
|
||
#endif
|
||
return NetLib_E_es_EmissionInProgress;
|
||
}
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"Send data :socket failure, error",iErrorCode);
|
||
#endif
|
||
return NetLib_E_es_SendSocketFailure;
|
||
}
|
||
|
||
if(ulBytesSent!=ulBytestoSend)
|
||
{
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISI(Net_C_Debug_TCP,"Send data :partly sent BytesSent",ulBytesSent,"BytestoSend", ulBytestoSend);
|
||
#endif
|
||
|
||
return NetLib_E_es_MessagePartlySent;
|
||
}
|
||
|
||
/* if the routine succeeded in sending the message, then it's its duty to free the associated cell */
|
||
vFree(pData);
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95TCPQueryChannelStatus
|
||
*
|
||
* 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: October 29, 1996 Author: Christophe ROGUET
|
||
* the IsReadable flag does not exist any more
|
||
****************************************************************************/
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPQueryChannelStatus(tduwNetChannel uwChannel)
|
||
{
|
||
/* verify the validity of the Channel */
|
||
int iErrorCode;
|
||
int iParameterSize;
|
||
|
||
if(uwChannel>=C_ucL0MaxNumberOfTCPChannels)
|
||
return NetLib_E_es_InvalidChannel; /* the channel does not exist in the table */
|
||
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsSlotInUse)
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot is not initialized for use */
|
||
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected)
|
||
/* is it worth a new error code ? */
|
||
return NetLib_E_es_ChannelUninitialized; /* the slot should not be accessed yet */
|
||
|
||
/* what else to report ???? */
|
||
iParameterSize=sizeof iErrorCode;
|
||
|
||
if
|
||
(
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_getsockopt
|
||
(
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD,SOL_SOCKET,
|
||
SO_ERROR,(char *)&iErrorCode, &iParameterSize
|
||
)==SOCKET_ERROR
|
||
)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
if(iErrorCode!=0)
|
||
{
|
||
vDebugSISISI(Net_C_Debug_TCP,"QueryChannelStatus(): on channel",uwChannel,
|
||
"socket",gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD,"error",iErrorCode);
|
||
}
|
||
#endif
|
||
switch(iErrorCode)
|
||
{
|
||
case 0:
|
||
return NetLib_E_es_NoError;
|
||
|
||
case WSAECONNRESET: /* the connection has been closed by the remote end */
|
||
vL0PCWin95TCPCloseChannel(uwChannel);
|
||
return NetLib_E_es_ChannelIsInvalid;
|
||
|
||
default:
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
}
|
||
|
||
void vL0PCWin95TCPGSConnectEngine();
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : void eL0PCWin95TCPNetEngine(void)
|
||
The level 0 NetEngine function for TCP connections
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
None
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_NoError
|
||
An NetLib_tdeErrorStatus if an error occured
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 7, 96
|
||
Author : Christophe Roguet
|
||
|
||
modification log:
|
||
Date: October 25, 1996 Author: Christophe ROGUET
|
||
modified the exception detection
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
void vL0PCWin95TCPNetEngine(void)
|
||
{
|
||
static fd_set stReadFD, stWriteFD, stExceptionFD;
|
||
static struct timeval stTimeOut = { 0, 0 };
|
||
tduwNetChannel uwChannel; /* channel number attributed to new connections */
|
||
int iErrorCode;
|
||
SOCKET uiSD;
|
||
int iAddrLength; /* getpeername() needs a variable argument */
|
||
int iOptLen;
|
||
|
||
/* is there any connection operation waiting to be serviced ? */
|
||
/* build an fd-set to test: */
|
||
|
||
FD_ZERO(&stReadFD);
|
||
FD_ZERO(&stWriteFD);
|
||
FD_ZERO(&stExceptionFD);
|
||
|
||
/* ability to read on our listening socket */
|
||
FD_SET(gs_uiListenSD, &stReadFD);
|
||
|
||
/* ability to write on sockets for which a connect() call has been issued
|
||
and presence of an exception for the same sockets and the sockets already used
|
||
*/
|
||
|
||
for(uwChannel=0; uwChannel<C_ucL0MaxNumberOfTCPChannels; uwChannel++)
|
||
if(gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsSlotInUse) {
|
||
FD_SET(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD, &stExceptionFD);
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected)
|
||
FD_SET(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD, &stWriteFD);
|
||
}
|
||
|
||
/* call select() */
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_select(0, &stReadFD, &stWriteFD, &stExceptionFD, &stTimeOut)==SOCKET_ERROR)
|
||
{
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return; /* an error code ??? */
|
||
}
|
||
|
||
/* service connection requests: */
|
||
/* accept() on our listening socket until there are no more pending requests */
|
||
if(DLL_FD_ISSET(gs_uiListenSD, &stReadFD))
|
||
do
|
||
{
|
||
uiSD=gs_p_stTCPWinSocDesc->m_pfn_ui_accept(gs_uiListenSD,NULL,NULL);
|
||
if(uiSD==INVALID_SOCKET)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
/* no more pending connections ? */
|
||
if(iErrorCode==WSAEWOULDBLOCK)
|
||
break;
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(uiSD);
|
||
return; /* an error code ??? */
|
||
}
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"accept()",uiSD);
|
||
#endif
|
||
|
||
/* got a new connection from a remote player: allocate a new channel */
|
||
uwChannel=uwL0PCWin95TCPOpenChannel(uiSD);
|
||
if(uwChannel==C_uwNetInvalidChannel)
|
||
{
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(uiSD);
|
||
return; /* return an error code ? */
|
||
}
|
||
/* set the channel's connection flag */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected=1;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsBroadcast=1;
|
||
/* set the channel's remote address */
|
||
iAddrLength=sizeof(gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr);
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_getpeername(uiSD,
|
||
(struct sockaddr *)&gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr,
|
||
&iAddrLength)==SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
/* if an error occured, simply close the channel .... */
|
||
vL0PCWin95TCPCloseChannel(uwChannel);
|
||
}
|
||
|
||
} while(1);
|
||
|
||
/* service connection completion: */
|
||
/* mark the channels that are ready to be used */
|
||
/* re- attempt to connect the channels whose connection has failed */
|
||
for(uwChannel=0; uwChannel<C_ucL0MaxNumberOfTCPChannels; uwChannel++) {
|
||
if(gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsSlotInUse) {
|
||
if(!gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected) {
|
||
if(DLL_FD_ISSET(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD, &stWriteFD)) {
|
||
/* connection completion */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected=1;
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSIS(Net_C_Debug_TCP,"channel",uwChannel,"connected !");
|
||
#endif
|
||
}
|
||
}
|
||
if(DLL_FD_ISSET(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD, &stExceptionFD)) {
|
||
/* connection failure or connection reset */
|
||
/* retrieve the error code */
|
||
iOptLen = sizeof(iErrorCode);
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_getsockopt(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD,
|
||
SOL_SOCKET, SO_ERROR,
|
||
(char *)&iErrorCode, &iOptLen) == SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
continue;
|
||
}
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISISI(Net_C_Debug_TCP,"exception on channel",uwChannel,
|
||
"socket",gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD,"error",iErrorCode);
|
||
#endif
|
||
|
||
/* release the corresponding channel */
|
||
/* vL0PCWin95TCPCloseChannel(uwChannel); */
|
||
|
||
/* attempt a new connection */
|
||
/* connect the socket to the remote host */
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_connect(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD,
|
||
(struct sockaddr *)&gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr,
|
||
sizeof(gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr))==SOCKET_ERROR)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(iErrorCode!=WSAEWOULDBLOCK) {
|
||
vL0PCWin95TCPCloseChannel(uwChannel);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
vL0PCWin95TCPGSConnectEngine();
|
||
}
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: eL0PCWin95TCPInit
|
||
*
|
||
* loads the sockets dll
|
||
*
|
||
*****************************************************************************
|
||
*
|
||
* Input:
|
||
*
|
||
* Output: an error code
|
||
*
|
||
*****************************************************************************
|
||
* Creation Date: April 24, 1996 Author: Christophe ROGUET
|
||
*****************************************************************************
|
||
*
|
||
* Modification log:
|
||
*
|
||
* Date: Author:
|
||
*
|
||
****************************************************************************/
|
||
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPInit(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 */
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
|
||
/* find the host address, set the corresponding global variable */
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_gethostname(ac80HostName, sizeof ac80HostName)==SOCKET_ERROR)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
if((hp=gs_p_stTCPWinSocDesc->m_pfn_pst_gethostbyname(ac80HostName))==NULL)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
gs_stMyAddress=*(struct in_addr *)(hp->h_addr_list[0]);
|
||
gs_bL0PCWin95TCPInitState = gs_bL0PCWin95TCPInitState |(char)0x02;
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : tdeErrorStatus eL0PCWin95TCPAddPort
|
||
Add a new port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number to use
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPAddPort(unsigned short uwPortNumber)
|
||
{
|
||
return eL0PCWin95DirectTCPAddPort(uwPortNumber, INADDR_NONE);
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95TCPAddPortSym
|
||
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_ eL0PCWin95DirectTCPAddPortSym(unsigned short uwPortNumber, char *ConnectAddress)
|
||
{
|
||
unsigned long NumAddr;
|
||
|
||
/* WinSock doesn't have inet_aton(), we have to use inet_addr() */
|
||
|
||
if((NumAddr=gs_p_stTCPWinSocDesc->m_pfn_ul_inet_addr(ConnectAddress))!=INADDR_NONE)
|
||
return eL0PCWin95DirectTCPAddPort(uwPortNumber, gs_p_stTCPWinSocDesc->m_pfn_ul_ntohl(NumAddr));
|
||
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95TCPReconnect
|
||
try to connect to an address to have a direct route to a player
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number to use
|
||
remote IP address to send 'broadcast' messages to
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : January 24, 1997
|
||
Author : Christophe Roguet
|
||
|
||
modification log:
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPReconnect(unsigned short uwPortNumber, long lConnectAddress)
|
||
{
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* if we already have a channel for this target address, return */
|
||
for(uwCurrentChannel=0; uwCurrentChannel<C_ucL0MaxNumberOfTCPChannels; uwCurrentChannel++)
|
||
if( gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse==1
|
||
&& gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].stRemoteAddr.sin_addr.s_addr==
|
||
gs_p_stTCPWinSocDesc->m_pfn_ul_ntohl(lConnectAddress))
|
||
return NetLib_E_es_NoError;
|
||
|
||
/* initiate an asynchronous connection to the target address */
|
||
return eL0PCWin95TCPChannelConnect(uwPortNumber, lConnectAddress, eReconnect, (tduwNetChannel *)C_pNull);
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95DirectTCPAddPort
|
||
Add a new port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number to use
|
||
IP address of remote host to connect to
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date :June 6, 1996 Author: Christophe ROGUET
|
||
Modification log:
|
||
Date: Author:
|
||
October 29, 1996 Christophe Roguet
|
||
no more UDP socket at channel 0; attempts to connect to the eventual remote host
|
||
January 24, 1997 Christophe Roguet
|
||
connect part moved to a new function: eL0PCWin95TCPChannelConnect
|
||
February 14, 1997 Christophe Roguet
|
||
close the socket descriptor when an error occurs
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95DirectTCPAddPort(unsigned short uwPortNumber, long lConnectAddress)
|
||
{
|
||
struct sockaddr_in my_name; /* the address to bind the socket to */
|
||
NetLib_tdeErrorStatus eErrorCode;
|
||
|
||
if(uwPortNumber<IPPORT_RESERVED)
|
||
return NetLib_E_es_InvalidPortNumber;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
eL0PCWin95TCPInit();
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* open the IP stream socket used for listening */
|
||
|
||
gs_uiListenSD=gs_p_stTCPWinSocDesc->m_pfn_ui_socket(PF_INET, SOCK_STREAM, 0);
|
||
if(gs_uiListenSD==INVALID_SOCKET)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
if(eL0PCWin95TCPConfigureSocket(gs_uiListenSD)!=NetLib_E_es_NoError)
|
||
eErrorCode = NetLib_E_es_InitialisationSocketError;
|
||
else {
|
||
/* bind this socket to our specific port */
|
||
my_name.sin_family = AF_INET;
|
||
my_name.sin_port = gs_p_stTCPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
my_name.sin_addr = gs_stMyAddress;
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_bind(gs_uiListenSD, (struct sockaddr *)&my_name, sizeof my_name)<0)
|
||
eErrorCode = NetLib_E_es_InitialisationSocketError;
|
||
else {
|
||
/* start listening on this socket */
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_listen(gs_uiListenSD, 5)==SOCKET_ERROR) /* 5 is the maximum backlog supported by Windobe */
|
||
eErrorCode = NetLib_E_es_InitialisationSocketError;
|
||
else {
|
||
eErrorCode=NetLib_E_es_NoError;
|
||
|
||
/* if the remote address is a valid address, initiate handshake with the remote end */
|
||
|
||
if(lConnectAddress!=INADDR_NONE) {
|
||
eErrorCode=eL0PCWin95TCPChannelConnect(uwPortNumber, lConnectAddress, eFirstConnect, (tduwNetChannel *)C_pNull);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if(eErrorCode!=NetLib_E_es_NoError) {
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(gs_uiListenSD);
|
||
gs_uiListenSD=INVALID_SOCKET;
|
||
} else gs_bL0PCWin95TCPInitState = gs_bL0PCWin95TCPInitState |(char)0x04;
|
||
|
||
return eErrorCode;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : NetLib_tdeErrorStatus eL0PCWin95TCPChannelConnect
|
||
open a new channel and initiate an asynchronous connection to a target address
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
port number to use
|
||
IP address of remote host to connect to
|
||
connection mode : either eFirstConnect or eReconnect
|
||
puwChannel : (output parameter) pointer to a variable that can hold the chosen channel number; can be C_pNull
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
a NetLib_tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date :January 24, 1997 Author: Christophe ROGUET
|
||
(code moved from TCPDIrectConnect)
|
||
Modification log:
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPChannelConnect(unsigned short uwPortNumber, long ConnectAddress, int iMode, tduwNetChannel *puwChannel)
|
||
|
||
{
|
||
int iErrorCode;
|
||
tduwNetChannel uwChannel; /* channel number for the connection attempt */
|
||
SOCKET uiNewSD; /* socket descriptor for the connection attempt */
|
||
|
||
/* open a new socket */
|
||
uiNewSD=gs_p_stTCPWinSocDesc->m_pfn_ui_socket(PF_INET, SOCK_STREAM, 0);
|
||
if(uiNewSD==INVALID_SOCKET)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
/* set options on the socket */
|
||
if(eL0PCWin95TCPConfigureSocket(uiNewSD)!=NetLib_E_es_NoError) {
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(uiNewSD);
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
/* allocate a new channel */
|
||
if((uwChannel=uwL0PCWin95TCPOpenChannel(uiNewSD))==C_uwNetInvalidChannel) {
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(uiNewSD);
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
|
||
/* if the caller wants to know the new channel number, tell him */
|
||
|
||
if(puwChannel!=(tduwNetChannel *)C_pNull)
|
||
*puwChannel=uwChannel;
|
||
|
||
/* mark the channel as 'broadcast' */
|
||
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsBroadcast=1;
|
||
|
||
/* store the target address in the channel */
|
||
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr.sin_family = AF_INET;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr.sin_port=gs_p_stTCPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr.sin_addr.s_addr=gs_p_stTCPWinSocDesc->m_pfn_ul_ntohl(ConnectAddress);
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"connect()");
|
||
#endif
|
||
/* connect the socket to the remote host */
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_connect(uiNewSD,
|
||
(struct sockaddr *)&gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr,
|
||
sizeof(gs_a_stL0PCWin95TCPChannels[uwChannel].stRemoteAddr))==SOCKET_ERROR)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
if(iErrorCode!=WSAEWOULDBLOCK) {
|
||
vL0PCWin95TCPCloseChannel(uwChannel);
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
}
|
||
|
||
/* differenciate between first connection (which will eventually result in a new broadcast channel) */
|
||
/* and re-connection (which will eventually result in a new 'reconnection' channel) */
|
||
|
||
switch(iMode) {
|
||
case eFirstConnect:
|
||
/* this is a channel usable to send only broadcast messages */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsBroadcast = 1;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsReconnect = 0;
|
||
break;
|
||
|
||
case eReconnect:
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsBroadcast = 0;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsReconnect = 1;
|
||
break;
|
||
}
|
||
|
||
/* the channel is working properly */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannel].eChannelStatus = E_ts_OK;
|
||
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : vL0PCWin95TCPCloseProtocol(void)
|
||
TCP-Level 0 closing function
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : May 6,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
|
||
void vL0PCWin95TCPCloseProtocol(void)
|
||
{
|
||
tduwNetChannel uwChannel;
|
||
|
||
/* close the listening socket */
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(gs_uiListenSD);
|
||
/* close all channel sockets still open */
|
||
for(uwChannel=0; uwChannel<C_ucL0MaxNumberOfTCPChannels; uwChannel++)
|
||
if(gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsSlotInUse
|
||
&& gs_a_stL0PCWin95TCPChannels[uwChannel].ubf1IsConnected)
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(gs_a_stL0PCWin95TCPChannels[uwChannel].uiSD);
|
||
|
||
eNetRestoreWinSock();
|
||
gs_cIsWinsocDescInit=0;
|
||
|
||
vLevel1RemoveProtocol(E_Net_pr_Windows95TCPProtocol);
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"\n\nBye-bye\n");
|
||
#endif
|
||
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPIsProtocolSet
|
||
Check if the protocol is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
none
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_ProtocolNotInitialized : the vLevel0SetupWin95PCTCPInterface has not
|
||
been called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function.
|
||
NetLib_E_es_InitialisationSocketError : the eLevel0InitWin95PCTCP function has not been
|
||
called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function
|
||
NetLib_E_es_NoPortSelected : the eL0PCWin95TCPAddPort 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_ eL0PCWin95TCPIsProtocolSet(void)
|
||
{
|
||
if(!(gs_bL0PCWin95TCPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
if(!(gs_bL0PCWin95TCPInitState&0x04))
|
||
return NetLib_E_es_NoPortSelected;
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPIsPortAvailable
|
||
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 26,96
|
||
Author : Albert Pais
|
||
Modification log:
|
||
Date: October 29, 1996 Author: Christophe ROGUET
|
||
no more UDP socket
|
||
Date: October 29, 1996 Author: Christophe ROGUET
|
||
close the socket descriptor even if an error occurs before binding
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPIsPortAvailable(unsigned short uwPortNumber)
|
||
{
|
||
struct sockaddr_in my_name; /* the address to bind the socket to */
|
||
SOCKET uiTempSock;
|
||
NetLib_tdeErrorStatus tdeErrorCode;
|
||
|
||
/* bind to the DLL if necessary */
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if((tdeErrorCode=eNetGetWinSockDesc(&gs_p_stTCPWinSocDesc))!=NetLib_E_es_NoError)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
if(uwPortNumber<IPPORT_RESERVED) return NetLib_E_es_InvalidPortNumber;
|
||
|
||
/* try to bind a stream TCP socket on the port */
|
||
|
||
uiTempSock=gs_p_stTCPWinSocDesc->m_pfn_ui_socket(PF_INET, SOCK_STREAM, 0);
|
||
|
||
if(uiTempSock==INVALID_SOCKET)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
|
||
if(eL0PCWin95TCPConfigureSocket(uiTempSock)!=NetLib_E_es_NoError)
|
||
tdeErrorCode = NetLib_E_es_InitialisationSocketError;
|
||
else {
|
||
my_name.sin_family = AF_INET;
|
||
my_name.sin_port = gs_p_stTCPWinSocDesc->m_pfn_uw_htons(uwPortNumber);
|
||
my_name.sin_addr = gs_stMyAddress;
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_bind(uiTempSock, (struct sockaddr *)&my_name, sizeof(my_name))<0)
|
||
tdeErrorCode = NetLib_E_es_InitialisationSocketError;
|
||
|
||
tdeErrorCode = NetLib_E_es_True;
|
||
}
|
||
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(uiTempSock);
|
||
|
||
return tdeErrorCode;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPIsProtocolAvailable
|
||
Check if the protocol is avaible for use or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
None
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_True if the port is avaible
|
||
An error code otherwise
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 26,96
|
||
Author : Albert Pais
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPIsProtocolAvailable(void)
|
||
{
|
||
unsigned short uwPortNumberTest;
|
||
NetLib_tdeErrorStatus eErrorReturned;
|
||
|
||
/* bind to the DLL if necessary */
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if((eErrorReturned=eNetGetWinSockDesc(&gs_p_stTCPWinSocDesc))!=NetLib_E_es_NoError)
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
uwPortNumberTest = IPPORT_RESERVED+1000;
|
||
while
|
||
(
|
||
((eErrorReturned = eL0PCWin95TCPIsPortAvailable(uwPortNumberTest))==NetLib_E_es_PortAlreadyUsed)&&
|
||
(uwPortNumberTest<IPPORT_RESERVED+1100)
|
||
)
|
||
uwPortNumberTest++;
|
||
return eErrorReturned;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : vL0PCWin95TCPClosePort
|
||
Close the socket bound with the specified port number
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
The port number to close
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
None
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 26,96
|
||
Author : Albert Pais
|
||
Modification log:
|
||
Date: October 29, 1996 Author: Christophe ROGUET
|
||
no more UDP socket at channel 0; close all used channels as well
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
|
||
void _NET_CALLING_CONV_ vL0PCWin95TCPClosePort(unsigned short uwOldPort)
|
||
{
|
||
struct sockaddr_in ListenSockName; /* the address that the listen socket is bound to */
|
||
int iAddrLen;
|
||
int iErrorCode;
|
||
tduwNetChannel uwCurrentChannel;
|
||
|
||
/* first verify that this port is used ... */
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x04))
|
||
return;
|
||
|
||
iAddrLen=sizeof(ListenSockName);
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_getsockname(gs_uiListenSD, (struct sockaddr *)&ListenSockName, &iAddrLen)==SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return;
|
||
}
|
||
|
||
if(!(uwOldPort == gs_p_stTCPWinSocDesc->m_pfn_uw_ntohs(ListenSockName.sin_port)))
|
||
return;
|
||
|
||
/* close the socket used for listening */
|
||
gs_p_stTCPWinSocDesc->m_pfn_i_closesocket(gs_uiListenSD);
|
||
gs_uiListenSD = INVALID_SOCKET;
|
||
|
||
/* close all used channels */
|
||
|
||
for(uwCurrentChannel=0; uwCurrentChannel<C_ucL0MaxNumberOfTCPChannels; uwCurrentChannel++)
|
||
if(gs_a_stL0PCWin95TCPChannels[uwCurrentChannel].ubf1IsSlotInUse==1)
|
||
vL0PCWin95TCPCloseChannel(uwCurrentChannel);
|
||
|
||
gs_bL0PCWin95TCPInitState = gs_bL0PCWin95TCPInitState& (char)~0x04;
|
||
|
||
}
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPIsPortOpened
|
||
Returns wether the port is opened or not
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
A port
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
an tdeErrorStatus
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : June 27,96
|
||
Author : Albert Pais
|
||
Modification log:
|
||
|
||
Date: October 29, 1996 Author: Christophe ROGUET
|
||
test on the listen socket since the UDP socket doesn't exist any more
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus _NET_CALLING_CONV_ eL0PCWin95TCPIsPortOpened(unsigned short uwPortNumber)
|
||
{
|
||
struct sockaddr_in ListenSockName; /* the address that the listen socket is bound to */
|
||
int iAddrLen;
|
||
int iErrorCode;
|
||
|
||
/* test whether the listen socket is valid and has the right port number */
|
||
|
||
if(gs_uiListenSD==INVALID_SOCKET)
|
||
return NetLib_E_es_False;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x04))
|
||
return NetLib_E_es_NoPortSelected;
|
||
|
||
iAddrLen=sizeof(ListenSockName);
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_getsockname(gs_uiListenSD, (struct sockaddr *)&ListenSockName, &iAddrLen)==SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
if(!(uwPortNumber == gs_p_stTCPWinSocDesc->m_pfn_uw_ntohs(ListenSockName.sin_port)))
|
||
return NetLib_E_es_False;
|
||
return NetLib_E_es_True;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPGetMyAddress
|
||
copy into a character string the numerical IP address which we are bound to
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
array of characters to store an alphanumeric name into
|
||
size of the array
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_ProtocolNotInitialized : the vLevel0SetupWin95PCTCPInterface has not
|
||
been called yet or it has failed, the application should call the level 2
|
||
eInitializeGlobalData function.
|
||
NetLib_E_es_InitialisationSocketError : the eLevel0InitWin95PCTCP 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 _NET_CALLING_CONV_ eL0PCWin95TCPGetMyAddress(char *pcReturnStringAddress, unsigned short Size)
|
||
{
|
||
char LocalStringAddress[80];
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
eL0PCWin95TCPInit();
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError ;
|
||
|
||
/* translate the numerical address into an alphabetic string */
|
||
|
||
strncpy(LocalStringAddress, gs_p_stTCPWinSocDesc->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;
|
||
}
|
||
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPGetPortAndAddress(unsigned short *p_uwPort, unsigned long *p_ulAddress)
|
||
{
|
||
struct sockaddr_in ListenSockName; /* the address that the listen socket is bound to */
|
||
int iAddrLen;
|
||
int iErrorCode;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x01))
|
||
return NetLib_E_es_ProtocolNotInitialized;
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
eL0PCWin95TCPInit();
|
||
|
||
if(!(gs_bL0PCWin95TCPInitState&0x02))
|
||
return NetLib_E_es_InitialisationSocketError ;
|
||
|
||
/* copy the requested information into the return parameters */
|
||
|
||
/* get the port number from the listen socket */
|
||
|
||
if(gs_uiListenSD==INVALID_SOCKET) {
|
||
*p_uwPort=0; /* if we are not bound, return 0 as port number */
|
||
} else {
|
||
iAddrLen=sizeof(ListenSockName);
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_getsockname(gs_uiListenSD, (struct sockaddr *)&ListenSockName, &iAddrLen)==SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_UnknownError;
|
||
}
|
||
|
||
*p_uwPort=gs_p_stTCPWinSocDesc->m_pfn_uw_ntohs(ListenSockName.sin_port);
|
||
}
|
||
|
||
/* get the IP address from the global variable */
|
||
*p_ulAddress=gs_p_stTCPWinSocDesc->m_pfn_ul_ntohl(gs_stMyAddress.s_addr);
|
||
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
/*
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Description : eL0PCWin95TCPConfigureSocket
|
||
set appropriate options on a socket
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Input :
|
||
uiSD the socket descriptor of the socket to configure
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Output :
|
||
NetLib_E_es_InitialisationSocketError if a system call returned an error
|
||
NetLib_E_es_NoError if the socket could be properly configured
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
Creation date : October 29,96
|
||
Author : Christophe Roguet
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
*/
|
||
NetLib_tdeErrorStatus eL0PCWin95TCPConfigureSocket(SOCKET uiSD)
|
||
|
||
{
|
||
int iOpt; /* parameter used for socket option setting via setsockopt() */
|
||
int iOptLen; /* length of option retrieved with getsockopt() */
|
||
unsigned long ulOpt; /* parameter used for socket option setting via ioctlsocket() */
|
||
int iErrorCode;
|
||
|
||
/* set non blocking mode on this socket */
|
||
ulOpt=(unsigned long)~0L;
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_ioctlsocket(uiSD, FIONBIO, &ulOpt)==SOCKET_ERROR) {
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
|
||
/* disable the Nagle algorithm on this socket */
|
||
/* (in order not to be blocked because a small message won't go out) */
|
||
|
||
iOpt=~0;
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_setsockopt(uiSD, IPPROTO_TCP, TCP_NODELAY, (char *)&iOpt, sizeof(iOpt))<0)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
|
||
/* set the system buffer size for send operations */
|
||
/* if it is too big, it will cause a lag because lots of messages will be stored in this buffer */
|
||
|
||
iOpt=C_iSendBufferSize;
|
||
iOptLen=sizeof(iOpt);
|
||
|
||
if(gs_p_stTCPWinSocDesc->m_pfn_i_setsockopt(uiSD, SOL_SOCKET, SO_SNDBUF, (char *)&iOpt, iOptLen)<0)
|
||
{
|
||
iErrorCode=gs_p_stTCPWinSocDesc->m_pfn_i_WSAGetLastError();
|
||
return NetLib_E_es_InitialisationSocketError;
|
||
}
|
||
return NetLib_E_es_NoError;
|
||
}
|
||
|
||
|
||
/*****************************************************************************/
|
||
/* functions related to gameservice direct reconnection */
|
||
/*****************************************************************************/
|
||
|
||
/* 5 s to perform all connections */
|
||
|
||
#define GS_CONNECTION_TIMEOUT 5000
|
||
|
||
typedef struct _stTargetCell {
|
||
unsigned short uwPortNumber; /* port number to reconnect to */
|
||
unsigned long ulTargetIPAddr; /* IP address to reconnect to */
|
||
tduwNetChannel uwChannel; /* channel associated to this target */
|
||
char cRouteKnown; /* flag: level 1 knows this route */
|
||
struct _stTargetCell *pstNextTarget; /* link to next cell in list */
|
||
} tdstTargetCell;
|
||
|
||
unsigned short gs_pstL0PCWin95TCP_GS_ListenPort=0; /* socket number to listen on */
|
||
tdstTargetCell *gs_pstL0PCWin95TCPTargetsList=(tdstTargetCell *)C_pNull; /* list of target addresses to reconnect to */
|
||
unsigned char gs_ucL0PCWin95TCPConnecting=0; /* flag: are we currently in a connection process ? */
|
||
unsigned long gs_ulL0PCWin95TCPConnectionStartTime; /* time at which the connect process began */
|
||
|
||
static tdfn_vConnectionResult gs_pfnConnectionResult; /* Call back for connection result. */
|
||
|
||
/*****************************************************************************/
|
||
/* start listening on a port */
|
||
|
||
void _NET_CALLING_CONV_ vL0PCWin95TCPGSSetCallBackResult(tdfn_vConnectionResult pfnConnectionResult)
|
||
{
|
||
gs_pfnConnectionResult=pfnConnectionResult;
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
/* start listening on a port */
|
||
|
||
void GS_FUNCTIONCALL vL0PCWin95TCPGSSetPLayer(unsigned short uwPlayerId, unsigned short uwPortNumber)
|
||
|
||
{
|
||
/* the playerId argument is ignored ... */
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSISI(Net_C_Debug_TCP,"SetPlayer PlayerId",uwPlayerId,"Port",uwPortNumber);
|
||
#endif
|
||
|
||
eL0PCWin95TCPAddPort(uwPortNumber);
|
||
gs_pstL0PCWin95TCP_GS_ListenPort=uwPortNumber;
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
/* add a new entry to the list of targets to reconnect to */
|
||
|
||
void GS_FUNCTIONCALL vL0PCWin95TCPGSSetChannel(unsigned short uwPortNumber, char *pcIPAddr)
|
||
|
||
{
|
||
tdstTargetCell *pstTargetCell; /* new list element for the new target */
|
||
tdstTargetCell *pstCurrentCell; /* pointer to run through the list */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"SetChannel Port",uwPortNumber);
|
||
vDebugSS(Net_C_Debug_TCP,"Addr : ",pcIPAddr);
|
||
#endif
|
||
|
||
/* do not begin to register a new list before the former has not been processed */
|
||
|
||
if(gs_ucL0PCWin95TCPConnecting)
|
||
return;
|
||
|
||
/* allocate a new cell */
|
||
|
||
pstTargetCell=(tdstTargetCell *)pMalloc(sizeof(tdstTargetCell));
|
||
|
||
if(pstTargetCell==(tdstTargetCell *)C_pNull)
|
||
return; /* not enough memory */
|
||
|
||
/* fill the new cell */
|
||
|
||
pstTargetCell->uwPortNumber=uwPortNumber;
|
||
pstTargetCell->ulTargetIPAddr=
|
||
gs_p_stTCPWinSocDesc->m_pfn_ul_ntohl(gs_p_stTCPWinSocDesc->m_pfn_ul_inet_addr(pcIPAddr));
|
||
pstTargetCell->uwChannel=C_uwNetInvalidChannel;
|
||
pstTargetCell->cRouteKnown=0;
|
||
|
||
/* insert the new cell at the tail of the list */
|
||
|
||
if(gs_pstL0PCWin95TCPTargetsList==(tdstTargetCell *)C_pNull) {
|
||
pstTargetCell->pstNextTarget=(tdstTargetCell *)C_pNull;
|
||
gs_pstL0PCWin95TCPTargetsList=pstTargetCell;
|
||
} else {
|
||
pstTargetCell->pstNextTarget=(tdstTargetCell *)C_pNull;
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell->pstNextTarget!=(tdstTargetCell *)C_pNull)
|
||
pstCurrentCell=pstCurrentCell->pstNextTarget;
|
||
|
||
pstCurrentCell->pstNextTarget=pstTargetCell;
|
||
}
|
||
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
/* start reconnecting to the targets */
|
||
|
||
void GS_FUNCTIONCALL vL0PCWin95TCPGSInitiateConnection(void)
|
||
|
||
{
|
||
tdstTargetCell *pstCurrentCell; /* pointer to run through the list */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"InitiateConnection");
|
||
#endif
|
||
/* record the start time */
|
||
|
||
gs_ulL0PCWin95TCPConnectionStartTime=GetTickCount();
|
||
|
||
/* for each entry in the list, allocate a channel and launch an asynchronous connection */
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell!=(tdstTargetCell *)C_pNull) {
|
||
eL0PCWin95TCPChannelConnect(pstCurrentCell->uwPortNumber, pstCurrentCell->ulTargetIPAddr,
|
||
eReconnect, &pstCurrentCell->uwChannel);
|
||
pstCurrentCell=pstCurrentCell->pstNextTarget;
|
||
}
|
||
|
||
/* set the connection flag */
|
||
|
||
gs_ucL0PCWin95TCPConnecting=(unsigned char)~0;
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
|
||
void _NET_CALLING_CONV_ vL0PCWin95TCPCloseListenPort()
|
||
|
||
{
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"Close listen port");
|
||
#endif
|
||
vL0PCWin95TCPClosePort(gs_pstL0PCWin95TCP_GS_ListenPort);
|
||
gs_pstL0PCWin95TCP_GS_ListenPort=0;
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
|
||
void vL0PCWin95TCPNewRouteKnown(tduwNetChannel uwChannel)
|
||
|
||
{
|
||
tdstTargetCell *pstCurrentCell; /* pointers to run through the list */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugSI(Net_C_Debug_TCP,"route through channel known",uwChannel);
|
||
#endif
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell!=(tdstTargetCell *)C_pNull) {
|
||
|
||
if(pstCurrentCell->uwChannel==uwChannel) {
|
||
pstCurrentCell->cRouteKnown=1;
|
||
break;
|
||
}
|
||
pstCurrentCell=pstCurrentCell->pstNextTarget;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
|
||
void vL0PCWin95TCPGSConnectEngine()
|
||
|
||
{
|
||
char cCompleted;
|
||
|
||
tdstTargetCell *pstCurrentCell, *pstNextCell; /* pointers to run through the list */
|
||
|
||
if(gs_ucL0PCWin95TCPConnecting) {
|
||
|
||
/* check for connection process timeout/completion */
|
||
|
||
cCompleted=1;
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell!=(tdstTargetCell *)C_pNull) {
|
||
|
||
if(!gs_a_stL0PCWin95TCPChannels[pstCurrentCell->uwChannel].ubf1IsConnected) {
|
||
cCompleted=0;
|
||
break;
|
||
}
|
||
|
||
if(!pstCurrentCell->cRouteKnown) {
|
||
cCompleted=0;
|
||
break;
|
||
}
|
||
|
||
pstCurrentCell=pstCurrentCell->pstNextTarget;
|
||
}
|
||
|
||
if(cCompleted) { /* all connections succeeded */
|
||
|
||
/* free the target list */
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell!=(tdstTargetCell *)C_pNull) {
|
||
pstNextCell=pstCurrentCell->pstNextTarget;
|
||
vFree(pstCurrentCell);
|
||
pstCurrentCell=pstNextCell;
|
||
}
|
||
|
||
gs_pstL0PCWin95TCPTargetsList=(tdstTargetCell *)C_pNull;
|
||
|
||
/* alert the gameservice */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"Connection result 1");
|
||
#endif
|
||
if (gs_pfnConnectionResult) gs_pfnConnectionResult(1);
|
||
|
||
gs_ucL0PCWin95TCPConnecting=0;
|
||
|
||
} else if(GetTickCount()-gs_ulL0PCWin95TCPConnectionStartTime>GS_CONNECTION_TIMEOUT) {
|
||
|
||
/* time is over */
|
||
|
||
/* close all channels and free the target list */
|
||
|
||
pstCurrentCell=gs_pstL0PCWin95TCPTargetsList;
|
||
|
||
while(pstCurrentCell!=(tdstTargetCell *)C_pNull) {
|
||
pstNextCell=pstCurrentCell->pstNextTarget;
|
||
|
||
vL0PCWin95TCPCloseChannel(pstCurrentCell->uwChannel);
|
||
|
||
vFree(pstCurrentCell);
|
||
pstCurrentCell=pstNextCell;
|
||
}
|
||
|
||
gs_pstL0PCWin95TCPTargetsList=(tdstTargetCell *)C_pNull;
|
||
|
||
/* close the listen port */
|
||
|
||
vL0PCWin95TCPCloseListenPort();
|
||
|
||
/* alert the gameservice */
|
||
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugS(Net_C_Debug_TCP,"Connection result 0");
|
||
#endif
|
||
if (gs_pfnConnectionResult) gs_pfnConnectionResult(1);
|
||
|
||
gs_ucL0PCWin95TCPConnecting=0;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*****************************************************************************/
|
||
|
||
/*****************************************************************************
|
||
*
|
||
* Description: vL0PCWin95TCPOpenProtocol
|
||
*
|
||
* 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:
|
||
* October 29, 1996 Christophe Roguet
|
||
* the CloseChannel interface function is now null
|
||
****************************************************************************/
|
||
void _NET_CALLING_CONV_ vL0PCWin95TCPOpenProtocol(void)
|
||
{
|
||
tduwNetChannel uwChannelToInit;
|
||
tdstNetProtocolInterface *p_stProtocolInterface;
|
||
tdstTCPReconnectInterface *p_stReconnectInterface;
|
||
|
||
p_stReconnectInterface=pstNetGetTCPReconnectInterface();
|
||
p_stReconnectInterface->pfn_eTCPReconnect=eL0PCWin95TCPReconnect;
|
||
p_stReconnectInterface->pfn_eTCPGetPortAndAddress=eL0PCWin95TCPGetPortAndAddress;
|
||
p_stReconnectInterface->pfn_vTCPNewRouteKnown=vL0PCWin95TCPNewRouteKnown;
|
||
p_stReconnectInterface->pfn_uwTCPGetNewReconnectChannel=uwL0PCWin95TCPGetNewReconnectChannel;
|
||
|
||
/* initialize our global socket descriptors */
|
||
#if defined(NET_USE_DEBUG)
|
||
vDebugClear(Net_C_Debug_TCP);
|
||
vDebugS(Net_C_Debug_TCP,"Netlib - Level 0 - TCP WIN95 : Log file");
|
||
#endif /* NET_USE_DEBUG */
|
||
|
||
gs_bL0PCWin95TCPInitState = 0x00;
|
||
|
||
/* bind to the DLL if necessary */
|
||
|
||
if(!gs_cIsWinsocDescInit) {
|
||
if(eNetGetWinSockDesc(&gs_p_stTCPWinSocDesc)!=NetLib_E_es_NoError)
|
||
return ;
|
||
gs_cIsWinsocDescInit=~0;
|
||
}
|
||
|
||
p_stProtocolInterface=pstLevel1AddProtocol();
|
||
|
||
/* logical identification of the protocol */
|
||
p_stProtocolInterface->eProtocol = E_Net_pr_Windows95TCPProtocol;
|
||
|
||
/* setup the function pointers */
|
||
p_stProtocolInterface->fn_uwStartChannelScan = uwL0PCWin95TCPStartChannelScan;
|
||
p_stProtocolInterface->fn_uwStartBroadcastChannelScan= uwL0PCWin95TCPStartBroadcastChannelScan;
|
||
p_stProtocolInterface->fn_uwNextChannel= uwL0PCWin95TCPNextChannel;
|
||
p_stProtocolInterface->fn_uwNextBroadcastChannel= uwL0PCWin95TCPNextBroadcastChannel;
|
||
p_stProtocolInterface->fn_eReadData= eL0PCWin95TCPReadData;
|
||
p_stProtocolInterface->fn_eSendData= eL0PCWin95TCPSendData;
|
||
p_stProtocolInterface->fn_eQueryChannelStatus= eL0PCWin95TCPQueryChannelStatus;
|
||
p_stProtocolInterface->fn_vLevel0NetEngine = vL0PCWin95TCPNetEngine;
|
||
p_stProtocolInterface->fn_vCloseChannel = (tdfn_vCloseChannel)C_pNull;
|
||
p_stProtocolInterface->fn_vLevel0CloseProtocol = vL0PCWin95TCPCloseProtocol;
|
||
p_stProtocolInterface->eIsInternet = 1;
|
||
|
||
/* initialize all slots as unused channels */
|
||
|
||
for (uwChannelToInit = 0; uwChannelToInit < C_ucL0MaxNumberOfTCPChannels; uwChannelToInit ++)
|
||
{
|
||
/* the channel is not used yet */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].ubf1IsSlotInUse = 0;
|
||
|
||
/* this is a channel usable to send private messages */
|
||
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].ubf1IsBroadcast = 0;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].ubf1IsConnected = 0;
|
||
|
||
/* initialize the destination address: */
|
||
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].stRemoteAddr.sin_family=AF_INET;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].stRemoteAddr.sin_port=0;
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].stRemoteAddr.sin_addr.s_addr=gs_p_stTCPWinSocDesc->m_pfn_ul_htonl(INADDR_NONE);
|
||
|
||
/* the channel is working properly */
|
||
gs_a_stL0PCWin95TCPChannels[uwChannelToInit].eChannelStatus = E_ts_OK;
|
||
}
|
||
gs_bL0PCWin95TCPInitState = gs_bL0PCWin95TCPInitState |(char)0x01;
|
||
gs_pfnConnectionResult=NULL;
|
||
}
|