mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5569 lines
154 KiB
5569 lines
154 KiB
/*++
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Comm.c
|
|
|
|
Abstract:
|
|
|
|
This module contains COMSYS's internal functions. These functions
|
|
are called by commapi functions.
|
|
|
|
Functions:
|
|
CommCreatePorts
|
|
CommInit
|
|
MonTcp
|
|
MonUdp
|
|
HandleMsg
|
|
CommReadStream
|
|
ProcTcpMsg
|
|
CommCreateTcpThd
|
|
CommCreateUdpThd
|
|
CreateThd
|
|
CommConnect
|
|
CommSend
|
|
CommSendAssoc
|
|
CommDisc
|
|
CommSendUdp
|
|
ParseMsg
|
|
CommAlloc
|
|
CommDealloc
|
|
CompareNbtReq
|
|
CommEndAssoc
|
|
DelAssoc
|
|
CommLockBlock
|
|
CommUnlockBlock
|
|
InitMem
|
|
ChkNtfSock
|
|
RecvData
|
|
|
|
|
|
Portability:
|
|
This module is portable
|
|
Author:
|
|
|
|
Pradeep Bahl (pradeepb) 18-Nov-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
/*
|
|
Includes
|
|
*/
|
|
//
|
|
// The max. number of connections that can be there to/from WINS.
|
|
//
|
|
// NOTE NOTE NOTE
|
|
//
|
|
// We specify a RCVBUF size, based on this value, for the notification socket.
|
|
//
|
|
#define FD_SETSIZE 300
|
|
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include "wins.h"
|
|
|
|
//
|
|
// pragma to disable duplicate definition message
|
|
//
|
|
#pragma warning (disable : 4005)
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#pragma warning (default : 4005)
|
|
|
|
#include <nb30.h>
|
|
#include <nbtioctl.h>
|
|
#include <tdi.h>
|
|
#include "nms.h"
|
|
#include "rpl.h"
|
|
#include "comm.h"
|
|
#include "assoc.h"
|
|
#include "winsthd.h"
|
|
#include "winsque.h"
|
|
#include "winsmsc.h"
|
|
#include "winsevt.h"
|
|
#include "winscnf.h"
|
|
#if MCAST > 0
|
|
#include "rnraddrs.h"
|
|
#endif
|
|
|
|
|
|
/*
|
|
defines
|
|
*/
|
|
|
|
#define TCP_QUE_LEN 5 /*Max # of backlog connections that can be
|
|
*existent at any time. NOTE: WinsSock
|
|
*api can keep a max. of 5 connection req
|
|
*in the queue. So, even if we specified
|
|
* a higher number, that wouldn't help.
|
|
*For our purposes 5 is enough.
|
|
*/
|
|
|
|
#define SPX_QUE_LEN 5 /*Max # of backlog connections that can be*/
|
|
|
|
//
|
|
// These specify the timeout value for select call that is made when
|
|
// message/data is expected on a connection
|
|
//
|
|
|
|
//
|
|
// We keep the timeout 5 mts for now to give the WINS server we are
|
|
// communicating enough time to respond (in case it has been asked to send
|
|
// a huge number of records.
|
|
//
|
|
#define SECS_TO_WAIT 300 //5 mts
|
|
#define MICRO_SECS_TO_WAIT 0
|
|
|
|
#define TWENTY_MTS 1200 //20 mts
|
|
#define FIVE_MTS TWENTY_MTS/4 //5 mts
|
|
|
|
//
|
|
// The max. number of bytes we can expect in a message from another WINS over
|
|
// a tcp connection
|
|
//
|
|
#define MAX_BYTES_IN_MSG (RPL_MAX_LIMIT_FOR_RPL * (sizeof(RPL_REC_ENTRY_T) + NMSDB_MAX_NAM_LEN + (RPL_MAX_GRP_MEMBERS * sizeof(COMM_ADD_T))) + 10000 /*pad*/)
|
|
|
|
#define MCAST_PKT_LEN_M(NoOfIpAdd) (COMM_MCAST_MSG_SZ -1 + (COMM_IP_ADD_SIZE * (NoOfIpAdd)))
|
|
//
|
|
// This is the string used for getting the port pertaining to a nameserver
|
|
// from the etc\services file (via getserverbyname)
|
|
//
|
|
#define NAMESERVER "nameserver"
|
|
|
|
/*
|
|
Globals
|
|
*/
|
|
|
|
RTL_GENERIC_TABLE CommUdpNbtDlgTable; /*table for dialogue blocks created as
|
|
*a result of nbt requests received
|
|
*over the UDP port
|
|
*/
|
|
|
|
BOOL fCommDlgError = FALSE; //set to TRUE in ChkNtfSock() fn.
|
|
DWORD CommWinsTcpPortNo = COMM_DEFAULT_IP_PORT;
|
|
DWORD WinsClusterIpAddress = 0;
|
|
#if SPX > 0
|
|
#define WINS_IPX_PORT 100
|
|
DWORD CommWinsSpxPortNo;
|
|
#endif
|
|
|
|
/*
|
|
Static variables
|
|
*/
|
|
#ifdef WINSDBG
|
|
#define SOCKET_TRACK_BUFFER_SIZE 20000
|
|
|
|
DWORD CommNoOfDgrms; //for testing purposes only. It counts the
|
|
//number of datagrams received
|
|
DWORD CommNoOfRepeatDgrms;
|
|
|
|
PUINT_PTR pTmpW;
|
|
BOOL sfMemoryOverrun = FALSE;
|
|
LPLONG pEndPtr;
|
|
#endif
|
|
|
|
DWORD CommConnCount = 0; //no of tcp connection from/to this WINS
|
|
struct timeval sTimeToWait = {SECS_TO_WAIT, MICRO_SECS_TO_WAIT};
|
|
|
|
STATIC HANDLE sNetbtSndEvtHdl;
|
|
STATIC HANDLE sNetbtRcvEvtHdl;
|
|
STATIC HANDLE sNetbtGetAddrEvtHdl;
|
|
|
|
#if MCAST > 0
|
|
#define COMM_MCAST_ADDR IP_S_MEMBERSHIP //just pick one in the allowed range
|
|
struct sockaddr_in McastAdd;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Structures used to store information about partners discovered via
|
|
// Multicasting
|
|
//
|
|
typedef struct _ADD_T {
|
|
DWORD NoOfAdds;
|
|
COMM_IP_ADD_T IpAdd[1];
|
|
} ADD_T, *PADD_T;
|
|
|
|
typedef struct _MCAST_PNR_STATUS_T {
|
|
DWORD NoOfPnrs; //no of pnrs in pPnrStatus buffer
|
|
DWORD NoOfPnrSlots; //no of pnr slots in pPnrStatus buffer
|
|
BYTE Pnrs[1];
|
|
} MCAST_PNR_STATUS_T, *PMCAST_PNR_STATUS_T;
|
|
|
|
typedef struct _PNR_STATUS_T {
|
|
COMM_IP_ADD_T IPAdd;
|
|
DWORD State;
|
|
} PNR_STATUS_T, *PPNR_STATUS_T;
|
|
|
|
#define MCAST_PNR_STATUS_SIZE_M(_NoOfPnrs) sizeof(MCAST_PNR_STATUS_T) +\
|
|
((_NoOfPnrs) * sizeof(PNR_STATUS_T))
|
|
|
|
PMCAST_PNR_STATUS_T pPnrStatus;
|
|
|
|
//
|
|
// To store WINS Addresses
|
|
//
|
|
PADD_T pWinsAddresses=NULL; //stores all the IP addresses returned by netbt
|
|
|
|
/* local function prototypes */
|
|
STATIC
|
|
DWORD
|
|
MonTcp(
|
|
LPVOID
|
|
);
|
|
STATIC
|
|
DWORD
|
|
MonUdp(
|
|
LPVOID
|
|
);
|
|
STATIC
|
|
VOID
|
|
HandleMsg(
|
|
SOCKET SockNo,
|
|
LPLONG pBytesRead,
|
|
LPBOOL pfSockCl
|
|
);
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
ProcTcpMsg(
|
|
SOCKET SockNo,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen,
|
|
LPBOOL pfSockCl
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
CreateThd(
|
|
DWORD (*pStartFunc)(LPVOID),
|
|
WINSTHD_TYP_E ThdTyp_e
|
|
);
|
|
|
|
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
ParseMsg(
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen,
|
|
COMM_TYP_E MsgType,
|
|
struct sockaddr_in *pFromAdd,
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx
|
|
);
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
DelAssoc(
|
|
SOCKET SockNo,
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx
|
|
);
|
|
|
|
|
|
STATIC
|
|
VOID
|
|
InitMem(
|
|
VOID
|
|
);
|
|
|
|
STATIC
|
|
BOOL
|
|
ChkNtfSock(
|
|
IN fd_set *pActSocks,
|
|
IN fd_set *pRdSocks
|
|
);
|
|
|
|
STATIC
|
|
STATUS
|
|
RecvData(
|
|
SOCKET SockNo,
|
|
LPBYTE pBuff,
|
|
DWORD BytesToRead,
|
|
INT Flags,
|
|
DWORD SecsToWait,
|
|
LPDWORD pBytesRead
|
|
);
|
|
|
|
STATUS
|
|
CommTcp(
|
|
IN PCOMM_ADD_T pHostAdd,
|
|
IN SOCKET Port,
|
|
OUT SOCKET *pSockNo
|
|
);
|
|
|
|
#if SPX > 0
|
|
STATUS
|
|
CommSpx(
|
|
IN PCOMM_ADD_T pHostAdd,
|
|
IN SOCKET Port,
|
|
OUT SOCKET *pSockNo
|
|
);
|
|
#endif
|
|
|
|
|
|
STATIC
|
|
LPVOID
|
|
CommHeapAlloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN CLONG BuffSize
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
CommHeapDealloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN PVOID pBuff
|
|
);
|
|
|
|
STATIC
|
|
NTSTATUS
|
|
DeviceIoCtrl(
|
|
IN LPHANDLE pEvtHdl,
|
|
IN PVOID pDataBuffer,
|
|
IN DWORD DataBufferSize,
|
|
IN ULONG Ioctl
|
|
);
|
|
|
|
STATIC
|
|
VOID
|
|
SendNetbt (
|
|
struct sockaddr_in *pDest,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
);
|
|
|
|
#if MCAST > 0
|
|
VOID
|
|
JoinMcastGrp(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
CheckMcastSock(
|
|
IN fd_set *pActSocks,
|
|
IN fd_set *pRdSocks
|
|
);
|
|
|
|
#endif
|
|
|
|
VOID
|
|
CreateTcpIpPorts(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
CreateSpxIpxPorts(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
ChkMyAdd(
|
|
COMM_IP_ADD_T IpAdd
|
|
);
|
|
|
|
|
|
/*
|
|
function definitions start here
|
|
*/
|
|
|
|
VOID
|
|
CommCreatePorts(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a TCP and UDP port for the WINS server
|
|
It uses the standard WINS server port # to bind to both the TCP and the UDP
|
|
sockets.
|
|
|
|
Arguments:
|
|
|
|
Qlen - Length of queue for incoming connects on the TCP port
|
|
pTcpPortHandle - Ptr to SOCKET for the TCP port
|
|
pUdpPortHandle - Ptr to SOCKET for the UDP port
|
|
pNtfSockHandle - Ptr to SOCKET for receiving messages carrying socket
|
|
handles
|
|
pNtfAdd - Address bound to Notification socket
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
ECommInit
|
|
|
|
Comments:
|
|
|
|
I might want to create a PassiveSock function that would create
|
|
a TCP/UDP port based on its arguments. This function would then
|
|
be called from MOnTCP and MonUDP.
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
CreateTcpIpPorts();
|
|
#if SPX > 0
|
|
CreateSpxIpxPorts();
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
CreateTcpIpPorts(
|
|
VOID
|
|
)
|
|
{
|
|
int Error;
|
|
DWORD AddLen = sizeof(struct sockaddr_in);
|
|
struct servent *pServEnt;
|
|
struct sockaddr_in sin;
|
|
int SockBuffSize;
|
|
|
|
|
|
WINSMSC_FILL_MEMORY_M(&sin, sizeof(sin), 0);
|
|
WINSMSC_FILL_MEMORY_M(&CommNtfSockAdd, sizeof(sin), 0);
|
|
|
|
#if MCAST > 0
|
|
/*
|
|
Allocate a socket for UDP
|
|
*/
|
|
|
|
if ( (CommUdpPortHandle = socket(
|
|
PF_INET,
|
|
SOCK_DGRAM,
|
|
IPPROTO_UDP
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_UDP_SOCK); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
DBGPRINT1(MTCAST, "Udp socket # is (%d)\n", CommUdpPortHandle);
|
|
#endif
|
|
|
|
sin.sin_family = PF_INET; //We are using the Internet
|
|
//family
|
|
if (WinsClusterIpAddress) {
|
|
sin.sin_addr.s_addr = htonl(WinsClusterIpAddress); //Any network
|
|
} else {
|
|
sin.sin_addr.s_addr = 0; //any network
|
|
}
|
|
|
|
|
|
if (CommWinsTcpPortNo == COMM_DEFAULT_IP_PORT)
|
|
{
|
|
pServEnt = getservbyname( NAMESERVER, NULL);
|
|
if (!pServEnt)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_UDP_SOCK); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
sin.sin_port = pServEnt->s_port;
|
|
CommWinsTcpPortNo = ntohs(sin.sin_port);
|
|
}
|
|
else
|
|
{
|
|
sin.sin_port = htons((USHORT)CommWinsTcpPortNo);
|
|
}
|
|
DBGPRINT1(DET, "UDP/TCP port used is (%d)\n", CommWinsTcpPortNo);
|
|
|
|
#if MCAST > 0
|
|
|
|
//
|
|
// Initialize global with mcast address of WINS. Used by SendMcastMsg
|
|
//
|
|
// Do this here as against later since sin gets changed later on
|
|
//
|
|
McastAdd.sin_family = PF_INET; //We are using the Internet
|
|
//family
|
|
McastAdd.sin_addr.s_addr = ntohl(inet_addr(COMM_MCAST_ADDR));
|
|
McastAdd.sin_port = sin.sin_port;
|
|
|
|
/*
|
|
Bind the address to the socket
|
|
*/
|
|
if ( bind(
|
|
CommUdpPortHandle,
|
|
(struct sockaddr *)&sin,
|
|
sizeof(sin)) == SOCKET_ERROR
|
|
)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Allocate a socket for receiving TCP connections
|
|
*/
|
|
if ( (CommTcpPortHandle = socket(
|
|
PF_INET,
|
|
SOCK_STREAM,
|
|
IPPROTO_TCP
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_TCP_SOCK_FOR_LISTENING);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
|
|
/*
|
|
* Bind the address to the socket
|
|
*/
|
|
#if 0
|
|
sin.sin_port = pServEnt->s_port;
|
|
CommWinsTcpPortNo = ntohs(pServEnt->s_port);
|
|
DBGPRINT1(DET, "TCP port used is (%d)\n", CommWinsTcpPortNo);
|
|
#endif
|
|
DBGPRINT1(DET, "TCP port used is (%d)\n", ntohs(sin.sin_port));
|
|
|
|
|
|
if ( bind(
|
|
CommTcpPortHandle,
|
|
(struct sockaddr *)&sin,
|
|
sizeof(sin)
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
// Inform the TCP/IP driver of the queue length for connections
|
|
if ( listen(CommTcpPortHandle, TCP_QUE_LEN) == SOCKET_ERROR)
|
|
{
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WINSOCK_LISTEN_ERR);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Create another socket for receiving socket #s of connections
|
|
// to be added/removed from the list of sockets monitored by the
|
|
// TCP listener thread. An example of a connection added to the
|
|
// above list is the one initiated by the PULL thread to push update
|
|
// notifications to other WINSs (PULL partners of this thread). An
|
|
// example of a connection removed is the one on which a PUSH
|
|
// notification (trigger) is received.
|
|
//
|
|
if ( (CommNtfSockHandle = socket(
|
|
PF_INET,
|
|
#if 0
|
|
SOCK_STREAM,
|
|
IPPROTO_TCP,
|
|
#endif
|
|
SOCK_DGRAM,
|
|
IPPROTO_UDP
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_NTF_SOCK); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
sin.sin_port = 0; //Use any available port in the range 1024-5000
|
|
/*
|
|
Bind the address to the socket
|
|
*/
|
|
if ( bind(
|
|
CommNtfSockHandle,
|
|
(struct sockaddr *)&sin,
|
|
sizeof(sin)) == SOCKET_ERROR
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
|
|
//
|
|
// Let us get the address that we have bound the notification socket to
|
|
//
|
|
if (getsockname(
|
|
CommNtfSockHandle,
|
|
(struct sockaddr *)&CommNtfSockAdd,
|
|
&AddLen
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_GETSOCKNAME_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
//
|
|
// Set the RCVBUF to FD_SETSIZE * 128. 128 is the # of bytes used up
|
|
// per msg by Afd. We can have a max of FD_SETSIZE connections initiated
|
|
// to and from WINS. So, making the recv buf this size ensures that msgs
|
|
// sent by push thread to the tcp thread will never get dropped.
|
|
//
|
|
// The above size comes out to be 38.4K for an FD_SETSIZE of 300. This
|
|
// is > 8k which the default used by Afd. Note: Specifying this does
|
|
// not use up memory. It is just used to set a threshold. pmon will
|
|
// show a higher non-paged pool since the number it shows for the same
|
|
// indicates the amount of memory charged to the process (not necessarily
|
|
// allocated
|
|
//
|
|
SockBuffSize = FD_SETSIZE * 128;
|
|
if (setsockopt(
|
|
CommNtfSockHandle,
|
|
SOL_SOCKET,
|
|
SO_RCVBUF,
|
|
(char *)&SockBuffSize,
|
|
sizeof(SockBuffSize)) == SOCKET_ERROR)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(ERR, "CommCreatePorts: SetSockOpt failed", Error);
|
|
}
|
|
|
|
//
|
|
// Initialize the address structure for this notification socket.
|
|
// We can't use the address returned by getsockname() if the
|
|
// machine we are running on is a multi-homed host.
|
|
//
|
|
// The IP address is in host byte order since we store all addresses in
|
|
// host order. CommNtfSockAdd will be passed to CommSendUdp which expects
|
|
// the IP address in it to be in host byte order.
|
|
//
|
|
// Note: the Port should be in net byte order
|
|
//
|
|
|
|
//
|
|
// The statement within #if 0 and #endif does not work.
|
|
//
|
|
CommNtfSockAdd.sin_addr.s_addr = NmsLocalAdd.Add.IPAdd;
|
|
|
|
#if 0
|
|
CommNtfSockAdd.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
|
|
#endif
|
|
|
|
#if MCAST > 0
|
|
|
|
JoinMcastGrp();
|
|
CommSendMcastMsg(COMM_MCAST_WINS_UP);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
#if SPX > 0
|
|
VOID
|
|
CreateSpxIpxPorts(
|
|
VOID
|
|
)
|
|
{
|
|
int Error;
|
|
DWORD AddLen = sizeof(struct sockaddr_ipx);
|
|
struct servent *pServEnt;
|
|
struct sockaddr_ipx sipx;
|
|
struct hostent *pHostEnt;
|
|
BYTE HostName[80];
|
|
|
|
WINSMSC_FILL_MEMORY_M(&sipx, sizeof(sipx), 0);
|
|
WINSMSC_FILL_MEMORY_M(CommNtfAdd, sizeof(sipx), 0);
|
|
|
|
|
|
|
|
/*
|
|
* Allocate a socket for receiving TCP connections
|
|
*/
|
|
if ( (CommSpxPortHandle = socket(
|
|
PF_IPX,
|
|
SOCK_STREAM,
|
|
NSPROTO_SPX
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_TCP_SOCK_FOR_LISTENING);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
|
|
/*
|
|
* Bind the address to the socket
|
|
*/
|
|
sipx.sa_family = PF_IPX;
|
|
sipx.sa_port = ntohs(WINS_IPX_PORT);
|
|
CHECK("How do I specify that I want the connection from any interface")
|
|
|
|
DBGPRINT1(DET, "SPX port used is (%d)\n", WINS_IPX_PORT);
|
|
CommWinsSpxPortNo = WINS_IPX_PORT;
|
|
|
|
if ( bind(
|
|
CommSpxPortHandle,
|
|
(struct sockaddr *)&sipx,
|
|
sizeof(sipx)
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
// Inform the TCP/IP driver of the queue length for connections
|
|
if ( listen(CommSpxPortHandle, SPX_QUE_LEN) == SOCKET_ERROR)
|
|
{
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_WINSOCK_LISTEN_ERR);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Create another socket for receiving socket #s of connections
|
|
// to be added/removed from the list of sockets monitored by the
|
|
// TCP listener thread. An example of a connection added to the
|
|
// above list is the one initiated by the PULL thread to push update
|
|
// notifications to other WINSs (PULL partners of this thread). An
|
|
// example of a connection removed is the one on which a PUSH
|
|
// notification (trigger) is received.
|
|
//
|
|
if ( (CommIpxNtfSockHandle = socket(
|
|
PF_IPX,
|
|
SOCK_DGRAM,
|
|
NSPROTO_IPX
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_NTF_SOCK); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
sipx.sa_port = 0; //Use any available port in the range 1024-5000
|
|
/*
|
|
Bind the address to the socket
|
|
*/
|
|
if ( bind(
|
|
CommIpxNtfSockHandle,
|
|
(struct sockaddr *)&sipx,
|
|
sizeof(sipx)) == SOCKET_ERROR
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
|
|
//
|
|
// Let us get the address that we have bound the notification socket to
|
|
//
|
|
if (getsockname(
|
|
CommIpxNtfSockHandle,
|
|
(struct sockaddr *)&CommIpxNtfSockAdd,
|
|
&AddLen
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_GETSOCKNAME_ERR); //log an event
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the address structure for this notification socket.
|
|
// We can't use the address returned by getsockname() if the
|
|
// machine we are running on is a multi-homed host.
|
|
//
|
|
// The IP address is in host byte order since we store all addresses in
|
|
// host order. *pNtfAdd will be passed to CommSendUdp which expects
|
|
// the IP address in it to be in host byte order.
|
|
//
|
|
// Note: the Port should be in net byte order
|
|
//
|
|
#if 0
|
|
if (gethostname(HostName, sizeof(HostName) == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
if (gethostbyname(HostName, sizeof(HostName) == NULL)
|
|
{
|
|
Error = WSAGetLastError();
|
|
WINS_RAISE_EXC_M(WINS_EXC_FATAL_ERR);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// The statement within #if 0 and #endif does not work.
|
|
//
|
|
CommIpxNtfSockAdd->sin_addr.s_addr = 0;
|
|
|
|
#if 0
|
|
pNtfAdd->sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
CommInit(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes all the lists, tables and memory
|
|
used by COMSYS.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Externals Used:
|
|
CommAssocTable
|
|
CommUdpNbtDlgTable
|
|
CommExNbtDlgHdl
|
|
CommUdpBuffHeapHdl
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
ECommInit
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = NULL;
|
|
|
|
//
|
|
// Do all memory initialization
|
|
//
|
|
InitMem();
|
|
|
|
/*
|
|
* Initialize the table that will store the dialogue context blocks
|
|
* for nbt requests received over the UDP port.
|
|
*/
|
|
WINSMSC_INIT_TBL_M(
|
|
&CommUdpNbtDlgTable,
|
|
CommCompareNbtReq,
|
|
CommHeapAlloc,
|
|
CommHeapDealloc,
|
|
NULL /* table context*/
|
|
);
|
|
|
|
/*
|
|
* Initialize the critical sections and queue heads
|
|
*
|
|
* The initialization is done in a CommAssoc function instead of here
|
|
* to avoid recursive includes
|
|
*/
|
|
CommAssocInit();
|
|
|
|
CommExNbtDlgHdl.pEnt = CommAssocAllocDlg();
|
|
pDlgCtx = CommExNbtDlgHdl.pEnt;
|
|
|
|
/*
|
|
* Initialize the explicit nbt dialogue handle
|
|
*/
|
|
pDlgCtx->Typ_e = COMM_E_UDP;
|
|
pDlgCtx->AssocHdl.pEnt = NULL;
|
|
pDlgCtx->Role_e = COMMASSOC_DLG_E_EXPLICIT;
|
|
|
|
#if USENETBT > 0
|
|
//
|
|
// Create two events (one for send and one for rcv to/from netbt)
|
|
//
|
|
WinsMscCreateEvt(NULL, FALSE, &sNetbtSndEvtHdl);
|
|
WinsMscCreateEvt(NULL, FALSE, &sNetbtRcvEvtHdl);
|
|
WinsMscCreateEvt(NULL, FALSE, &sNetbtGetAddrEvtHdl);
|
|
#endif
|
|
|
|
return;
|
|
} // CommInit()
|
|
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
MonTcp(
|
|
LPVOID pArg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the thread startup function for the TCP listener
|
|
thread. It monitors the TCP port and the connections that have
|
|
been made and received by this process.
|
|
|
|
If a connection is received, it is accepted. If there is data on
|
|
a TCP connection, a function is called to process it.
|
|
|
|
Arguments:
|
|
|
|
pArg - Argument (Not used)
|
|
|
|
Externals Used:
|
|
CommTCPPortHandle -- TCP port for the process
|
|
CommAssocTable
|
|
|
|
Called by:
|
|
ECommInit
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Sucess status codes -- WINS_SUCCESS
|
|
Error status codes -- WINS_FAILURE
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
struct sockaddr_in fsin; //address of connector
|
|
#if SPX > 0
|
|
struct sockaddr_ipx fsipx; //address of connector
|
|
#endif
|
|
SOCKET Port;
|
|
LPVOID pRemAdd;
|
|
fd_set RdSocks; //The read socket set
|
|
fd_set ActSocks; //the active socket set
|
|
int AddLen = sizeof(fsin); //length of from address
|
|
u_short No; //Counter for iterating over the sock
|
|
//array
|
|
BOOL fSockCl = FALSE; //Was the socket closed ?
|
|
SOCKET NewSock = INVALID_SOCKET;
|
|
BOOL fNewAssoc = FALSE;
|
|
DWORD BytesRead = 0;
|
|
DWORD Error;
|
|
int i = 0; //for testing purpose only
|
|
SOCKET SockNo;
|
|
LONG NoOfSockReady = 0;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = NULL;
|
|
STATUS RetStat = WINS_SUCCESS;
|
|
BOOL fLimitReached = FALSE;
|
|
#ifdef WINSDBG
|
|
PUINT_PTR pTmpSv;
|
|
DWORD Index = 0;
|
|
#endif
|
|
|
|
|
|
EnterCriticalSection(&NmsTermCrtSec);
|
|
NmsTotalTrmThdCnt++;
|
|
LeaveCriticalSection(&NmsTermCrtSec);
|
|
|
|
|
|
FD_ZERO(&ActSocks); //init the Active socket array
|
|
FD_ZERO(&RdSocks); //init the Read socket array
|
|
|
|
FD_SET(CommTcpPortHandle, &ActSocks); /*set the TCP listening socket
|
|
handle in the Active array */
|
|
FD_SET(CommNtfSockHandle, &ActSocks); /*set the Notification socket
|
|
*handle in the Active array */
|
|
#if MCAST > 0
|
|
|
|
if (CommUdpPortHandle != INVALID_SOCKET)
|
|
{
|
|
//
|
|
// We want to monitor multicast packets also
|
|
//
|
|
FD_SET(CommUdpPortHandle, &ActSocks);
|
|
WinsMscAlloc(MCAST_PNR_STATUS_SIZE_M(RPL_MAX_OWNERS_INITIALLY),
|
|
(LPVOID *)&pPnrStatus
|
|
);
|
|
pPnrStatus->NoOfPnrs = 0;
|
|
pPnrStatus->NoOfPnrSlots = RPL_MAX_OWNERS_INITIALLY;
|
|
}
|
|
#endif
|
|
#if SPX > 0
|
|
|
|
FD_SET(CommSpxPortHandle, &ActSocks); /*set the TCP listening socket
|
|
handle in the Active array */
|
|
FD_SET(CommIpxNtfSockHandle, &ActSocks); /*set the Notification socket
|
|
*handle in the Active array */
|
|
#endif
|
|
#ifdef WINSDBG
|
|
WinsMscAlloc(SOCKET_TRACK_BUFFER_SIZE, &pTmpSv);
|
|
pTmpW = pTmpSv;
|
|
pEndPtr = (LPLONG)((LPBYTE)pTmpSv + SOCKET_TRACK_BUFFER_SIZE);
|
|
#endif
|
|
|
|
LOOPTCP:
|
|
try {
|
|
|
|
/*
|
|
Loop forever
|
|
*/
|
|
while(TRUE)
|
|
{
|
|
BOOL fConnTcp;
|
|
BOOL fConnSpx;
|
|
|
|
fConnTcp = FALSE;
|
|
fConnSpx = FALSE;
|
|
/*
|
|
Copy the the active socket array into the
|
|
read socket array. This is done every time before calling
|
|
select. This is because select changes the contents of
|
|
the read socket array.
|
|
*/
|
|
WINSMSC_COPY_MEMORY_M(&RdSocks, &ActSocks, sizeof(fd_set));
|
|
|
|
/*
|
|
Do a blocking select on all sockets in the array (for connections
|
|
and data)
|
|
*/
|
|
DBGPRINT1(FLOW, "Rd array count is %d \n", RdSocks.fd_count);
|
|
#ifdef WINSDBG
|
|
if (!sfMemoryOverrun)
|
|
{
|
|
if ((ULONG_PTR)(pTmpW + (10 + RdSocks.fd_count)) > (ULONG_PTR)pEndPtr)
|
|
{
|
|
WinsDbg |= 0x3;
|
|
DBGPRINT0(ERR, "MonTcp: Stopping socket tracking to prevent Memory overrun\n")
|
|
sfMemoryOverrun = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pTmpW++ = RdSocks.fd_count;
|
|
*pTmpW++ = 0xFFFFFFFF;
|
|
for(i = 0; i< (int)RdSocks.fd_count; i++)
|
|
{
|
|
*pTmpW++ = RdSocks.fd_array[i];
|
|
DBGPRINT1(FLOW, "Sock no is (%d)\n", RdSocks.fd_array[i]);
|
|
}
|
|
*pTmpW++ = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
#endif
|
|
if (
|
|
(
|
|
NoOfSockReady = select(
|
|
FD_SETSIZE /*ignored arg*/,
|
|
&RdSocks,
|
|
(fd_set *)0,
|
|
(fd_set *)0,
|
|
(struct timeval *)0 //Infinite
|
|
//timeout
|
|
)
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
#ifdef WINSDBG
|
|
if (Error == WSAENOTSOCK)
|
|
{
|
|
DWORD i;
|
|
PUINT_PTR pW;
|
|
WinsDbg |= 0x3;
|
|
DBGPRINT0(ERR, "MonTcp: Memory dump is\n\n");
|
|
|
|
for (i=0, pW = pTmpSv; pW < pTmpW; pW++,i++)
|
|
{
|
|
DBGPRINT1(ERR, "|%x|", *pW);
|
|
if (*pW == 0xEFFFFFFE)
|
|
{
|
|
DBGPRINT1(ERR, "Socket closed = (%x)\n", *++pW);
|
|
}
|
|
if ((i == 16) || (*pW == 0xFFFFFFFF))
|
|
{
|
|
DBGPRINT0(ERR, "\n");
|
|
}
|
|
|
|
}
|
|
DBGPRINT0(ERR, "Memory Dump End\n");
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If state is not terminating, we have an error. If
|
|
// it is terminating, then the reason we got an error
|
|
// from select is because the main thread closed the
|
|
// TCP socket. In the latter case, we pass WINS_SUCCESS
|
|
// to WinsMscTermThd so that we don't end up signaling
|
|
// the main thread prematurely.
|
|
//
|
|
if (
|
|
(WinsCnf.State_e == WINSCNF_E_RUNNING)
|
|
||
|
|
(WinsCnf.State_e == WINSCNF_E_PAUSED)
|
|
)
|
|
{
|
|
ASSERT(Error != WSAENOTSOCK);
|
|
WINSEVT_LOG_D_M( Error, WINS_EVT_WINSOCK_SELECT_ERR );
|
|
RetStat = WINS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// State is terminating. Error should
|
|
// be WSENOTSOCK
|
|
//
|
|
//ASSERT(Error == WSAENOTSOCK);
|
|
}
|
|
|
|
WinsThdPool.CommThds[0].fTaken = FALSE;
|
|
WinsMscTermThd(RetStat, WINS_NO_DB_SESSION_EXISTS);
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
DBGPRINT1(FLOW, "Select returned with success. No of Sockets ready - (%d) \n", NoOfSockReady);
|
|
/*
|
|
if a connection has been received on the TCP port, accept it
|
|
and change the active socket array
|
|
*/
|
|
if (FD_ISSET(CommTcpPortHandle, &RdSocks))
|
|
{
|
|
fConnTcp = TRUE;
|
|
Port = CommTcpPortHandle;
|
|
pRemAdd = &fsin;
|
|
}
|
|
#if SPX > 0
|
|
else
|
|
{
|
|
if (FD_ISSET(CommSpxPortHandle, &RdSocks))
|
|
{
|
|
fConnSpx = TRUE;
|
|
Port = CommSpxPortHandle;
|
|
pRemAdd = &fsipx;
|
|
}
|
|
|
|
}
|
|
#endif
|
|
if (fConnTcp || fConnSpx)
|
|
{
|
|
DWORD ConnCount;
|
|
//
|
|
// Note: FD_SET can fail silently if the fd_set array is
|
|
// full. Therefore we should check this. Do it here instead
|
|
// of after the accept to save on network traffic.
|
|
//
|
|
ConnCount = InterlockedExchange(&CommConnCount, CommConnCount);
|
|
//if (ActSocks.fd_count >= FD_SETSIZE)
|
|
|
|
#ifdef WINSDBG
|
|
if (ConnCount >= 200)
|
|
{
|
|
DBGPRINT0(ERR,
|
|
"MonTcp: Connection limit of 200 reached. \n");
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
if (ConnCount >= FD_SETSIZE)
|
|
{
|
|
DBGPRINT1(ERR,
|
|
"MonTcp: Connection limit of %d reached. No accept being done\n",
|
|
FD_SETSIZE);
|
|
WINSEVT_LOG_D_M(ConnCount,
|
|
WINS_EVT_CONN_LIMIT_REACHED);
|
|
fLimitReached = TRUE;
|
|
}
|
|
#endif
|
|
|
|
DBGPRINT0(FLOW, "Going to do an accept now\n");
|
|
if ( (NewSock = accept(
|
|
Port,
|
|
(struct sockaddr *)pRemAdd,
|
|
&AddLen
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
if (WinsCnf.State_e != WINSCNF_E_TERMINATING)
|
|
{
|
|
WINSEVT_LOG_M(
|
|
Error,
|
|
WINS_EVT_WINSOCK_ACCEPT_ERR,
|
|
);
|
|
}
|
|
WinsThdPool.CommThds[0].fTaken = FALSE;
|
|
WinsMscTermThd(
|
|
(((Error == WSAEINTR) || (Error == WSAENOTSOCK)) ?
|
|
WINS_SUCCESS : WINS_FAILURE),
|
|
WINS_NO_DB_SESSION_EXISTS);
|
|
}
|
|
|
|
DBGPRINT1(FLOW, "New Sock value is (%d)\n", NewSock);
|
|
if (fLimitReached)
|
|
{
|
|
FUTURES("Move this into CommDisc -- add a flag to it to indicate abrupt stop")
|
|
struct linger Linger;
|
|
Linger.l_onoff = 0;
|
|
if (setsockopt(
|
|
NewSock,
|
|
SOL_SOCKET,
|
|
SO_DONTLINGER,
|
|
(char *)&Linger,
|
|
sizeof(Linger)) == SOCKET_ERROR)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(ERR,
|
|
"MonTcp: SetSockOpt failed", Error);
|
|
}
|
|
fLimitReached = FALSE;
|
|
CommDisc(NewSock, FALSE); //close the socket
|
|
continue;
|
|
}
|
|
|
|
FD_SET(NewSock, &ActSocks);
|
|
InterlockedIncrement(&CommConnCount);
|
|
#ifdef WINSDBG
|
|
/*
|
|
* Let us see if the assoc. is there or not. It shouldn't be
|
|
* but let us check anyway (robust programming).
|
|
*/
|
|
pAssocCtx = CommAssocLookupAssoc( NewSock );
|
|
|
|
if (!pAssocCtx)
|
|
{
|
|
#endif
|
|
pAssocCtx = CommAssocCreateAssocInTbl(NewSock);
|
|
|
|
if (!pAssocCtx)
|
|
{
|
|
WINSEVT_LOG_D_M(
|
|
WINS_OUT_OF_MEM,
|
|
WINS_EVT_CANT_ALLOC_RSP_ASSOC,
|
|
);
|
|
WinsMscTermThd(WINS_FAILURE, WINS_NO_DB_SESSION_EXISTS);
|
|
}
|
|
|
|
#ifdef WINSDBG
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT0(ERR, "MonTcp: Not a new assoc. Weird\n");
|
|
|
|
//
|
|
// log an error (Cleanup was not done properly)
|
|
//
|
|
return(WINS_FAILURE);
|
|
|
|
}
|
|
#endif
|
|
pAssocCtx->State_e = COMMASSOC_ASSOC_E_NON_EXISTENT;
|
|
pAssocCtx->Role_e = COMMASSOC_ASSOC_E_RESPONDER;
|
|
pAssocCtx->DlgHdl.pEnt = NULL;
|
|
|
|
if (fConnTcp)
|
|
{
|
|
pAssocCtx->RemoteAdd.sin_addr.s_addr =
|
|
ntohl(fsin.sin_addr.s_addr);
|
|
pAssocCtx->AddTyp_e = COMM_ADD_E_TCPUDPIP;
|
|
}
|
|
#if SPX > 0
|
|
else
|
|
{
|
|
RtlCopyMemory(
|
|
pAssocCtx->RemoteAddSpx.sa_netnum,
|
|
fsipx.netnum,
|
|
sizeof(fsipx.netnum);
|
|
RtlCopyMemory(
|
|
pAssocCtx->RemoteAddSpx.sa_nodenum,
|
|
fsipx.nodenum,
|
|
sizeof(fsipx.nodenum);
|
|
pAssocCtx->AddTyp_e = COMM_ADD_E_SPXIPX;
|
|
}
|
|
#endif
|
|
}
|
|
else /* one or more sockets has received data or a disconnect*/
|
|
{
|
|
|
|
#if MCAST > 0
|
|
|
|
if (CheckMcastSock(&ActSocks, &RdSocks) == TRUE)
|
|
{
|
|
continue;
|
|
}
|
|
#endif
|
|
//
|
|
// Check if the notification socket has data in it
|
|
// If yes, continue.
|
|
//
|
|
if (ChkNtfSock(&ActSocks, &RdSocks))
|
|
{
|
|
DBGPRINT0(FLOW,
|
|
"MonTcp: Notification socket had data in it\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Handle sockets that have been set. These could have
|
|
* been set either because there is data on them or
|
|
* due to disconnects.
|
|
*/
|
|
for(No = 0; No < RdSocks.fd_count; ++No)
|
|
{
|
|
|
|
SockNo = RdSocks.fd_array[No];
|
|
if (FD_ISSET(SockNo, &RdSocks))
|
|
{
|
|
BytesRead = 0;
|
|
fSockCl = FALSE;
|
|
|
|
DBGPRINT1(FLOW, "MonTcp: Socket (%d) was signaled. It has either data or a disconnect on it\n",
|
|
SockNo);
|
|
|
|
/*
|
|
* Socket has data on it or a disconnect. Call
|
|
* HandleMsg to handle either case
|
|
*/
|
|
(VOID)HandleMsg(SockNo, &BytesRead, &fSockCl);
|
|
|
|
/*
|
|
* if the socket was closed due to a stop message
|
|
* having been received, let us clean up the
|
|
* socket array
|
|
*/
|
|
if (fSockCl)
|
|
{
|
|
DBGPRINT1(FLOW, "MonTcp: Sock (%d) was closed\n",
|
|
SockNo);
|
|
FD_CLR(SockNo, &ActSocks);
|
|
}
|
|
else
|
|
{
|
|
|
|
/*
|
|
* if bytes read are 0, we have a disconnect
|
|
* All the processing for the disconnect should
|
|
* have been handled by HandleMsg. We just need
|
|
* to close the socket and update the socket
|
|
* array appropriately.
|
|
*/
|
|
|
|
if (BytesRead == 0)
|
|
{
|
|
DBGPRINT0(FLOW,
|
|
"MonTcp: Received a disconnect\n");
|
|
//CommDisc(SockNo, TRUE);
|
|
FD_CLR(SockNo, &ActSocks);
|
|
}
|
|
}
|
|
}
|
|
|
|
} //for (loop over all sockets)
|
|
|
|
} //else (one or more sockets has received data or a disconnect
|
|
} //else clause (if select () < 0)
|
|
} // while (TRUE) loop end
|
|
|
|
} // end of try {}
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DBGPRINTEXC("MONTCP");
|
|
WINSEVT_LOG_M(GetExceptionCode(), WINS_EVT_TCP_LISTENER_EXC);
|
|
|
|
#if 0
|
|
//
|
|
// Don't use WinsMscTermThd here
|
|
//
|
|
ExitThread(WINS_FAILURE);
|
|
#endif
|
|
}
|
|
goto LOOPTCP; //ugly but useful
|
|
|
|
UNREFERENCED_PARAMETER(NoOfSockReady);
|
|
|
|
// we should never hit this return
|
|
ASSERT(0);
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
DWORD
|
|
MonUdp(
|
|
LPVOID pArg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is the thread startup function for the UDP listener
|
|
thread. It monitors the UDP port for UDP messages.
|
|
|
|
Arguments:
|
|
pArg - Argument (not used)
|
|
|
|
Externals Used:
|
|
CommUDPPortHandle -- UDP port for the process
|
|
|
|
Called by:
|
|
ECommInit
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
register LPBYTE pBuffer;
|
|
struct sockaddr_in FromAdd;
|
|
int AddLen = sizeof(FromAdd);
|
|
register PCOMM_BUFF_HEADER_T pBuffHdr = NULL;
|
|
|
|
|
|
DWORD DataBuffLen;
|
|
tREM_ADDRESS *pRemAdd;
|
|
NTSTATUS NTStatus;
|
|
|
|
LOOP:
|
|
try {
|
|
while(TRUE)
|
|
{
|
|
|
|
//
|
|
// Allocate a buffer to get the datagram. This buffer is prefixed
|
|
// by the COMM_BUFF_HEADER_T and tREM_ADDRESS structure.
|
|
//
|
|
pBuffHdr = WinsMscHeapAlloc (
|
|
CommUdpBuffHeapHdl,
|
|
COMM_DATAGRAM_SIZE + sizeof(COMM_BUFF_HEADER_T)
|
|
+ COMM_NETBT_REM_ADD_SIZE
|
|
);
|
|
DBGPRINT2(HEAP, "MonUdp: HeapHdl = (%p), pBuffHdr=(%p)\n",
|
|
CommUdpBuffHeapHdl, pRemAdd);
|
|
|
|
|
|
|
|
|
|
pBuffHdr->Typ_e = COMM_E_UDP;
|
|
|
|
//
|
|
// Adjust pointer to point to the Remote address header
|
|
//
|
|
pRemAdd = (tREM_ADDRESS *)
|
|
((LPBYTE)pBuffHdr + sizeof(COMM_BUFF_HEADER_T));
|
|
|
|
DataBuffLen = COMM_DATAGRAM_SIZE + COMM_NETBT_REM_ADD_SIZE;
|
|
//
|
|
// Point to the data portion (passed to ParseMsg)
|
|
//
|
|
pBuffer = (LPBYTE)pRemAdd + COMM_NETBT_REM_ADD_SIZE;
|
|
|
|
//
|
|
// read a datagram prefixed with the address of the sender from
|
|
// nbt
|
|
//
|
|
NTStatus = DeviceIoCtrl(
|
|
&sNetbtRcvEvtHdl,
|
|
pRemAdd,
|
|
DataBuffLen,
|
|
IOCTL_NETBT_WINS_RCV
|
|
);
|
|
|
|
if (!NT_SUCCESS(NTStatus))
|
|
{
|
|
|
|
//
|
|
// log the message only if WINS is not terminating
|
|
//
|
|
if (WinsCnf.State_e != WINSCNF_E_TERMINATING)
|
|
|
|
{
|
|
//
|
|
// We do not log the message if the Netbt handle is NULL
|
|
// We can have a small window when the handle may be NULL
|
|
// This happens when we get an address/device change
|
|
// notification. WINS closes the old handle and opens
|
|
// a new one after such an event if the machine has a
|
|
// a valid address that WINS can bind with. The address
|
|
// notification can occur due to ipconfig /release and
|
|
// /renew or due to psched being installed/removed.
|
|
//
|
|
if (WinsCnfNbtHandle != NULL)
|
|
{
|
|
WINSEVT_LOG_D_M(
|
|
NTStatus,
|
|
WINS_EVT_NETBT_RECV_ERR
|
|
);
|
|
}
|
|
DBGPRINT1(ERR, "MonUdp: Status = (%x)\n", NTStatus);
|
|
WinsMscHeapFree( CommUdpBuffHeapHdl, pBuffHdr);
|
|
Sleep(0); //relinquish the processor
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
|
|
DBGPRINT0(ERR, "MonUdp, Exiting Thread\n");
|
|
|
|
|
|
WinsThdPool.CommThds[1].fTaken = FALSE;
|
|
#if TEST_HEAP > 0
|
|
WinsMscHeapDestroy(CommUdpBuffHeapHdl);
|
|
DBGPRINT0(ERR, "MonUdp: Destroyed udp buff heap\n");
|
|
WinsMscHeapDestroy(CommUdpDlgHeapHdl);
|
|
DBGPRINT0(ERR, "MonUdp: Destroyed udp dlg buff heap\n");
|
|
#endif
|
|
return(WINS_FAILURE);
|
|
}
|
|
}
|
|
#ifdef WINSDBG
|
|
++CommNoOfDgrms;
|
|
DBGPRINT1(FLOW, "UDP listener thread: Got datagram (from NETBT) no = (%d)\n", CommNoOfDgrms);
|
|
|
|
// DBGPRINT1(SPEC, "UDP listener thread: Got datagram (from NETBT) no = (%d)\n", CommNoOfDgrms);
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// NETBT returns the same code as is in winsock.h for the
|
|
// internet family. Also, port and IpAddress returned are
|
|
// in network order
|
|
//
|
|
FromAdd.sin_family = pRemAdd->Family;
|
|
FromAdd.sin_port = pRemAdd->Port;
|
|
FromAdd.sin_addr.s_addr = ntohl(pRemAdd->IpAddress);
|
|
|
|
// from now on the memory allocated for pBuffHdr is passed down the way so consider it handled there
|
|
// There is basically no chance to hit an exception (unless everything is really messed up - like no mem)
|
|
// in ParseMsg before having this buffer passed down to a different thread for processing.
|
|
pBuffHdr = NULL;
|
|
/*
|
|
* process message
|
|
*/
|
|
(void)ParseMsg(
|
|
pBuffer,
|
|
COMM_DATAGRAM_SIZE,
|
|
COMM_E_UDP,
|
|
&FromAdd,
|
|
NULL
|
|
);
|
|
|
|
} //end of while(TRUE)
|
|
|
|
} // end of try {..}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DWORD ExcCode = GetExceptionCode();
|
|
DBGPRINT1(EXC, "MonUdp: Got Exception (%X)\n", ExcCode);
|
|
if (ExcCode == STATUS_NO_MEMORY)
|
|
{
|
|
//
|
|
//If the exception is due to insufficient resources, it could
|
|
// mean that WINS is not able to keep up with the fast arrivel
|
|
// rate of the datagrams. In such a case drop the datagram.
|
|
//
|
|
WINSEVT_LOG_M( WINS_OUT_OF_HEAP, WINS_EVT_CANT_ALLOC_UDP_BUFF);
|
|
}
|
|
else
|
|
{
|
|
WINSEVT_LOG_M(ExcCode, WINS_EVT_UDP_LISTENER_EXC);
|
|
}
|
|
PERF("Check how many cycles try consumes. If negligeble, move try inside the")
|
|
PERF("the while loop")
|
|
#if 0
|
|
//Don't use WinsMscTermThd here
|
|
ExitThread(WINS_FAILURE);
|
|
#endif
|
|
} // end of exception
|
|
|
|
if (pBuffHdr != NULL)
|
|
WinsMscHeapFree(CommUdpBuffHeapHdl, pBuffHdr);
|
|
|
|
goto LOOP; //ugly but useful
|
|
|
|
//
|
|
// we should never hit this return
|
|
//
|
|
ASSERT(0);
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
|
|
VOID
|
|
HandleMsg(
|
|
IN SOCKET SockNo,
|
|
OUT LPLONG pBytesRead,
|
|
OUT LPBOOL pfSockCl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to read in a message or a disconnect from
|
|
a socket and handle either appropriately.
|
|
If there were no bytes received on the socket, tt
|
|
does the cleanup
|
|
|
|
The bytes read are handed to ProcTcpMsg function.
|
|
|
|
Arguments:
|
|
|
|
SockNo - Socket to read data from
|
|
pBytesRead - # of bytes that were read
|
|
fSockCl - whether the socket is in closed condition
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
|
|
MonTcp
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
MSG_T pMsg;
|
|
STATUS RetStat;
|
|
|
|
/*
|
|
* Read in the message from the socket
|
|
*/
|
|
// ---ft: 06/16/2000---
|
|
// The second parameter to the call below has to be TRUE (timed receive).
|
|
// If it is not so (it was FALSE before this moment) the following scenario
|
|
// could happen.
|
|
// An attacher creates a TCP socket and connects it to port 42 to any
|
|
// WINS server and then sends 4 or less bytes on that socket. He leaves the
|
|
// connection open (doesn't close the socket) and simply unplug his net cable.
|
|
// Then he kills his app. Although his end of the connection terminates, WINS
|
|
// will have no idea about that (since the cable is disconnected) and will
|
|
// remain blocked in the call below (CommReadStrea->RecvData->recv) indefinitely
|
|
//
|
|
// Consequences:
|
|
// - WINS will never be able again to listen on the TCP port 42: push/pull replication
|
|
// is brought down along with the consistency checking.
|
|
// - WINS will not be able to terminate gracefully (in case the administrator attempts
|
|
// to shut down the service and restart it) because the MonTcp thread is in a hung state
|
|
//
|
|
// The same could happen in more usual cases (not necesarily on an intenional attack):
|
|
// While sending Push notification (which happens quite often):
|
|
// 1) the pusher is powered down (power outage)
|
|
// 2) the pusher hits a PnP event like media disconnect or adapter disabled
|
|
// 3) some router is down between the pusher and the receiving WINS.
|
|
//
|
|
// With this fix the best we can do for now is to have MonTcp thread recover in 20mts.
|
|
// Even better would be to log an event.
|
|
RetStat = CommReadStream(
|
|
SockNo,
|
|
TRUE, //don't do timed recv
|
|
&pMsg,
|
|
pBytesRead
|
|
);
|
|
|
|
//
|
|
// if either RetStat is not WINS_SUCCESS or the number of bytes
|
|
// read are 0, we need to delete the association and close the
|
|
// socket. Further, we need to set *pfSockCl to TRUE to indicate
|
|
// to the caller (MonTcp) that it should get rid of the socket
|
|
// from its array of sockets.
|
|
//
|
|
if ((RetStat != WINS_SUCCESS) || (*pBytesRead == 0))
|
|
{
|
|
/*
|
|
* No bytes received. This means that it is a disconnect
|
|
* Let us get rid of the context associated with the socket
|
|
*/
|
|
DelAssoc(
|
|
SockNo,
|
|
NULL /* we don't have the ptr to assoc block*/
|
|
);
|
|
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
}
|
|
else // means (RetStat == WINS_SUCCESS) and (*pBytesRead > 0)
|
|
{
|
|
ASSERT(*pBytesRead > 0);
|
|
|
|
/*
|
|
* process the message
|
|
*/
|
|
ProcTcpMsg(
|
|
SockNo,
|
|
pMsg,
|
|
*pBytesRead,
|
|
pfSockCl
|
|
);
|
|
}
|
|
return;
|
|
} // HandleMsg()
|
|
|
|
|
|
STATUS
|
|
CommReadStream(
|
|
IN SOCKET SockNo,
|
|
IN BOOL fDoTimedRecv,
|
|
OUT PMSG_T ppMsg,
|
|
OUT LPLONG pBytesRead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads from a TCP socket. If there are no bytes
|
|
there, it means a disconnect was received on that socket.
|
|
|
|
Arguments:
|
|
SockNo - Socket to read data from
|
|
fDoTimedRecv - Whether timed receive should be done (set to TRUE only
|
|
if we are not sure whether data has arrived or not yet)
|
|
ppMsg - Buffer containing data that was read in
|
|
pBytesRead - Size of buffer
|
|
|
|
|
|
Return Value:
|
|
|
|
TBS
|
|
|
|
--*/
|
|
|
|
{
|
|
u_long MsgLen;
|
|
LONG BytesToRead;
|
|
INT Flags = 0; /*flags for recv call (PEEK and/or OOB).
|
|
* we want neither
|
|
*/
|
|
WINS_MEM_T WinsMem[2];
|
|
PWINS_MEM_T pWinsMem = WinsMem;
|
|
STATUS RetStat;
|
|
PCOMM_BUFF_HEADER_T pBuffHdr;
|
|
|
|
DBGENTER("CommReadStream\n");
|
|
pWinsMem->pMem = NULL;
|
|
|
|
#ifdef WINSDBG
|
|
try {
|
|
#endif
|
|
|
|
/*
|
|
* All TCP messages are preceded by a length word (4 bytes) that
|
|
* gives the length of the message that follows. Read the length
|
|
* bytes.
|
|
*/
|
|
RetStat = RecvData(
|
|
SockNo,
|
|
(LPBYTE)&MsgLen,
|
|
sizeof(u_long),
|
|
Flags,
|
|
fDoTimedRecv ? TWENTY_MTS : fDoTimedRecv,
|
|
pBytesRead
|
|
);
|
|
|
|
|
|
/*
|
|
* Check if there was an error in reading. We will have a RetStat
|
|
* of WINS_SUCCESS even if 0 bytes (meaning a disconnect) were read
|
|
* in
|
|
*/
|
|
if (RetStat == WINS_SUCCESS)
|
|
{
|
|
if (*pBytesRead != 0)
|
|
{
|
|
COMM_NET_TO_HOST_L_M(MsgLen, MsgLen);
|
|
|
|
//
|
|
// Just making sure that the message length did not get
|
|
// corrupted on the way. Also, this is a good guard against
|
|
// a process that is trying to bring us down.
|
|
//
|
|
if (MsgLen <= MAX_BYTES_IN_MSG)
|
|
{
|
|
/*
|
|
* Allocate memory for the buffer. Allocate extra space
|
|
* at the top to store the Header for the buffer. This
|
|
* header is used to store information about the buffer.
|
|
* (See ECommFreeBuff also)
|
|
*/
|
|
*ppMsg = WinsMscHeapAlloc(
|
|
CommAssocTcpMsgHeapHdl,
|
|
MsgLen +
|
|
#if USENETBT > 0
|
|
COMM_NETBT_REM_ADD_SIZE +
|
|
#endif
|
|
sizeof(COMM_BUFF_HEADER_T) + sizeof(LONG)
|
|
);
|
|
//
|
|
// if *ppMsg is NULL, it means that we received garabage
|
|
// in the first 4 bytes. It should have been the length
|
|
// of the message.
|
|
//
|
|
if (*ppMsg == NULL)
|
|
{
|
|
//
|
|
// return with *pBytesRead = 0
|
|
//
|
|
*pBytesRead = 0;
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
pWinsMem->pMem = *ppMsg;
|
|
(++pWinsMem)->pMem = NULL;
|
|
|
|
/*
|
|
* Increment pointer past the buffer header and field
|
|
* storing the length of the message.
|
|
*/
|
|
pBuffHdr = (PCOMM_BUFF_HEADER_T)(*ppMsg + sizeof(LONG));
|
|
*ppMsg = *ppMsg +
|
|
#if USENETBT > 0
|
|
COMM_NETBT_REM_ADD_SIZE +
|
|
#endif
|
|
sizeof(COMM_BUFF_HEADER_T) + sizeof(LONG);
|
|
#if 0
|
|
pBuffHdr =
|
|
(PCOMM_BUFF_HEADER_T)(*ppMsg - sizeof(COMM_BUFF_HEADER_T));
|
|
#endif
|
|
|
|
pBuffHdr->Typ_e = COMM_E_TCP; //store type of buffer info
|
|
BytesToRead = MsgLen;
|
|
|
|
/*
|
|
* Read the whole message into the allocated buffer
|
|
*/
|
|
RetStat = RecvData(
|
|
SockNo,
|
|
*ppMsg,
|
|
BytesToRead,
|
|
Flags,
|
|
fDoTimedRecv ? FIVE_MTS : fDoTimedRecv,
|
|
pBytesRead
|
|
);
|
|
//
|
|
// If no bytes were read, deallocate memory
|
|
//
|
|
if ((*pBytesRead == 0) || (RetStat != WINS_SUCCESS))
|
|
{
|
|
ECommFreeBuff(*ppMsg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(ERR, "CommReadStream: Message size (%x) is TOO BIG\n", MsgLen);
|
|
WINSEVT_LOG_M(MsgLen, WINS_EVT_MSG_TOO_BIG);
|
|
*pBytesRead = 0;
|
|
}
|
|
}
|
|
} // if (RetStat == WINS_SUCCESS)
|
|
#ifdef WINSDBG
|
|
else
|
|
{
|
|
//
|
|
// *pBytesRead = 0 is a valid condition. It indicates a
|
|
// disconnect from the remote WINS
|
|
//
|
|
}
|
|
#endif
|
|
#ifdef WINSDBG
|
|
} // end of try { .. }
|
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|
DBGPRINTEXC("CommReadStream");
|
|
WINS_HDL_EXC_M(WinsMem);
|
|
WINS_RERAISE_EXC_M();
|
|
}
|
|
#endif
|
|
DBGLEAVE("CommReadStream\n");
|
|
return(RetStat);
|
|
} //CommReadStream()
|
|
|
|
|
|
VOID
|
|
ProcTcpMsg(
|
|
IN SOCKET SockNo,
|
|
IN MSG_T pMsg,
|
|
IN MSG_LEN_T MsgLen,
|
|
OUT LPBOOL pfSockCl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function processes a TCP message after it has been read in
|
|
Arguments:
|
|
SockNo - Socket on which data was received
|
|
pMsg - Buffer containing data
|
|
MsgLen - Size of buffer
|
|
pfSockCl - Flag indicating whether the socket was closed
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
HandleMsg
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
#if SUPPORT612WINS > 0
|
|
BYTE AssocMsg[COMMASSOC_POST_BETA1_ASSOC_MSG_SIZE];
|
|
#else
|
|
BYTE AssocMsg[COMMASSOC_ASSOC_MSG_SIZE];
|
|
#endif
|
|
|
|
DWORD Opc;
|
|
DWORD MsgTyp;
|
|
DWORD MsgSz = sizeof(AssocMsg);
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx;
|
|
BOOL fAssocAV = FALSE;
|
|
|
|
DBGENTER("ProcTcpMsg\n");
|
|
|
|
//#ifdef WINSDBG
|
|
try {
|
|
//#endif
|
|
|
|
/*
|
|
Get the opcode and check whether it is an NBT message or a
|
|
message from a WINSS.
|
|
*/
|
|
if (NMSISNBT_M(pMsg))
|
|
{
|
|
/*
|
|
* Get the assoc. ctx block associated with the socket
|
|
*/
|
|
if ( (pAssocCtx = CommAssocLookupAssoc(SockNo) ) == NULL )
|
|
{
|
|
ECommFreeBuff(pMsg);
|
|
WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_CANT_LOOKUP_ASSOC);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
|
|
if (pAssocCtx->DlgHdl.pEnt == NULL)
|
|
{
|
|
pDlgCtx = CommAssocAllocDlg();
|
|
|
|
//
|
|
// The following will initialize the dlg and assoc ctx
|
|
// blocks. The association will be marked ACTIVE.
|
|
//
|
|
COMMASSOC_SETUP_COMM_DS_M(
|
|
pDlgCtx,
|
|
pAssocCtx,
|
|
COMM_E_NBT,
|
|
COMMASSOC_DLG_E_IMPLICIT
|
|
);
|
|
}
|
|
|
|
/*
|
|
* Parse the message
|
|
*/
|
|
ParseMsg(
|
|
pMsg,
|
|
MsgLen,
|
|
pAssocCtx->Typ_e,
|
|
&pAssocCtx->RemoteAdd,
|
|
pAssocCtx
|
|
);
|
|
}
|
|
else /*message from WINS */
|
|
{
|
|
ULONG uLocalAssocCtx;
|
|
|
|
COMM_GET_HEADER_M(pMsg, Opc, uLocalAssocCtx, MsgTyp);
|
|
|
|
DBGPRINT1(REPL,"ProcTcpMsg: Got Wins msg with tag %08x.\n", uLocalAssocCtx);
|
|
|
|
pAssocCtx = (PCOMMASSOC_ASSOC_CTX_T)CommAssocTagMap(&sTagAssoc, uLocalAssocCtx);
|
|
|
|
/*
|
|
If the ptr to my assoc. ctx block is NULL, it means that
|
|
this is the "start asssoc req" message from the remote WINS.
|
|
|
|
We don't need to check MsgTyp but are doing it anyway for more
|
|
robust error checking
|
|
*/
|
|
if ((pAssocCtx == NULL) && (MsgTyp == COMM_START_REQ_ASSOC_MSG))
|
|
{
|
|
|
|
/*
|
|
Get the assoc. ctx block associated with the socket
|
|
*/
|
|
|
|
if ( (pAssocCtx = CommAssocLookupAssoc(SockNo)) == NULL )
|
|
{
|
|
ECommFreeBuff(pMsg);
|
|
WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_CANT_LOOKUP_ASSOC);
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
/*
|
|
Unformat the assoc. message. This function will return
|
|
with an error status if the message received is not
|
|
a start assoc. message.
|
|
*/
|
|
CommAssocUfmStartAssocReq(
|
|
pMsg,
|
|
&pAssocCtx->Typ_e,
|
|
&pAssocCtx->MajVersNo,
|
|
&pAssocCtx->MinVersNo,
|
|
&pAssocCtx->uRemAssocCtx
|
|
);
|
|
|
|
#if SUPPORT612WINS > 0
|
|
if (MsgLen >= (COMMASSOC_POST_BETA1_ASSOC_MSG_SIZE - sizeof(LONG)))
|
|
{
|
|
pAssocCtx->MajVersNo = WINS_BETA2_MAJOR_VERS_NO;
|
|
}
|
|
#endif
|
|
//
|
|
// Free the buffer read in.
|
|
//
|
|
ECommFreeBuff(pMsg);
|
|
|
|
/*
|
|
check if association set up params specified in the
|
|
message are acceptable.
|
|
*/
|
|
//
|
|
// if the version numbers do not match, terminate the association
|
|
// and log a message
|
|
//
|
|
#if SUPPORT612WINS > 0
|
|
if (pAssocCtx->MajVersNo != WINS_BETA2_MAJOR_VERS_NO)
|
|
{
|
|
#endif
|
|
if (pAssocCtx->MajVersNo != WINS_MAJOR_VERS)
|
|
{
|
|
|
|
DelAssoc(0, pAssocCtx);
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
//CommDecConnCount();
|
|
WINSEVT_LOG_M(pAssocCtx->MajVersNo, WINS_EVT_VERS_MISMATCH);
|
|
DBGLEAVE("ProcTcpMsg\n");
|
|
return;
|
|
}
|
|
#if SUPPORT612WINS > 0
|
|
}
|
|
#endif
|
|
|
|
FUTURES("When we support more sophisticated association set up protocol")
|
|
FUTURES("we will check the params. A more sophisticated set up protocol")
|
|
FUTURES("is one where there is some negotiation going one. Backward")
|
|
FUTURES("compatibility is another item which would require it")
|
|
|
|
/*
|
|
* Format a start assoc. response message.
|
|
*
|
|
* The address passed to the formatting function is offset
|
|
* from the address of the buffer by a LONG so that
|
|
* CommSendAssoc can store the length of the message in it.
|
|
*/
|
|
CommAssocFrmStartAssocRsp(
|
|
pAssocCtx,
|
|
AssocMsg + sizeof(LONG),
|
|
MsgSz - sizeof(LONG)
|
|
);
|
|
|
|
|
|
CommSendAssoc(
|
|
pAssocCtx->SockNo,
|
|
AssocMsg + sizeof(LONG),
|
|
MsgSz - sizeof(LONG)
|
|
);
|
|
|
|
|
|
//
|
|
// Allocate the dlg and initialize the assoc and dlg ctx blocks.
|
|
// The association is marked ACTIVE
|
|
//
|
|
pDlgCtx = CommAssocAllocDlg();
|
|
COMMASSOC_SETUP_COMM_DS_M(
|
|
pDlgCtx,
|
|
pAssocCtx,
|
|
pAssocCtx->Typ_e,
|
|
COMMASSOC_DLG_E_IMPLICIT
|
|
);
|
|
|
|
}
|
|
else /*the assoc has to be in the ACTIVE state */
|
|
{
|
|
|
|
/*
|
|
Let us check that this is not the stop assoc message
|
|
*/
|
|
if (MsgTyp == COMM_STOP_REQ_ASSOC_MSG)
|
|
{
|
|
|
|
fAssocAV = TRUE;
|
|
DelAssoc(0, pAssocCtx);
|
|
fAssocAV = FALSE;
|
|
ECommFreeBuff(pMsg);
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
//CommDecConnCount();
|
|
}
|
|
else
|
|
{
|
|
PERF("Remove this test")
|
|
CHECK("Is there any need for this test")
|
|
fAssocAV = TRUE;
|
|
if (pAssocCtx->State_e == COMMASSOC_ASSOC_E_NON_EXISTENT)
|
|
{
|
|
fAssocAV = FALSE;
|
|
ECommFreeBuff(pMsg);
|
|
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_BAD_STATE_ASSOC);
|
|
DelAssoc(0, pAssocCtx);
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
// CommDecConnCount();
|
|
WINS_RAISE_EXC_M(WINS_EXC_BAD_STATE_ASSOC);
|
|
}
|
|
else
|
|
{
|
|
fAssocAV = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Parse the message header to determine what message it is.
|
|
*/
|
|
ParseMsg(
|
|
pMsg,
|
|
MsgLen,
|
|
pAssocCtx->Typ_e,
|
|
&pAssocCtx->RemoteAdd, //not used
|
|
pAssocCtx
|
|
);
|
|
} //else (msg is not stop assoc msg)
|
|
} //else (assoc is active)
|
|
} // else (message is from a remote wins
|
|
//#ifdef WINSDBG
|
|
} // end of try block
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
DWORD ExcCode = GetExceptionCode();
|
|
FUTURES("Distinguish between different exceptions. Handle some. Reraise others")
|
|
DBGPRINT1(EXC, "ProcTcpMsg: Got Exception (%x)\n", ExcCode);
|
|
WINSEVT_LOG_D_M(ExcCode, WINS_EVT_SFT_ERR);
|
|
if (ExcCode == WINS_EXC_COMM_FAIL)
|
|
{
|
|
DelAssoc(0, pAssocCtx);
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
// CommDecConnCount();
|
|
}
|
|
if (fAssocAV)
|
|
{
|
|
ECommFreeBuff(pMsg);
|
|
// Without the following the assoc and the tcp connection
|
|
// will stay until either the tcp connection gets a valid
|
|
// message (one with the correct pAssocCtx) or it gets
|
|
// terminated
|
|
#if 0
|
|
DelAssoc(SockNo, NULL);
|
|
CommDisc(SockNo, TRUE);
|
|
*pfSockCl = TRUE;
|
|
// CommDecConnCount();
|
|
#endif
|
|
}
|
|
|
|
// WINS_RERAISE_EXC_M();
|
|
}
|
|
//#endif
|
|
|
|
|
|
DBGLEAVE("ProcTcpMsg\n");
|
|
return;
|
|
} //ProcTcpMsg()
|
|
|
|
VOID
|
|
CommCreateTcpThd(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function creates the TCP listener thread
|
|
|
|
Arguments:
|
|
None
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
CommInit
|
|
|
|
Comments:
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
CreateThd(MonTcp, WINSTHD_E_TCP);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
CommCreateUdpThd(VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function creates the UDP listener thread
|
|
|
|
Arguments:
|
|
None
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
CommInit
|
|
|
|
Comments:
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
CreateThd(MonUdp, WINSTHD_E_UDP);
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CreateThd(
|
|
DWORD (*pStartFunc)(LPVOID),
|
|
WINSTHD_TYP_E ThdTyp_e
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates a COMSYS thread and initializes the
|
|
context for it.
|
|
|
|
Arguments:
|
|
pStartFunc -- address of startup function for the thread
|
|
ThdTyp_e -- Type of thread (TCP listener or UDP listener)
|
|
|
|
|
|
Externals Used:
|
|
WinsThdPool
|
|
|
|
Called by:
|
|
CommCreateTCPThd, CommCreateUDPThd
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
|
|
HANDLE ThdHandle;
|
|
DWORD ThdId;
|
|
INT No;
|
|
|
|
/*
|
|
Create a thread with no sec attributes (i.e. it will take the
|
|
security attributes of the process), and default stack size
|
|
*/
|
|
|
|
ThdHandle = WinsMscCreateThd(
|
|
pStartFunc,
|
|
NULL, /*no arg*/
|
|
&ThdId
|
|
);
|
|
|
|
|
|
FUTURES("Improve the following to remove knowledge of # of threads in commsys")
|
|
/*
|
|
Grab the first slot for comm threads (2 slots in total) if available.
|
|
Else, use the second one. Initialize the thread context block
|
|
*/
|
|
No = (WinsThdPool.CommThds[0].fTaken == FALSE) ? 0 : 1;
|
|
{
|
|
|
|
WinsThdPool.CommThds[No].fTaken = TRUE;
|
|
WinsThdPool.CommThds[No].ThdId = ThdId;
|
|
WinsThdPool.CommThds[No].ThdHdl = ThdHandle;
|
|
WinsThdPool.CommThds[No].ThdTyp_e = ThdTyp_e;
|
|
}
|
|
|
|
WinsThdPool.ThdCount++;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
STATUS
|
|
CommConnect(
|
|
IN PCOMM_ADD_T pHostAdd,
|
|
IN SOCKET Port,
|
|
OUT SOCKET *pSockNo
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This function creates a TCP connection to a destination host
|
|
|
|
Arguments:
|
|
pHostAdd --pointer to Host's address
|
|
Port -- Port number to connect to
|
|
pSockNo -- ptr to a Socket variable
|
|
|
|
|
|
Called by:
|
|
|
|
Externals Used:
|
|
|
|
Return Value:
|
|
|
|
TBS
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//struct sockaddr_in sin; //*Internet endpoint address
|
|
DWORD ConnCount;
|
|
|
|
ConnCount = InterlockedExchange(&CommConnCount, CommConnCount);
|
|
#ifdef WINSDBG
|
|
if (ConnCount >= 200)
|
|
{
|
|
DBGPRINT0(ERR,
|
|
"MonTcp: Connection limit of 200 reached. \n");
|
|
}
|
|
#endif
|
|
#if 0
|
|
if (ConnCount >= FD_SETSIZE)
|
|
{
|
|
DBGPRINT2(EXC, "CommConnect: Socket Limit reached. Current no = (%d). Connection not being made to WINS. Address faimly of WINS is (%s)\n",
|
|
ConnCount,
|
|
pHostAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP ? "TCPIP" : "SPXIPX"
|
|
);
|
|
WINSEVT_LOG_D_M(ConnCount, WINS_EVT_CONN_LIMIT_REACHED);
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
#endif
|
|
|
|
#if SPX == 0
|
|
if (CommTcp(pHostAdd, Port, pSockNo) != WINS_SUCCESS)
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
#else
|
|
if (pHostAdd->AddTyp_e == COMM_ADD_E_TCPUDPIP)
|
|
{
|
|
if (CommTcp(pHostAdd, Port, pSockNo) != WINS_SUCCESS)
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (CommSpx(pHostAdd, Port, pSockNo) != WINS_SUCCESS)
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
}
|
|
//
|
|
#endif
|
|
// Connection has been made. Let us increment the connection count
|
|
//
|
|
InterlockedIncrement(&CommConnCount);
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
STATUS
|
|
CommTcp(
|
|
IN PCOMM_ADD_T pHostAdd,
|
|
IN SOCKET Port,
|
|
OUT SOCKET *pSockNo
|
|
)
|
|
{
|
|
|
|
struct sockaddr_in destsin; //*Internet endpoint address
|
|
struct sockaddr_in srcsin;
|
|
// DWORD ConnCount;
|
|
|
|
if (pHostAdd->Add.IPAdd == INADDR_NONE)
|
|
{
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Create a TCP socket and connect it to the target host
|
|
//
|
|
if ((*pSockNo = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
|
|
{
|
|
WINSEVT_LOG_M(
|
|
WSAGetLastError(),
|
|
WINS_EVT_CANT_CREATE_TCP_SOCK_FOR_CONN
|
|
);
|
|
return(WINS_FAILURE);
|
|
|
|
}
|
|
|
|
if (WinsClusterIpAddress) {
|
|
WINSMSC_FILL_MEMORY_M(&srcsin, sizeof(srcsin), 0);
|
|
srcsin.sin_addr.s_addr = htonl(WinsClusterIpAddress);
|
|
srcsin.sin_family = PF_INET;
|
|
srcsin.sin_port = 0;
|
|
|
|
if ( bind(*pSockNo,(struct sockaddr *)&srcsin,sizeof(srcsin)) == SOCKET_ERROR)
|
|
{
|
|
|
|
WINSEVT_LOG_M(WSAGetLastError(), WINS_EVT_WINSOCK_BIND_ERR); //log an event
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
FUTURES("May want to call setsockopt() on it to enable graceful close")
|
|
WINSMSC_FILL_MEMORY_M(&destsin, sizeof(destsin), 0);
|
|
destsin.sin_addr.s_addr = htonl(pHostAdd->Add.IPAdd);
|
|
destsin.sin_family = PF_INET;
|
|
destsin.sin_port = (u_short)htons((u_short)Port);
|
|
|
|
if (
|
|
connect(*pSockNo, (struct sockaddr *)&destsin, sizeof(destsin))
|
|
== SOCKET_ERROR
|
|
)
|
|
{
|
|
struct in_addr InAddr;
|
|
InAddr.s_addr = destsin.sin_addr.s_addr;
|
|
|
|
WinsEvtLogDetEvt(FALSE, WINS_EVT_WINSOCK_CONNECT_ERR,
|
|
NULL, __LINE__, "sd",
|
|
COMM_NETFORM_TO_ASCII_M(&InAddr),
|
|
WSAGetLastError());
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
|
|
return(WINS_SUCCESS);
|
|
}
|
|
|
|
#if SPX > 0
|
|
STATUS
|
|
CommSpx(
|
|
IN PCOMM_ADD_T pHostAdd,
|
|
IN SOCKET Port,
|
|
OUT SOCKET *pSockNo
|
|
)
|
|
{
|
|
struct sockaddr_ipx sipx; //*SPX/IPX endpoint address
|
|
LPVOID pRemAdd;
|
|
DWORD SizeOfRemAdd;
|
|
|
|
//
|
|
// Create an SPX socket and connect it to the target host
|
|
//
|
|
if ((*pSockNo = socket(PF_IPX, SOCK_STREAM, NSPROTO_SPX)) ==
|
|
INVALID_SOCKET)
|
|
{
|
|
WINSEVT_LOG_M(WSAGetLastError(),
|
|
WINS_EVT_CANT_CREATE_TCP_SOCK_FOR_CONN);
|
|
return(WINS_FAILURE);
|
|
|
|
}
|
|
WINSMSC_FILL_MEMORY_M(&sipx, sizeof(sipx), 0);
|
|
sipx.sa_socket = htons(Port);
|
|
sipx.sa_family = PF_IPX;
|
|
RtlCopyMemory(sipx.sa_netnum, pHostAdd->Add.netnum,
|
|
sizeof(pHostAdd->Add.netnum);
|
|
RtlCopyMemory(sipx.sa_nodenum, pHostAdd->Add.nodenum,
|
|
sizeof(pHostAdd->Add.nodenum);
|
|
|
|
|
|
FUTURES("May want to call setsockopt() on it to enable graceful close")
|
|
if (
|
|
connect(*pSockNo, (struct sockaddr *)&sipx, sizeof(sipx))
|
|
== SOCKET_ERROR
|
|
)
|
|
{
|
|
PERF("Pass address as binary data. Also log WSAGetLastError()")
|
|
|
|
WinsEvtLogDetEvt(FALSE, WINS_EVT_WINSOCK_CONNECT_ERR,
|
|
NULL, __LINE__, "sd",
|
|
sipx.sa_nodenum,
|
|
WSAGetLastError());
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
|
|
return(WINS_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
CommSend(
|
|
COMM_TYP_E CommTyp_e,
|
|
PCOMM_HDL_T pAssocHdl,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to send a TCP message to a WINS server or to
|
|
an nbt client
|
|
|
|
Arguments:
|
|
CommTyp_e - Type of communication
|
|
pAssocHdl - Handle to association to send message on
|
|
pMSg - Message to send
|
|
MsgLen - Length of above message
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
Replicator code
|
|
|
|
Comments:
|
|
This function should not be called for sending assoc messages.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
|
|
|
|
PCOMM_HEADER_T pCommHdr = NULL;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pAssocHdl->pEnt;
|
|
LPLONG pLong;
|
|
|
|
if (!CommLockBlock(pAssocHdl))
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_LOCK_ASSOC_ERR);
|
|
}
|
|
|
|
try {
|
|
/*
|
|
* If it is not an NBT message (i.e. it is a WINS message), we
|
|
* need to set the header appropriately
|
|
*/
|
|
if (CommTyp_e != COMM_E_NBT)
|
|
{
|
|
|
|
pCommHdr = (PCOMM_HEADER_T)(pMsg - COMM_HEADER_SIZE);
|
|
pLong = (LPLONG) pCommHdr;
|
|
|
|
COMM_SET_HEADER_M(
|
|
pLong,
|
|
WINS_IS_NOT_NBT,
|
|
pAssocCtx->uRemAssocCtx,
|
|
COMM_RPL_MSG
|
|
);
|
|
|
|
pMsg = (LPBYTE)pCommHdr;
|
|
MsgLen = MsgLen + COMM_HEADER_SIZE;
|
|
}
|
|
|
|
/*
|
|
send the message
|
|
*/
|
|
CommSendAssoc(
|
|
pAssocCtx->SockNo,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
|
|
}
|
|
finally {
|
|
|
|
CommUnlockBlock(pAssocHdl);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CommSendAssoc(
|
|
SOCKET SockNo,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to interface with the TCP/IP code for
|
|
sending a message on a TCP link
|
|
Arguments:
|
|
|
|
SockNo - Socket to send message on
|
|
pMsg - Message to send
|
|
MsgLen - Length of message to send
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
CommAssocSetUpAssoc
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
int Flags = 0; //flags to indicate OOB or DONTROUTE
|
|
INT Error;
|
|
int BytesSent;
|
|
LONG Len = MsgLen;
|
|
LPLONG pLong = (LPLONG)(pMsg - sizeof(LONG));
|
|
int NoOfBytesToSend;
|
|
|
|
|
|
|
|
//initialize the last four bytes with the length of
|
|
//the message
|
|
|
|
COMM_HOST_TO_NET_L_M(Len, Len);
|
|
*pLong = Len;
|
|
|
|
MsgLen = MsgLen + 4;
|
|
|
|
|
|
while(MsgLen > 0)
|
|
{
|
|
|
|
//
|
|
// Since send(...) takes an int for the size of the message, let us
|
|
// be conservative (since int could be different on different
|
|
// machines) and not specify anything larger than MAXUSHORT.
|
|
//
|
|
// This strategy is also prudent since winsock may not work
|
|
// properly for sizes > 64K
|
|
//
|
|
if ( MsgLen > MAXUSHORT)
|
|
{
|
|
NoOfBytesToSend = MAXUSHORT;
|
|
}
|
|
else
|
|
{
|
|
NoOfBytesToSend = MsgLen;
|
|
}
|
|
|
|
BytesSent = send(
|
|
SockNo,
|
|
(LPBYTE)pLong,
|
|
NoOfBytesToSend,
|
|
Flags
|
|
);
|
|
|
|
if (BytesSent == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
|
|
if (
|
|
(Error == WSAENOTCONN) ||
|
|
(Error == WSAECONNRESET) ||
|
|
(Error == WSAECONNABORTED) ||
|
|
(Error == WSAEDISCON)
|
|
|
|
)
|
|
{
|
|
DBGPRINT1(ERR, "CommSendAssoc: send returned SOCKET_ERROR due to connection abortion or reset. Error = (%d) \n", Error);
|
|
|
|
WINSEVT_LOG_D_M(
|
|
Error,
|
|
WINS_EVT_WINSOCK_SEND_MSG_ERR
|
|
);
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
// break;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
DBGPRINT1(ERR, "CommSendAssoc: send returned SOCKET_ERROR due to severe error = (%d) \n", Error);
|
|
//
|
|
// Some severe error. Raise an exception. We
|
|
// don't want the caller to ignore this.
|
|
//
|
|
WINSEVT_LOG_M(Error, WINS_EVT_WINSOCK_SEND_ERR);
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (BytesSent < NoOfBytesToSend)
|
|
{
|
|
|
|
DBGPRINT2(ERR, "CommSendAssoc: Bytes Sent (%d) are < Specified (%d)\n", BytesSent, NoOfBytesToSend);
|
|
WINSEVT_LOG_D_M(BytesSent, WINS_EVT_WINSOCK_SEND_MSG_ERR);
|
|
|
|
|
|
/*
|
|
* The connection could have gone down because of the
|
|
* other side aborting in the middle
|
|
*
|
|
* We should log an error but not raise an exception.
|
|
*/
|
|
//WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
WINS_RAISE_EXC_M(WINS_EXC_COMM_FAIL);
|
|
// break;
|
|
|
|
}
|
|
else //BytesSent == NoOfBytesToSend
|
|
{
|
|
//
|
|
// Let us update the length left and the pointer into the
|
|
// buffer to send.
|
|
//
|
|
MsgLen -= BytesSent;
|
|
pLong = (LPLONG)((LPBYTE)pLong + BytesSent);
|
|
}
|
|
|
|
}
|
|
}
|
|
return;
|
|
} // CommSendAssoc()
|
|
|
|
|
|
VOID
|
|
CommDisc(
|
|
SOCKET SockNo,
|
|
BOOL fDecCnt
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function closes the connection (socket)
|
|
|
|
Arguments:
|
|
SockNo - Socket that needs to be disconnected
|
|
|
|
Externals Used:
|
|
|
|
None
|
|
|
|
Called by:
|
|
MonTcp, HandleMsg, ProcTcpMsg, CommEndAssoc
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
|
|
DBGPRINT1(FLOW, "CommDisc: Closing socket = (%d)\n", SockNo);
|
|
|
|
if (closesocket(SockNo) == SOCKET_ERROR)
|
|
{
|
|
WINSEVT_LOG_M(WSAGetLastError(),
|
|
WINS_EVT_WINSOCK_CLOSESOCKET_ERR);
|
|
//WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
#ifdef WINSDBG
|
|
if (!sfMemoryOverrun)
|
|
{
|
|
if ((UINT_PTR)(pTmpW + 2) < (UINT_PTR)pEndPtr)
|
|
{
|
|
*pTmpW++ = 0xEFFFFFFE;
|
|
*pTmpW++ = SockNo;
|
|
}
|
|
else
|
|
{
|
|
WinsDbg |= 0x3;
|
|
DBGPRINT0(ERR, "CommDisc: Stopping socket close tracking to prevent Memory overrun\n")
|
|
sfMemoryOverrun = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (fDecCnt)
|
|
{
|
|
CommDecConnCount();
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
CommSendUdp (
|
|
SOCKET SockNo,
|
|
struct sockaddr_in *pDest,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This function is called to send a message to an NBT node using the
|
|
datagram port
|
|
|
|
Arguments:
|
|
|
|
SockNo - Socket to send message on (UDP port)
|
|
pDest - Address of node to send message to
|
|
pMsg - Message to send
|
|
MsgLen - Length of message to send
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Called by:
|
|
|
|
NmsNmh functions
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
DWORD BytesSent;
|
|
DWORD Error;
|
|
int Flags = 0;
|
|
struct sockaddr_in CopyOfDest;
|
|
|
|
#if USENETBT > 0
|
|
//
|
|
// When the address to send the datagram to is CommNtfSockAdd, we
|
|
// use sockets, else we send it over NETBT.
|
|
//
|
|
#if MCAST > 0
|
|
if ((pDest != &CommNtfSockAdd) && (SockNo != CommUdpPortHandle))
|
|
#else
|
|
if (pDest != &CommNtfSockAdd)
|
|
#endif
|
|
{
|
|
SendNetbt(pDest, pMsg, MsgLen);
|
|
return;
|
|
}
|
|
#endif
|
|
//
|
|
// use copy of the destination so that when we change the byte
|
|
// order in it, we don't disturb the source. This is important
|
|
// because CommSendUdp can be called multiple times by HdlPushNtf
|
|
// in the Push thread with pDest pointing to the address of the
|
|
// UDP socket used by the TCP listener thread. This address is
|
|
// in host byte order and should not be changed
|
|
//
|
|
CopyOfDest = *pDest;
|
|
|
|
CopyOfDest.sin_addr.s_addr = htonl(pDest->sin_addr.s_addr);
|
|
BytesSent = (DWORD)sendto(
|
|
SockNo,
|
|
pMsg,
|
|
MsgLen,
|
|
Flags,
|
|
(struct sockaddr *)&CopyOfDest,
|
|
sizeof(struct sockaddr)
|
|
);
|
|
|
|
if ((BytesSent != MsgLen) || (BytesSent == SOCKET_ERROR))
|
|
{
|
|
Error = WSAGetLastError();
|
|
#ifdef WINSDBG
|
|
if (BytesSent == SOCKET_ERROR)
|
|
{
|
|
DBGPRINT1(ERR, "CommSendUdp:SendTo returned socket error. Error = (%d)\n", Error);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT0(ERR, "CommSendUdp:SendTo did not send all the bytes");
|
|
|
|
}
|
|
#endif
|
|
if (WinsCnf.State_e != WINSCNF_E_TERMINATING)
|
|
{
|
|
WINSEVT_LOG_D_M(Error, WINS_EVT_WINSOCK_SENDTO_ERR);
|
|
}
|
|
|
|
//
|
|
// Don't raise exception since sendto might have failed as
|
|
// a result of wrong address in the RFC name request packet.
|
|
//
|
|
// For sending responses to name requests, there is no
|
|
// possibility of WINS using a wrong address since the
|
|
// address it uses is the one that it got from recvfrom
|
|
// (stored In FromAdd field of the dlg ctx block.
|
|
//
|
|
// The possibility of a wrong address being there is
|
|
// only there when a WACK/name query/name release is sent
|
|
// by WINS. In this case, it takes the address that is
|
|
// stored in the database for the conflicting entry (this
|
|
// address is ofcourse the one that was passed in the
|
|
// RFC packet
|
|
//
|
|
// WSAEINVAL error is returned by GetLastError if the
|
|
// address is invalid (winsock document doesn't list this --
|
|
// inform Dave Treadwell about this).
|
|
//
|
|
|
|
FUTURES("At name registration, should WINS make sure that the address in ")
|
|
FUTURES("the packet is the same as the address it got from recvfrom")
|
|
FUTURES("probably yes")
|
|
|
|
//WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if USENETBT > 0
|
|
VOID
|
|
SendNetbt (
|
|
struct sockaddr_in *pDest,
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to send a datagram through NETBT
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Point to the address structure prefix
|
|
//
|
|
tREM_ADDRESS *pRemAdd = (tREM_ADDRESS *)(pMsg -
|
|
COMM_NETBT_REM_ADD_SIZE);
|
|
|
|
#ifdef JIM
|
|
{
|
|
BYTE TransId = *pMsg;
|
|
ASSERT(TransId == 0x80);
|
|
}
|
|
#endif
|
|
|
|
pRemAdd->Family = pDest->sin_family;
|
|
pRemAdd->Port = pDest->sin_port;
|
|
pRemAdd->IpAddress = htonl(pDest->sin_addr.s_addr);
|
|
#ifdef JIM
|
|
ASSERT(MsgLen > 0x20);
|
|
#endif
|
|
pRemAdd->LengthOfBuffer = MsgLen;
|
|
DeviceIoCtrl(
|
|
&sNetbtSndEvtHdl,
|
|
pRemAdd,
|
|
MsgLen + COMM_NETBT_REM_ADD_SIZE,
|
|
IOCTL_NETBT_WINS_SEND
|
|
);
|
|
return;
|
|
}
|
|
#endif
|
|
VOID
|
|
ParseMsg(
|
|
MSG_T pMsg,
|
|
MSG_LEN_T MsgLen,
|
|
COMM_TYP_E MsgTyp_e,
|
|
struct sockaddr_in *pFromAdd,
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to process a message received on the
|
|
UDP port or a TCP connection.
|
|
|
|
Arguments:
|
|
pMsg - ptr to message received
|
|
MsgLen - length of message received
|
|
MsgType - type of message
|
|
pFromAdd - ptr to who it is from
|
|
pAssocHdl - Assoc Handle if it came on an association
|
|
|
|
Externals Used:
|
|
CommUdpNbtDlgTable
|
|
|
|
Called by:
|
|
ProcTcpMsg, MonUdp
|
|
|
|
Comments:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
--*/
|
|
{
|
|
|
|
COMM_HDL_T DlgHdl;
|
|
COMMASSOC_DLG_CTX_T DlgCtx;
|
|
register PCOMMASSOC_DLG_CTX_T pDlgCtx;
|
|
BOOL fNewElem = FALSE;
|
|
|
|
|
|
try {
|
|
/*
|
|
* If the assoc handle is NULL, this is a UDP message
|
|
*/
|
|
if (pAssocCtx == NULL)
|
|
{
|
|
|
|
/*
|
|
* Check if this message is a response. If it is, the explicit
|
|
* dialogue is used
|
|
*/
|
|
if (*(pMsg + 2) & NMS_RESPONSE_MASK)
|
|
{
|
|
ENmsHandleMsg(
|
|
&CommExNbtDlgHdl,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Initialize the STATIC dlg ctx block with the fields that the
|
|
* compare function will use to check if this is a duplicate
|
|
*/
|
|
WINSMSC_COPY_MEMORY_M(
|
|
&DlgCtx.FromAdd,
|
|
pFromAdd,
|
|
sizeof(struct sockaddr_in)
|
|
);
|
|
|
|
//
|
|
// Copy the first four bytes of the message into the FirstWrdOfMsg
|
|
// field of the Dlg Ctx block. The first 4 bytes contain the
|
|
// transaction id and the opcode. These values along with the
|
|
// address of the sender are used by CompareNbtReq to determine
|
|
// whether a request is a repeat request or a new one.
|
|
//
|
|
// Note: The message buffer and the dlg ctx block are deleted
|
|
// in different functions, the message buffer getting deleted
|
|
// first. We can not use the pointer to the message
|
|
// buffer for the purposes of getting at the first word at
|
|
// comparison time since then we open ourselves to the possibility
|
|
// of two dialogues pointing to the same block for a finite
|
|
// window (true, when requests are coming rapidly)
|
|
//
|
|
|
|
FUTURES("Directly assign the value instead of copying it")
|
|
WINSMSC_COPY_MEMORY_M(
|
|
&DlgCtx.FirstWrdOfMsg,
|
|
pMsg,
|
|
sizeof(DWORD)
|
|
);
|
|
|
|
|
|
/*
|
|
create and insert a dlg ctx block into the table of
|
|
NBT type Implicit dialogues. The key to searching for
|
|
a duplicate inside the table comprises of the Transaction Id
|
|
of the message, and the FromAdd of the nbt node that sent the
|
|
datagram.
|
|
(refer : CheckDlgDuplicate function).
|
|
|
|
*/
|
|
pDlgCtx = CommAssocInsertUdpDlgInTbl(&DlgCtx, &fNewElem);
|
|
|
|
if (pDlgCtx == NULL)
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_OUT_OF_MEM);
|
|
}
|
|
|
|
/*
|
|
* If the dialogue for the particular command from the nbt node is
|
|
* already there, we will ignore this request, deallocate the
|
|
* UDP buffer and return.
|
|
*/
|
|
if (!fNewElem)
|
|
{
|
|
DBGPRINT0(FLOW, "Not a new element\n");
|
|
ECommFreeBuff(pMsg);
|
|
#ifdef WINSDBG
|
|
CommNoOfRepeatDgrms++;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Initialize the dlg ctx block that got inserted
|
|
*/
|
|
pDlgCtx->Role_e = COMMASSOC_DLG_E_IMPLICIT;
|
|
pDlgCtx->Typ_e = COMM_E_UDP;
|
|
|
|
DlgHdl.pEnt = pDlgCtx;
|
|
|
|
/*
|
|
* Call name space manager to handle the request
|
|
*/
|
|
ENmsHandleMsg(&DlgHdl, pMsg, MsgLen);
|
|
}
|
|
else // the request came over an association
|
|
{
|
|
|
|
pDlgCtx = pAssocCtx->DlgHdl.pEnt;
|
|
|
|
//
|
|
// required by the PULL thread (HandlePushNtf).
|
|
// and the PUSH thread to print out the address of the WINS
|
|
// that sent the push trigger or the Pull request
|
|
//
|
|
WINSMSC_COPY_MEMORY_M(
|
|
&pDlgCtx->FromAdd,
|
|
pFromAdd,
|
|
sizeof(struct sockaddr_in)
|
|
);
|
|
|
|
/*
|
|
* The request came over a TCP connection. Examine the Dlg type
|
|
* and then call the appropriate component
|
|
*/
|
|
if (pAssocCtx->Typ_e == COMM_E_NBT)
|
|
{
|
|
|
|
/*
|
|
* It is an nbt request over a TCP connection. Call
|
|
* the Name Space Manager
|
|
*/
|
|
ENmsHandleMsg(
|
|
&pAssocCtx->DlgHdl,
|
|
pMsg,
|
|
MsgLen
|
|
);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Call the replicator component
|
|
*
|
|
* Note: pMsg points to COMM_HEADER_T on top of the
|
|
* data. We strip it off
|
|
*/
|
|
DBGIF(fWinsCnfRplEnabled)
|
|
ERplInsertQue(
|
|
WINS_E_COMSYS,
|
|
QUE_E_CMD_REPLICATE_MSG,
|
|
&pAssocCtx->DlgHdl,
|
|
pMsg + COMM_HEADER_SIZE,
|
|
MsgLen - COMM_HEADER_SIZE,
|
|
NULL, // no context
|
|
0 // no magic no.
|
|
);
|
|
}
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
DBGPRINTEXC("ParseMsg");
|
|
/*
|
|
* If this dialogue was allocated as a result of an Insert
|
|
* get rid of it.
|
|
*/
|
|
if (fNewElem)
|
|
{
|
|
CommAssocDeleteUdpDlgInTbl( pDlgCtx );
|
|
}
|
|
WINS_RERAISE_EXC_M();
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
LPVOID
|
|
CommAlloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN CLONG BuffSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to allocate a buffer
|
|
|
|
Arguments:
|
|
pTable - Table where the buffer will be stored
|
|
BuffSize - Size of buffer to allocate
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- ptr to buffer allocated
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
RtlInsertElementGeneric()
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
This function exists just because the RtlTbl functions require
|
|
this prototype for the user specified alloc function.
|
|
--*/
|
|
|
|
{
|
|
LPVOID pTmp;
|
|
|
|
UNREFERENCED_PARAMETER(pTable);
|
|
|
|
WinsMscAlloc( (DWORD) BuffSize, &pTmp );
|
|
|
|
return(pTmp);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
CommDealloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN PVOID pBuff
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to deallocate memory allocated via CommAlloc.
|
|
|
|
|
|
Arguments:
|
|
pTable - Table where buffer was stored
|
|
pBuff - Buffer to deallocate
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
The pTable argument is required since the address of this function
|
|
is passed as an argument to RtlTbl functions
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
UNREFERENCED_PARAMETER(pTable);
|
|
WinsMscDealloc(
|
|
pBuff
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
#if 0
|
|
RTL_GENERIC_COMPARE_RESULTS
|
|
CompareAssoc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN PVOID pFirstAssoc,
|
|
IN PVOID pSecondAssoc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function compares the first and the second assoc. structures
|
|
Arguments:
|
|
pTable - table where buffer (assoc. ctx block) is to be stored
|
|
pFirstAssoc - First assoc ctx block
|
|
pSecondAssoc - Second assoc ctx block
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
RtlInsertElementGenericTable (called by MonTcp)
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
The pTable argument is ignored.
|
|
This function was once being used. Due to change in code, it is
|
|
no longer being used. It is kept here for potential future use
|
|
--*/
|
|
{
|
|
|
|
PCOMMASSOC_ASSOC_CTX_T pFirst = pFirstAssoc;
|
|
PCOMMASSOC_ASSOC_CTX_T pSecond = pSecondAssoc;
|
|
|
|
if (pFirst->SockNo == pSecond->SockNo)
|
|
{
|
|
return(GenericEqual);
|
|
}
|
|
|
|
if (pFirst->SockNo > pSecond->SockNo)
|
|
{
|
|
return(GenericGreaterThan);
|
|
}
|
|
else
|
|
{
|
|
return(GenericLessThan);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
RTL_GENERIC_COMPARE_RESULTS
|
|
CommCompareNbtReq(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN PVOID pFirstDlg,
|
|
IN PVOID pSecondDlg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function compares two dialogue context blocks. The fields
|
|
used for comparison are:
|
|
the address of the sender
|
|
the first long word of the message (contains transaction id
|
|
and opcode)
|
|
|
|
Arguments:
|
|
pTable - Table where the Dialogue for the NBT request will be stored
|
|
pFirstDlg - Dlg. ctx. block
|
|
pSecondDlg - Dlg. ctx. block
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- GenericLessThan or GenericGreaterThan
|
|
Error status codes -- GenericEqual
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
RtlInsertElementGenericTable (called by ParseMsg)
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
The pTable argument is ignored.
|
|
--*/
|
|
{
|
|
|
|
PCOMMASSOC_DLG_CTX_T pFirst = pFirstDlg;
|
|
PCOMMASSOC_DLG_CTX_T pSecond = pSecondDlg;
|
|
LONG Val = 0;
|
|
LONG FirstMsgLong = pFirst->FirstWrdOfMsg;
|
|
LONG SecondMsgLong = pSecond->FirstWrdOfMsg;
|
|
|
|
//
|
|
// There seems to be no Rtl function with the functionality of memcmp
|
|
// RtlCompareMemory does not tell you which of the comparators is
|
|
// smaller/larger
|
|
//
|
|
CHECK("Is there an Rtl function faster than memcmp in the nt arsenal\n");
|
|
if ( (Val = (long)memcmp(
|
|
&pFirst->FromAdd,
|
|
&pSecond->FromAdd,
|
|
sizeof(struct sockaddr_in)
|
|
)
|
|
) > 0
|
|
)
|
|
{
|
|
return(GenericGreaterThan);
|
|
}
|
|
else
|
|
{
|
|
if (Val < 0)
|
|
{
|
|
return(GenericLessThan);
|
|
}
|
|
}
|
|
|
|
/*
|
|
if the addresses are the same, compare the first long word of
|
|
the message
|
|
*/
|
|
|
|
Val = FirstMsgLong - SecondMsgLong;
|
|
|
|
if (Val > 0)
|
|
{
|
|
return(GenericGreaterThan);
|
|
}
|
|
else
|
|
{
|
|
if (Val < 0)
|
|
{
|
|
return(GenericLessThan);
|
|
}
|
|
}
|
|
|
|
return(GenericEqual);
|
|
|
|
} // CommCompareNbtReq()
|
|
|
|
VOID
|
|
CommEndAssoc(
|
|
IN PCOMM_HDL_T pAssocHdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to terminate an explicit association. It sends a stop
|
|
association response message to the WINS identified by the Address
|
|
in the assoc ctx block. It then closes the socket and deallocates the
|
|
association
|
|
|
|
Arguments:
|
|
pAssocHdl - Handle to the Association to be terminated
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
ECommEndDlg (only for an explicit assoc)
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
|
|
--*/
|
|
{
|
|
|
|
BYTE Msg[COMMASSOC_ASSOC_MSG_SIZE];
|
|
DWORD MsgLen = COMMASSOC_ASSOC_MSG_SIZE;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pAssocHdl->pEnt;
|
|
SOCKET SockNo;
|
|
|
|
|
|
// no need to lock the association
|
|
//
|
|
try {
|
|
/*
|
|
Format the Stop Assoc. Message
|
|
|
|
The address passed to the formatting function is offset
|
|
from the address of the buffer by a LONG so that CommSendAssoc
|
|
can store the length of the message in it.
|
|
*/
|
|
CommAssocFrmStopAssocReq(
|
|
pAssocCtx,
|
|
Msg + sizeof(LONG),
|
|
MsgLen - sizeof(LONG),
|
|
COMMASSOC_E_USER_INITIATED
|
|
);
|
|
CommSendAssoc(
|
|
pAssocCtx->SockNo,
|
|
Msg + sizeof(LONG),
|
|
MsgLen - sizeof(LONG)
|
|
);
|
|
|
|
CommAssocTagFree(&sTagAssoc, pAssocCtx->nTag);
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER) {
|
|
DBGPRINTEXC("CommEndAssoc");
|
|
}
|
|
//
|
|
// The above call might have failed (It will fail if the connection
|
|
// is down. This can happen for instance in the case where GetReplicas()
|
|
// in rplpull gets a comm. failure due to the connection going down).
|
|
//
|
|
SockNo = pAssocCtx->SockNo;
|
|
|
|
CommAssocDeallocAssoc(pAssocCtx);
|
|
CommDisc(SockNo, TRUE);
|
|
//
|
|
// decrement the conn. count
|
|
//
|
|
//CommDecConnCount();
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
DelAssoc(
|
|
IN SOCKET SockNo,
|
|
IN PCOMMASSOC_ASSOC_CTX_T pAssocCtxPassed
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called only by the TCP listener thread. The
|
|
socket no. therefore maps to a RESPONDER association. The function
|
|
is called when the TCP listener thread gets an error or 0 bytes
|
|
on doing a 'recv'.
|
|
|
|
|
|
Arguments:
|
|
|
|
SockNo - Socket of association that has to be removed
|
|
pAssocCtx - Assoc. ctx block to be removed
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
ProcTcpMsg, HandleMsg
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
This function is called from HandleMsg() which is called
|
|
only by the TCP listener thread.
|
|
--*/
|
|
|
|
{
|
|
|
|
COMM_HDL_T DlgHdl;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
|
|
DBGPRINT1(FLOW, "ENTER: DelAssoc. Sock No is (%d)\n", SockNo);
|
|
if (pAssocCtxPassed == NULL)
|
|
{
|
|
|
|
/*
|
|
Lookup the assoc. ctx block associated with the socket
|
|
*/
|
|
|
|
pAssocCtx = CommAssocLookupAssoc(SockNo);
|
|
|
|
/*
|
|
* There is no reason why the assoc. ctx block should not
|
|
* be there (a responder association is deleted only via this
|
|
* function).
|
|
*/
|
|
if(!pAssocCtx)
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pAssocCtx = pAssocCtxPassed;
|
|
}
|
|
|
|
/*
|
|
* Only, if the association is not in the non-existent state,
|
|
* look for a dialogue handle
|
|
*/
|
|
if (pAssocCtx->State_e != COMMASSOC_ASSOC_E_NON_EXISTENT)
|
|
{
|
|
/*
|
|
* get the dialogue handle
|
|
*/
|
|
DlgHdl = pAssocCtx->DlgHdl;
|
|
|
|
/*
|
|
* Lock the dialogue
|
|
*
|
|
* We have to synchronize with thread calling CommSndRsp
|
|
*/
|
|
CommLockBlock(&pAssocCtx->DlgHdl);
|
|
|
|
/*
|
|
Remove the assoc. from the table. This will also put
|
|
the assoc. in the free list.
|
|
*/
|
|
CommAssocDeleteAssocInTbl( pAssocCtx );
|
|
|
|
/*
|
|
dealloc the dialogue (i.e. put it in the free list)
|
|
|
|
Note: An implicit dialogue is deleted when the association(s)
|
|
it is mapped to terminates. If this dialogue was earlier
|
|
passed on to a client, the client will find out that it
|
|
has been deleted (via a communications failure exception)
|
|
when it tries to use it (which may be never) -- see ECommSndRsp
|
|
*/
|
|
CommAssocDeallocDlg( DlgHdl.pEnt );
|
|
|
|
/*
|
|
Unlock the dialogue so that other threads can use it
|
|
*/
|
|
CommUnlockBlock(&DlgHdl);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Remove the assoc. from the table. This will also put
|
|
the assoc. in the free list
|
|
*/
|
|
CommAssocDeleteAssocInTbl(pAssocCtx);
|
|
|
|
}
|
|
|
|
DBGLEAVE("DelAssoc\n");
|
|
return;
|
|
}
|
|
|
|
#if PRSCONN
|
|
BOOL
|
|
CommIsBlockValid (
|
|
IN PCOMM_HDL_T pEntHdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to check if the hdl is valid
|
|
|
|
Arguments:
|
|
pEntHdl - Handle to entity to lock
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- TRUE
|
|
Error status codes -- FALSE
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// pEnt will be NULL for a persistent dlg that was never created during
|
|
// the lifetime of this WINS instance or one that was ended.
|
|
//
|
|
if (pEntHdl->pEnt == NULL)
|
|
{
|
|
ASSERT(pEntHdl->SeqNo == 0);
|
|
return (FALSE);
|
|
}
|
|
//
|
|
// If we can lock the block, the dlg hdl is still valid. If not, it means
|
|
// that the dlg was terminated earlier.
|
|
//
|
|
if (CommLockBlock(pEntHdl))
|
|
{
|
|
(VOID)CommUnlockBlock(pEntHdl);
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
CommLockBlock(
|
|
IN PCOMM_HDL_T pEntHdl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to lock the COMSYS entity identified by the
|
|
handle.
|
|
|
|
Arguments:
|
|
pEntHdl - Handle to entity to lock
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- TRUE
|
|
Error status codes -- FALSE
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
PCOMM_TOP_T pTop = pEntHdl->pEnt;
|
|
|
|
//lock before checking
|
|
|
|
#if 0
|
|
WinsMscWaitInfinite(pTop->MutexHdl);
|
|
#endif
|
|
EnterCriticalSection(&pTop->CrtSec);
|
|
if (pEntHdl->SeqNo == pTop->SeqNo)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
CommUnlockBlock(pEntHdl);
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
__inline
|
|
STATUS
|
|
CommUnlockBlock(
|
|
PCOMM_HDL_T pEntHdl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to unlock the COMSYS entity identified by the
|
|
handle.
|
|
|
|
Arguments:
|
|
pEntHdl - Handle to entity to unlock
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes -- WINS_FAILURE
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
FUTURES("Change to a macro")
|
|
#if 0
|
|
BOOL RetVal = TRUE;
|
|
BOOL RetStat = WINS_SUCCESS;
|
|
#endif
|
|
PCOMM_TOP_T pTop = pEntHdl->pEnt;
|
|
|
|
LeaveCriticalSection(&pTop->CrtSec);
|
|
#if 0
|
|
RetVal = ReleaseMutex(pTop->MutexHdl);
|
|
|
|
if (RetVal == FALSE)
|
|
{
|
|
RetStat = WINS_FAILURE;
|
|
}
|
|
#endif
|
|
return(WINS_SUCCESS);
|
|
|
|
}
|
|
|
|
VOID
|
|
InitMem(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to do all memory initialization required
|
|
by COMSYS.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
CommInit
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
{
|
|
|
|
|
|
/*
|
|
* Create Memory heap for UDP buffers
|
|
* We want mutual exclusion and generation of exceptions
|
|
*/
|
|
DBGPRINT0(HEAP_CRDL,"InitMem: Udp. Buff heap\n");
|
|
CommUdpBuffHeapHdl = WinsMscHeapCreate(
|
|
HEAP_GENERATE_EXCEPTIONS,
|
|
COMMASSOC_UDP_BUFFER_HEAP_SIZE
|
|
);
|
|
|
|
DBGPRINT0(HEAP_CRDL,"InitMem: Udp. Buff heap\n");
|
|
CommUdpDlgHeapHdl = WinsMscHeapCreate(
|
|
HEAP_GENERATE_EXCEPTIONS,
|
|
COMMASSOC_UDP_DLG_HEAP_SIZE
|
|
);
|
|
|
|
/*
|
|
* Create Memory heap for Assoc Ctx blocks.
|
|
* We want mutual exclusion and generation of exceptions
|
|
*/
|
|
DBGPRINT0(HEAP_CRDL,"InitMem: Assoc. blocks heap\n");
|
|
CommAssocAssocHeapHdl = WinsMscHeapCreate(
|
|
HEAP_GENERATE_EXCEPTIONS,
|
|
COMMASSOC_ASSOC_BLKS_HEAP_SIZE
|
|
);
|
|
/*
|
|
* Create Memory heap for dlg blocks
|
|
* We want mutual exclusion and generation of exceptions
|
|
*/
|
|
DBGPRINT0(HEAP_CRDL,"InitMem: Dlgs. blocks heap\n");
|
|
CommAssocDlgHeapHdl = WinsMscHeapCreate(
|
|
HEAP_GENERATE_EXCEPTIONS,
|
|
COMMASSOC_DLG_BLKS_HEAP_SIZE
|
|
);
|
|
/*
|
|
* Create Memory heap for messages on tcp connections
|
|
*/
|
|
DBGPRINT0(HEAP_CRDL,"InitMem: tcp connection message heap\n");
|
|
CommAssocTcpMsgHeapHdl = WinsMscHeapCreate(
|
|
HEAP_GENERATE_EXCEPTIONS,
|
|
COMMASSOC_TCP_MSG_HEAP_SIZE
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
ChkNtfSock(
|
|
IN fd_set *pActSocks,
|
|
IN fd_set *pRdSocks
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to check if there is a notification message
|
|
on the Notification socket. If there is one, it reads the message.
|
|
The message contains a socket # and a command to add or remove the
|
|
socket to/from the list of sockets being monitored by the TCP
|
|
listener thread.
|
|
|
|
|
|
Arguments:
|
|
|
|
pActSocks - Array of active sockets
|
|
pRdSocks - Array of sockets returned by select
|
|
|
|
Externals Used:
|
|
CommNtfSockHandle
|
|
|
|
Return Value:
|
|
TRUE - Yes, there was a message. The Active sockets array has been
|
|
changed.
|
|
FALSE - No. There was no message
|
|
|
|
Error Handling:
|
|
In case of an error, an exception is raised
|
|
|
|
Called by:
|
|
MonTcp
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
DWORD Error;
|
|
int RetVal;
|
|
COMM_NTF_MSG_T NtfMsg;
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx;
|
|
SOCKET Sock;
|
|
BOOL fNtfSockSet = TRUE;
|
|
|
|
if (FD_ISSET(CommNtfSockHandle, pRdSocks))
|
|
{
|
|
Sock = CommNtfSockHandle;
|
|
}
|
|
else
|
|
{
|
|
#if SPX > 0
|
|
if (FD_ISSET(CommIpxNtfSockHandle, pRdSocks))
|
|
{
|
|
Sock = CommIpxNtfSockHandle;
|
|
}
|
|
#endif
|
|
fNtfSockSet = FALSE;
|
|
}
|
|
|
|
if (fNtfSockSet)
|
|
{
|
|
//do a recvfrom to read in the data.
|
|
RetVal = recvfrom(
|
|
Sock,
|
|
(char *)&NtfMsg,
|
|
COMM_NTF_MSG_SZ,
|
|
0, //default flags (i.e. no peeking
|
|
//or reading OOB message
|
|
NULL, //don't want address of sender
|
|
0 //length of above arg
|
|
);
|
|
|
|
if (RetVal == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
if (WinsCnf.State_e != WINSCNF_E_TERMINATING)
|
|
{
|
|
WINSEVT_LOG_M(
|
|
Error,
|
|
WINS_EVT_WINSOCK_RECVFROM_ERR
|
|
);
|
|
}
|
|
WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
pDlgCtx = NtfMsg.DlgHdl.pEnt;
|
|
pAssocCtx = pDlgCtx->AssocHdl.pEnt;
|
|
|
|
if (NtfMsg.Cmd_e == COMM_E_NTF_START_MON)
|
|
{
|
|
DBGPRINT1(FLOW, "ChkNtfSock: Adding Socket (%d) to monitor list\n", NtfMsg.SockNo);
|
|
|
|
//
|
|
// We do this since FD_SETSIZE can fail silently
|
|
//
|
|
if (pActSocks->fd_count < FD_SETSIZE)
|
|
{
|
|
FD_SET(NtfMsg.SockNo, pActSocks);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(ERR,
|
|
"ChkNtfSock: Connection limit of %d reached\n",
|
|
FD_SETSIZE);
|
|
WINSEVT_LOG_M(WINS_FAILURE,
|
|
WINS_EVT_CONN_LIMIT_REACHED);
|
|
|
|
//
|
|
//This will cleanup the dlg and assoc. ctx. blk
|
|
//
|
|
ECommEndDlg(&NtfMsg.DlgHdl);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Add the association to the table of associations.
|
|
// Since this association will be monitored, we change
|
|
// the role of the association to RESPONDER. Also,
|
|
// change the dialogue role to IMPLICIT. These are
|
|
// sleight of hand tactics. The client who
|
|
// established the association (Replicator)
|
|
// does not care whet we do with the comm data
|
|
// structures as long as we monitor the dialogue that
|
|
// it initiated with a remote WINS
|
|
//
|
|
pAssocCtx->Role_e = COMMASSOC_ASSOC_E_RESPONDER;
|
|
pDlgCtx->Role_e = COMMASSOC_DLG_E_IMPLICIT;
|
|
pDlgCtx->FromAdd = pAssocCtx->RemoteAdd;
|
|
CommAssocInsertAssocInTbl(pAssocCtx);
|
|
}
|
|
else //COMM_NTF_STOP_MON
|
|
{
|
|
|
|
DBGPRINT1(FLOW, "ChkNtfSock: Removing Socket (%d) from monitor list\n", NtfMsg.SockNo);
|
|
FD_CLR(NtfMsg.SockNo, pActSocks);
|
|
|
|
//
|
|
//Remove the association from the table of
|
|
//associations. Since this association will not be
|
|
//monitored by the TCP thread, we change the role of
|
|
//the association to INITIATOR. Also, change the
|
|
//dialogue role to EXPLICIT. These are sleight of
|
|
//hand tactics.
|
|
//
|
|
if (CommLockBlock(&NtfMsg.DlgHdl))
|
|
{
|
|
pAssocCtx->Role_e = COMMASSOC_ASSOC_E_INITIATOR;
|
|
pDlgCtx->Role_e = COMMASSOC_DLG_E_EXPLICIT;
|
|
COMMASSOC_UNLINK_RSP_ASSOC_M(pAssocCtx);
|
|
pAssocCtx->RemoteAdd = pDlgCtx->FromAdd;
|
|
CommUnlockBlock(&NtfMsg.DlgHdl);
|
|
|
|
//
|
|
// Let us signal the PUSH thread so that it can
|
|
// hand over the connection to the PULL thread (See
|
|
// HandleUpdNtf in rplpush.c)
|
|
//
|
|
WinsMscSignalHdl(RplSyncWTcpThdEvtHdl);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//The dlg could not be locked. It means that before
|
|
//the tcp listener thread started processing this
|
|
//message, it had already processed a disconnect.
|
|
//
|
|
fCommDlgError = TRUE;
|
|
WinsMscSignalHdl(RplSyncWTcpThdEvtHdl);
|
|
}
|
|
|
|
}
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
} // ChkNtfSock()
|
|
|
|
|
|
STATUS
|
|
RecvData(
|
|
IN SOCKET SockNo,
|
|
IN LPBYTE pBuff,
|
|
IN DWORD BytesToRead,
|
|
IN INT Flags,
|
|
IN DWORD SecsToWait,
|
|
OUT LPDWORD pBytesRead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to do a timed recv on a socket.
|
|
|
|
Arguments:
|
|
SockNo - Socket No.
|
|
pBuff - Buffer to read the data into
|
|
BytesToRead - The number of bytes to read
|
|
Flags - flag arguments for recv
|
|
SecsToWait - No of secs to wait for the first read.
|
|
pBytesRead - No of Bytes that are read
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- WINS_SUCCESS
|
|
Error status codes -- WINS_FAILURE or WINS_RECV_TIMED_OUT
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
CommReadStream
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
fd_set RdSocks;
|
|
int NoOfSockReady;
|
|
INT BytesRead = 0;
|
|
INT BytesLeft = BytesToRead;
|
|
DWORD InChars;
|
|
DWORD Error;
|
|
BOOL fFirst = TRUE;
|
|
STATUS RetStat;
|
|
|
|
FD_ZERO(&RdSocks);
|
|
FD_SET(SockNo, &RdSocks);
|
|
|
|
/*
|
|
* Read the whole message into the allocated buffer
|
|
*/
|
|
for (
|
|
InChars = 0;
|
|
BytesLeft > 0;
|
|
InChars += BytesRead
|
|
)
|
|
{
|
|
//
|
|
// Check if we were told to do a timed receive. This will
|
|
// never happen in the TCP listener thread
|
|
//
|
|
if (SecsToWait)
|
|
{
|
|
//
|
|
// Block on a timed select. The first time around we want to
|
|
// wait the time specified by caller. The caller expects the other
|
|
// side to send something within this much time. For subsequent
|
|
// reads we wait a pre-defined interval since the sender has already
|
|
// accumulated all that it wants to send and has started sending it
|
|
// obviating the need for us to wait long.
|
|
//
|
|
if (fFirst)
|
|
{
|
|
sTimeToWait.tv_sec = (long)SecsToWait;
|
|
fFirst = FALSE;
|
|
}
|
|
else
|
|
{
|
|
sTimeToWait.tv_sec = SECS_TO_WAIT;
|
|
}
|
|
if (
|
|
(
|
|
NoOfSockReady = select(
|
|
FD_SETSIZE /*ignored arg*/,
|
|
&RdSocks,
|
|
(fd_set *)0,
|
|
(fd_set *)0,
|
|
&sTimeToWait
|
|
)
|
|
) == SOCKET_ERROR
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(ERR,
|
|
"RecvData: Timed Select returned SOCKET ERROR. Error = (%d)\n",
|
|
Error);
|
|
// CommDecConnCount();
|
|
return(WINS_FAILURE);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(FLOW, "ReceiveData: Timed Select returned with success. No of Sockets ready - (%d) \n", NoOfSockReady);
|
|
|
|
if (NoOfSockReady == 0)
|
|
{
|
|
//
|
|
// Timing out of RecvData indicates some problem at
|
|
// the remote WINS (either it is very slow
|
|
// (overloaded) or the TCP listener thread is out of
|
|
// commission).
|
|
WINSEVT_LOG_INFO_D_M(
|
|
WINS_SUCCESS,
|
|
WINS_EVT_WINSOCK_SELECT_TIMED_OUT
|
|
);
|
|
DBGPRINT0(ERR, "ReceiveData: Select TIMED OUT\n");
|
|
*pBytesRead = 0;
|
|
*pBytesRead = BytesRead;
|
|
// CommDecConnCount();
|
|
return(WINS_RECV_TIMED_OUT);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Do a blocking recv
|
|
//
|
|
BytesRead = recv(
|
|
SockNo,
|
|
(char *)(pBuff + InChars),
|
|
BytesLeft,
|
|
Flags
|
|
);
|
|
|
|
if (BytesRead == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
|
|
DBGPRINT1(ERR,
|
|
"RecvData: recv returned SOCKET_ERROR. Error = (%d)\n",
|
|
Error);
|
|
|
|
|
|
/*
|
|
* If the connection was aborted or reset from the
|
|
* other end, we close the socket and return an error
|
|
*/
|
|
if (
|
|
(Error == WSAECONNABORTED)
|
|
||
|
|
(Error == WSAECONNRESET)
|
|
||
|
|
(Error == WSAEDISCON)
|
|
)
|
|
{
|
|
DBGPRINT0(ERR,
|
|
"RecvData: Connection aborted\n");
|
|
WINSEVT_LOG_INFO_D_M(
|
|
WINS_SUCCESS,
|
|
WINS_EVT_CONN_ABORTED
|
|
);
|
|
}
|
|
*pBytesRead = BytesRead;
|
|
// CommDecConnCount();
|
|
return(WINS_FAILURE);
|
|
}
|
|
if (BytesRead == 0)
|
|
{
|
|
/*recv returns 0 (normal graceful shutdown from
|
|
* either side)
|
|
* Note:
|
|
* recv returns 0 if the connection terminated with no
|
|
* loss of data from either end point of the connection
|
|
*/
|
|
|
|
//
|
|
// If we were told to do a non timed receive,
|
|
// we must be executing in the TCP listener thread
|
|
//
|
|
// We don't return an error status here since
|
|
// a disconnect is a valid condition (the other
|
|
// WINS is terminating its connection normally)
|
|
//
|
|
if (SecsToWait == 0)
|
|
{
|
|
RetStat = WINS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The fact that we were told to do a
|
|
// timed select means that we are in
|
|
// a thread of one of the clients of
|
|
// COMSYS. We were expecting data but
|
|
// got a disconnect instead. Let us
|
|
// return an error
|
|
//
|
|
RetStat = WINS_FAILURE;
|
|
}
|
|
|
|
//
|
|
// We are done. Break out of the loop
|
|
//
|
|
*pBytesRead = BytesRead;
|
|
// CommDecConnCount();
|
|
return(RetStat);
|
|
}
|
|
|
|
BytesLeft -= BytesRead;
|
|
|
|
//
|
|
//We are here means that BytesRead > 0
|
|
//
|
|
|
|
} // end of for { ... }
|
|
|
|
*pBytesRead = InChars;
|
|
return(WINS_SUCCESS);
|
|
} // RecvData()
|
|
|
|
#if USENETBT > 0
|
|
VOID
|
|
CommOpenNbt(
|
|
DWORD FirstBindingIpAddr
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function opens the NetBt device for the interface specified by
|
|
FirstBindingIpAddr.
|
|
|
|
Arguments:
|
|
|
|
path - path to the NETBT driver
|
|
oflag - currently ignored. In the future, O_NONBLOCK will be
|
|
relevant.
|
|
ignored - not used
|
|
|
|
Return Value:
|
|
|
|
An NT handle for the stream, or INVALID_HANDLE_VALUE if unsuccessful.
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
// STRING name_string;
|
|
UNICODE_STRING uc_name_string;
|
|
NTSTATUS status;
|
|
PFILE_FULL_EA_INFORMATION pEaBuffer;
|
|
ULONG EaBufferSize;
|
|
|
|
//
|
|
// Convert the path into UNICODE_STRING form
|
|
//
|
|
#ifdef _PNP_POWER_
|
|
RtlInitUnicodeString(&uc_name_string, L"\\Device\\NetBt_Wins_Export");
|
|
#else
|
|
#ifdef UNICODE
|
|
RtlInitUnicodeString(&uc_name_string, pWinsCnfNbtPath);
|
|
#else
|
|
RtlInitString(&name_string, pWinsCnfNbtPath);
|
|
RtlAnsiStringToUnicodeString(&uc_name_string, &name_string, TRUE);
|
|
#endif
|
|
#endif // _PNP_POWER_
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&uc_name_string,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(HANDLE) NULL,
|
|
(PSECURITY_DESCRIPTOR) NULL
|
|
);
|
|
|
|
EaBufferSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
|
|
strlen(WINS_INTERFACE_NAME) + 1 +
|
|
sizeof(FirstBindingIpAddr); // EA length
|
|
|
|
|
|
WinsMscAlloc(EaBufferSize, &pEaBuffer);
|
|
|
|
if (pEaBuffer == NULL)
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_OUT_OF_MEM);
|
|
}
|
|
|
|
pEaBuffer->NextEntryOffset = 0;
|
|
pEaBuffer->Flags = 0;
|
|
pEaBuffer->EaNameLength = (UCHAR)strlen(WINS_INTERFACE_NAME);
|
|
|
|
|
|
//
|
|
// put "WinsInterface" into the name
|
|
//
|
|
RtlMoveMemory(
|
|
pEaBuffer->EaName,
|
|
WINS_INTERFACE_NAME,
|
|
pEaBuffer->EaNameLength + 1);
|
|
|
|
pEaBuffer->EaValueLength = sizeof(FirstBindingIpAddr);
|
|
*(DWORD UNALIGNED *)(pEaBuffer->EaName + pEaBuffer->EaNameLength + 1) = FirstBindingIpAddr;
|
|
|
|
status =
|
|
NtCreateFile(
|
|
&WinsCnfNbtHandle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
0,
|
|
pEaBuffer,
|
|
EaBufferSize
|
|
);
|
|
|
|
#ifndef UNICODE
|
|
RtlFreeUnicodeString(&uc_name_string);
|
|
#endif
|
|
|
|
WinsMscDealloc(pEaBuffer);
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
WinsEvtLogDetEvt(
|
|
FALSE,
|
|
WINS_PNP_FAILURE,
|
|
NULL,
|
|
__LINE__,
|
|
"d",
|
|
status);
|
|
|
|
DBGPRINT1(EXC, "CommOpenNbt: Status from NtCreateFile is (%x)\n",
|
|
status);
|
|
WINS_RAISE_EXC_M(WINS_EXC_NBT_ERR);
|
|
}
|
|
return;
|
|
|
|
} // CommOpenNbt
|
|
|
|
//------------------------------------------------------------------------
|
|
#if NEWNETBTIF == 0
|
|
//#include "nbtioctl.sav"
|
|
|
|
STATUS
|
|
CommGetNetworkAdd(
|
|
IN OUT PCOMM_ADD_T pAdd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure does an adapter status query to get the local name table.
|
|
It either prints out the local name table or the remote (cache) table
|
|
depending on whether WhichNames is NAMES or CACHE .
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
0 if successful, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG i;
|
|
PVOID pBuffer;
|
|
ULONG BufferSize=sizeof(tADAPTERSTATUS);
|
|
NTSTATUS Status;
|
|
tADAPTERSTATUS *pAdapterStatus;
|
|
ULONG QueryType;
|
|
PUCHAR pAddr;
|
|
ULONG Ioctl;
|
|
|
|
//
|
|
// Get the local name table
|
|
//
|
|
Ioctl = IOCTL_TDI_QUERY_INFORMATION;
|
|
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
while (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
WinsMscAlloc(BufferSize, &pBuffer);
|
|
Status = DeviceIoCtrl(
|
|
&sNetbtGetAddrEvtHdl,
|
|
pBuffer,
|
|
BufferSize,
|
|
Ioctl
|
|
);
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
WinsMscDealloc(pBuffer);
|
|
|
|
BufferSize *=2;
|
|
if (BufferSize == 0xFFFF)
|
|
{
|
|
WINSEVT_LOG_D_M(BufferSize, WINS_EVT_UNABLE_TO_ALLOCATE_PACKET);
|
|
DBGPRINT1(ERR, "CommGetNetworkAdd: Unable to get address from NBT\n", BufferSize);
|
|
return(WINS_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
pAdapterStatus = (tADAPTERSTATUS *)pBuffer;
|
|
if (pAdapterStatus->AdapterInfo.name_count == 0)
|
|
{
|
|
WINSEVT_LOG_D_M(WINS_FAILURE, WINS_EVT_ADAPTER_STATUS_ERR);
|
|
DBGPRINT0(ERR, "CommGetNetworkAdd: No names in NBT cache\n");
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
|
|
//
|
|
// print out the Ip Address of this node
|
|
//
|
|
pAddr = &pAdapterStatus->AdapterInfo.adapter_address[2];
|
|
NMSMSGF_RETRIEVE_IPADD_M(pAddr, pAdd->Add.IPAdd);
|
|
|
|
WinsMscDealloc(pBuffer);
|
|
return(WINS_SUCCESS);
|
|
}
|
|
#else
|
|
STATUS
|
|
CommGetNetworkAdd(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets all the Ip Addresses of Netbt interfaces.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
0 if successful, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Buffer[NBT_MAXIMUM_BINDINGS + 1];
|
|
ULONG BufferSize=sizeof(Buffer);
|
|
NTSTATUS Status;
|
|
ULONG Ioctl;
|
|
PULONG pBuffer;
|
|
PULONG pBufferSv;
|
|
DWORD i, Count;
|
|
BOOL fAlloc = FALSE;
|
|
|
|
//
|
|
// Get the local addresses
|
|
//
|
|
Ioctl = IOCTL_NETBT_GET_IP_ADDRS;
|
|
|
|
|
|
//
|
|
// NETBT does not support more than 64 adapters and not more than
|
|
// one ip address per adapter. So, there can be a max of 64 ip addresses
|
|
// which means we don't require more than 65 * 4 = 280 bytes (256 for the
|
|
// addresses followed by a delimiter address of 0.
|
|
//
|
|
Status = DeviceIoCtrl(
|
|
&sNetbtGetAddrEvtHdl,
|
|
(LPBYTE)Buffer,
|
|
BufferSize,
|
|
Ioctl
|
|
);
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
BufferSize *= 10; //alocate a buffer that is 10 times bigger.
|
|
//surely, netbt can not be supporting so many
|
|
//addresses. If it is, then the netbt developer
|
|
//goofed in that (s)he did not update
|
|
//NBT_MAXIMUM_BINDINGS in nbtioctl.h
|
|
WinsMscAlloc(BufferSize, &pBuffer);
|
|
|
|
DBGPRINT1(ERR, "CommGetNetworkAdd: Ioctl - GET_IP_ADDRS failed. Return code = (%x)\n", Status);
|
|
Status = DeviceIoCtrl(
|
|
&sNetbtGetAddrEvtHdl,
|
|
(LPBYTE)pBuffer,
|
|
BufferSize,
|
|
Ioctl
|
|
);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
DBGPRINT1(ERR, "CommGetNetworkAdd: Ioctl - GET_IP_ADDRS failed AGAIN. Return code = (%x)\n", Status);
|
|
WINSEVT_LOG_M(Status, WINS_EVT_UNABLE_TO_GET_ADDRESSES);
|
|
WinsMscDealloc(pBuffer); //dealloc the buffer
|
|
return(WINS_FAILURE);
|
|
}
|
|
fAlloc = TRUE;
|
|
|
|
}
|
|
else
|
|
{
|
|
pBuffer = Buffer;
|
|
}
|
|
|
|
//
|
|
// Count the number of addresses returned
|
|
// The end of the address table contains -1 and any null addresses
|
|
// contain 0
|
|
//
|
|
pBufferSv = pBuffer;
|
|
for(Count=0; *pBuffer != -1; pBuffer++)
|
|
{
|
|
// Increment Count only if it is a valid address.
|
|
if ( *pBuffer ) {
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
if ( !Count ) {
|
|
DBGPRINT0(ERR, "CommGetNetworkAdd: Netbt did not give any valid address\n");
|
|
WINSEVT_LOG_M(Status, WINS_EVT_UNABLE_TO_GET_ADDRESSES);
|
|
if (fAlloc)
|
|
{
|
|
WinsMscDealloc(pBufferSv);
|
|
}
|
|
|
|
return(WINS_FAILURE);
|
|
}
|
|
|
|
if (pWinsAddresses)
|
|
{
|
|
WinsMscDealloc(pWinsAddresses);
|
|
}
|
|
//
|
|
// Allocate space for the addresses
|
|
//
|
|
WinsMscAlloc(sizeof(ADD_T) + ((Count - 1) * COMM_IP_ADD_SIZE), &pWinsAddresses);
|
|
pWinsAddresses->NoOfAdds = Count;
|
|
pBuffer = pBufferSv;
|
|
// Copy all valid addresses
|
|
for (i=0; i<Count; pBuffer++)
|
|
{
|
|
if ( *pBuffer ) {
|
|
|
|
pWinsAddresses->IpAdd[i] = *pBuffer;
|
|
i++;
|
|
}
|
|
}
|
|
if (fAlloc)
|
|
{
|
|
WinsMscDealloc(pBufferSv);
|
|
}
|
|
|
|
return(WINS_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------
|
|
NTSTATUS
|
|
DeviceIoCtrl(
|
|
IN LPHANDLE pEvtHdl,
|
|
IN PVOID pDataBuffer,
|
|
IN DWORD DataBufferSize,
|
|
IN ULONG Ioctl
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This procedure performs an ioctl(I_STR) on a stream.
|
|
|
|
Arguments:
|
|
|
|
fd - NT file handle
|
|
iocp - pointer to a strioctl structure
|
|
|
|
Return Value:
|
|
|
|
0 if successful, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK iosb;
|
|
#if NEWNETBTIF == 0
|
|
TDI_REQUEST_QUERY_INFORMATION QueryInfo;
|
|
#endif
|
|
PVOID pInput = NULL;
|
|
ULONG SizeInput = 0;
|
|
|
|
|
|
#if NEWNETBTIF == 0
|
|
PERF("TDI_QUERY_INFORMATION is used only at WINS initialization")
|
|
if (Ioctl == IOCTL_TDI_QUERY_INFORMATION)
|
|
{
|
|
pInput = &QueryInfo;
|
|
QueryInfo.QueryType = TDI_QUERY_ADAPTER_STATUS; // node status
|
|
SizeInput = sizeof(TDI_REQUEST_QUERY_INFORMATION);
|
|
}
|
|
#endif
|
|
|
|
while (TRUE)
|
|
{
|
|
status = NtDeviceIoControlFile(
|
|
WinsCnfNbtHandle, // Handle
|
|
*pEvtHdl, // Event
|
|
NULL, // ApcRoutine
|
|
NULL, // ApcContext
|
|
&iosb, // IoStatusBlock
|
|
Ioctl, // IoControlCode
|
|
pInput, // InputBuffer
|
|
SizeInput, // Buffer Length
|
|
pDataBuffer, // Output Buffer
|
|
DataBufferSize // Output BufferSize
|
|
);
|
|
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
return(status);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If status is PENDING, do a wait on the event
|
|
//
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = NtWaitForSingleObject(
|
|
*pEvtHdl, // Handle
|
|
TRUE, // Alertable
|
|
NULL); // Timeout
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
return(status);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// status returned by NtDeviceIoCtrl or NtWaitForSingleObject is
|
|
// a failure code
|
|
//
|
|
DBGPRINT1(ERR, "DeviceIoCtrl, Status returned is (%x)\n", status);
|
|
if (status != STATUS_CANCELLED)
|
|
{
|
|
//
|
|
// If it is insufficient resources, we drop this datagram and
|
|
// try again (only for recv)
|
|
//
|
|
if (Ioctl == IOCTL_NETBT_WINS_RCV)
|
|
{
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
//
|
|
// in case of a send, it can be invalid handle, invalid
|
|
// parameter or insufficient resourcesi. If it is INVALID_PARAMETER,
|
|
// it means that we passed 0 in the Address field on top of the buffer.
|
|
//
|
|
// Drop this datagram and return to the caller
|
|
//
|
|
if (Ioctl == IOCTL_NETBT_WINS_SEND)
|
|
{
|
|
if (
|
|
(status == STATUS_INSUFFICIENT_RESOURCES)
|
|
||
|
|
(status == STATUS_INVALID_PARAMETER)
|
|
)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(EXC, "NtDeviceIoCtrl returned error = (%x)\n",
|
|
status);
|
|
WINSEVT_LOG_D_M(status, WINS_EVT_NETBT_SEND_ERR);
|
|
|
|
|
|
//
|
|
// If the machine's address has gone away due to some
|
|
// reason, WinsCnfNbtHandle will have been changed
|
|
// to NULL. In this case, we will get
|
|
// STATUS_INVALID_HANDLE error. We do not check for
|
|
// handle being NULL prior to making the Nbt call
|
|
// to avoid an if check which is of no value for
|
|
// 99% of the time.
|
|
//
|
|
// An error will be logged up above. We should not see
|
|
// too many of these since the window where
|
|
// WinsCnfNbtHandle is NULL is very small unless WINS
|
|
// is terminating in which case this thread will
|
|
// just terminate as a result of the exception being
|
|
// raised below.
|
|
//
|
|
// The address can go away due to the following reasons
|
|
//
|
|
// 1) psched installation (unbind followed by bind)
|
|
// 2) Changing from dhcp/static or static/dhcp
|
|
// 3) ipconfig release/renew
|
|
//
|
|
|
|
//
|
|
// When the main thread has to terminate WINS, it
|
|
// closes WinsCnfNetbtHandle. A worker thread or a
|
|
// challenge thread might be busy dealing with its
|
|
// queue of work items (potentially long on a busy
|
|
// WINS) and may not see a termination
|
|
// signal from the main thread. This exception will
|
|
// terminate it
|
|
//
|
|
|
|
//
|
|
// Raise an exception if the wins is terminating
|
|
//
|
|
if (WinsCnf.State_e == WINSCNF_E_TERMINATING)
|
|
{
|
|
WINS_RAISE_EXC_M(WINS_EXC_NBT_ERR);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
} // end of while (TRUE)
|
|
return(status);
|
|
}
|
|
#endif
|
|
|
|
LPVOID
|
|
CommHeapAlloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN CLONG BuffSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called to allocate a buffer
|
|
|
|
Arguments:
|
|
pTable - Table where the buffer will be stored
|
|
BuffSize - Size of buffer to allocate
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes -- ptr to buffer allocated
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
RtlInsertElementGeneric()
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
This function exists just because the RtlTbl functions require
|
|
this prototype for the user specified alloc function.
|
|
--*/
|
|
|
|
{
|
|
LPVOID pTmp;
|
|
|
|
UNREFERENCED_PARAMETER(pTable);
|
|
|
|
pTmp = WinsMscHeapAlloc( CommUdpDlgHeapHdl, (DWORD) BuffSize );
|
|
|
|
return(pTmp);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
CommHeapDealloc(
|
|
IN PRTL_GENERIC_TABLE pTable,
|
|
IN PVOID pBuff
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to deallocate memory allocated via CommAlloc.
|
|
|
|
|
|
Arguments:
|
|
pTable - Table where buffer was stored
|
|
pBuff - Buffer to deallocate
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
None
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
The pTable argument is required since the address of this function
|
|
is passed as an argument to RtlTbl functions
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
UNREFERENCED_PARAMETER(pTable);
|
|
WinsMscHeapFree(
|
|
CommUdpDlgHeapHdl,
|
|
pBuff
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
VOID
|
|
CommDecConnCount(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function decrements the conn. count
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
DWORD ConnCount;
|
|
ConnCount = InterlockedExchange(&CommConnCount, CommConnCount);
|
|
if (ConnCount != 0)
|
|
{
|
|
InterlockedDecrement(&CommConnCount);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT0(ERR, "CommDecConnCount: WEIRD: ConnCount should not have been zero\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if PRSCONN
|
|
__inline
|
|
BOOL
|
|
CommIsDlgActive (
|
|
PCOMM_HDL_T pDlgHdl
|
|
)
|
|
{
|
|
|
|
fd_set RdSocks;
|
|
int NoOfSockReady;
|
|
BOOL fRetStat = TRUE;
|
|
DWORD Error;
|
|
|
|
PCOMMASSOC_DLG_CTX_T pDlgCtx = pDlgHdl->pEnt;
|
|
PCOMM_HDL_T pAssocHdl = &pDlgCtx->AssocHdl;
|
|
PCOMMASSOC_ASSOC_CTX_T pAssocCtx = pAssocHdl->pEnt;
|
|
|
|
if (!CommLockBlock(pAssocHdl))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
try {
|
|
|
|
FD_ZERO(&RdSocks);
|
|
FD_SET(pAssocCtx->SockNo, &RdSocks);
|
|
sTimeToWait.tv_sec = 0;
|
|
|
|
//
|
|
// Pass socket and a win32 event with flag of FD_CLOSE to WSAEventSelect.
|
|
// if the socket is disconnected, the event will be set. NOTE, only one
|
|
// event select can be active on the socket at any time - vadime 9/2/98
|
|
//
|
|
FUTURES("Use WSAEventSelect for marginally better performance")
|
|
|
|
if (NoOfSockReady = select(
|
|
FD_SETSIZE /*ignored arg*/,
|
|
&RdSocks,
|
|
(fd_set *)0,
|
|
(fd_set *)0,
|
|
&sTimeToWait
|
|
) == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(ERR,
|
|
"RecvData: Timed Select returned SOCKET ERROR. Error = (%d)\n",
|
|
Error);
|
|
// CommDecConnCount();
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
DBGPRINT1(FLOW, "ReceiveData: Timed Select returned with success. No of Sockets ready - (%d) \n", NoOfSockReady);
|
|
|
|
//
|
|
// Either there is data or the socket is disconnected. There
|
|
// should never be any data. We will just assume a disconnect
|
|
// is there and return FALSE. The client (RPL) will end the dlg.
|
|
//
|
|
if (NoOfSockReady == 1)
|
|
{
|
|
fRetStat = FALSE;
|
|
}
|
|
ASSERT(NoOfSockReady == 0);
|
|
}
|
|
}
|
|
finally {
|
|
CommUnlockBlock(pAssocHdl);
|
|
}
|
|
|
|
return(fRetStat);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if MCAST > 0
|
|
|
|
|
|
VOID
|
|
JoinMcastGrp(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called by the comm. subsystem to make WINS join
|
|
a multicast group
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
CommCreatePorts
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
int Loop = 0; //to disable loopback of multicast messages on the
|
|
//same interface
|
|
DWORD Error;
|
|
struct ip_mreq mreq;
|
|
DBGENTER("JoinMcastGrp\n");
|
|
#if 0
|
|
//
|
|
// Open a socket for sending/receiving multicast packets. We open
|
|
// a seperate socket instead of using the one for udp datagrams since
|
|
// we don't want to impact the client name packet processing with any
|
|
// sort of overhead. Also, having a seperate socket keeps things nice
|
|
// and clean.
|
|
//
|
|
if ( (CommMcastPortHandle = socket(
|
|
PF_INET,
|
|
SOCK_DGRAM,
|
|
IPPROTO_UDP
|
|
)
|
|
) == INVALID_SOCKET
|
|
)
|
|
{
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(MTCAST, "JoinMcastGrp: Can not create MCAST socket\n", Error);
|
|
// WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_MCAST_SOCK); //log an event
|
|
return;
|
|
}
|
|
#endif
|
|
//
|
|
// Set TTL
|
|
//
|
|
if (setsockopt(
|
|
CommUdpPortHandle,
|
|
IPPROTO_IP,
|
|
IP_MULTICAST_TTL,
|
|
(char *)&WinsCnf.McastTtl,
|
|
sizeof((int)WinsCnf.McastTtl)) == SOCKET_ERROR)
|
|
{
|
|
|
|
closesocket(CommUdpPortHandle);
|
|
CommUdpPortHandle = INVALID_SOCKET;
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(MTCAST, "JoinMcastGrp: Can not set TTL option. Error = (%d)\n", Error);
|
|
// WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_MCAST_SOCK); //log an event
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Disable loopback of messages
|
|
//
|
|
if (setsockopt(CommUdpPortHandle, IPPROTO_IP, IP_MULTICAST_LOOP,
|
|
(char *)&Loop, sizeof(Loop)) == SOCKET_ERROR)
|
|
{
|
|
|
|
closesocket(CommUdpPortHandle);
|
|
CommUdpPortHandle = INVALID_SOCKET;
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(MTCAST, "JoinMcastGrp: Can not set DISABLE LOOPBACK option. Error = (%d)\n",
|
|
Error);
|
|
// WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_MCAST_SOCK); //log an event
|
|
return;
|
|
}
|
|
#endif
|
|
//
|
|
// Join a multicast grp
|
|
//
|
|
mreq.imr_multiaddr.s_addr = htonl(McastAdd.sin_addr.s_addr);
|
|
mreq.imr_interface.s_addr = INADDR_ANY; //use the default mcast i/f
|
|
|
|
if (setsockopt(CommUdpPortHandle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
|
(char *)&mreq, sizeof(mreq)) == SOCKET_ERROR)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
closesocket(CommUdpPortHandle);
|
|
CommUdpPortHandle = INVALID_SOCKET;
|
|
DBGPRINT1(MTCAST, "JoinMcastGrp: Can not ADD SELF TO MCAST GRP. Error = (%d)\n", Error);
|
|
// WINSEVT_LOG_M(Error, WINS_EVT_CANT_CREATE_MCAST_SOCK); //log an event
|
|
return;
|
|
}
|
|
|
|
DBGLEAVE("JoinMcastGrp\n");
|
|
|
|
return;
|
|
}
|
|
VOID
|
|
CommLeaveMcastGrp(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function is called by the comm. subsystem to make WINS join
|
|
a multicast group
|
|
|
|
Arguments:
|
|
|
|
|
|
Externals Used:
|
|
None
|
|
|
|
|
|
Return Value:
|
|
|
|
Success status codes --
|
|
Error status codes --
|
|
|
|
Error Handling:
|
|
|
|
Called by:
|
|
CommCreatePorts
|
|
Side Effects:
|
|
|
|
Comments:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
DWORD Error;
|
|
struct ip_mreq mreq;
|
|
|
|
//
|
|
// Leave a multicast grp
|
|
//
|
|
mreq.imr_multiaddr.s_addr = htonl(McastAdd.sin_addr.s_addr);
|
|
mreq.imr_interface.s_addr = INADDR_ANY; //use the default mcast i/f
|
|
|
|
if (setsockopt(CommUdpPortHandle, IPPROTO_IP, IP_DROP_MEMBERSHIP,
|
|
(char *)&mreq, sizeof(mreq)) == SOCKET_ERROR)
|
|
{
|
|
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(MTCAST, "CommLeaveMcastGrp: Can not DROP MEMBERSHIP TO MCAST GRP. Error = (%d)\n", Error);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
CheckMcastSock(
|
|
IN fd_set *pActSocks,
|
|
IN fd_set *pRdSocks
|
|
)
|
|
{
|
|
DWORD Error;
|
|
int RetVal;
|
|
BYTE Buff[COMM_DATAGRAM_SIZE];
|
|
PCOMM_MCAST_MSG_T pMcastMsg = (PCOMM_MCAST_MSG_T)Buff;
|
|
struct sockaddr_in RemWinsAdd;
|
|
int RemWinsAddLen = sizeof(RemWinsAdd);
|
|
|
|
LPBYTE pBody;
|
|
COMM_IP_ADD_T IPAdd;
|
|
BOOL fFound;
|
|
DWORD i, j;
|
|
DWORD NoOfAddsInPkt;
|
|
struct in_addr InAdd;
|
|
LPBYTE pAdd;
|
|
DWORD FirstDelEntryIndex;
|
|
PPNR_STATUS_T pPnrStatusTmp;
|
|
|
|
DBGENTER("CheckMcastSock\n");
|
|
if (FD_ISSET(CommUdpPortHandle, pRdSocks))
|
|
{
|
|
//do a recvfrom to read in the data.
|
|
RetVal = recvfrom(
|
|
CommUdpPortHandle,
|
|
(char *)pMcastMsg,
|
|
COMM_DATAGRAM_SIZE,
|
|
//COMM_MCAST_MSG_SZ + COMM_IP_ADD_SIZE,
|
|
0, //default flags (i.e. no peeking
|
|
//or reading OOB message
|
|
(struct sockaddr *)&RemWinsAdd,
|
|
&RemWinsAddLen
|
|
);
|
|
|
|
if (RetVal == SOCKET_ERROR)
|
|
{
|
|
Error = WSAGetLastError();
|
|
DBGPRINT1(MTCAST, "CheckMcastSock: recvfrom failed. Error = (%d)\n", Error);
|
|
if (WinsCnf.State_e != WINSCNF_E_TERMINATING)
|
|
{
|
|
WINSEVT_LOG_M(
|
|
Error,
|
|
WINS_EVT_WINSOCK_RECVFROM_ERR
|
|
);
|
|
}
|
|
//WINS_RAISE_EXC_M(WINS_EXC_FAILURE);
|
|
}
|
|
|
|
//
|
|
// If we were told not to use self found pnrs, return
|
|
//
|
|
if (!WinsCnf.fUseSelfFndPnrs)
|
|
{
|
|
DBGLEAVE("ChkMcastSock - 99\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// If the sign is not in the valid range, return
|
|
//
|
|
if ((pMcastMsg->Sign < COMM_MCAST_SIGN_START) || (pMcastMsg->Sign > COMM_MCAST_SIGN_END))
|
|
{
|
|
DBGPRINT1(MTCAST, "Signature in received message = %d\n", pMcastMsg->Sign);
|
|
DBGLEAVE("CheckMcastSock - 1\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Compute the number of addresses in the packet.
|
|
//
|
|
NoOfAddsInPkt = (RetVal - (COMM_MCAST_MSG_SZ - 1))/COMM_IP_ADD_SIZE;
|
|
DBGPRINT2(MTCAST, "ChkMcastSock: RetVal = (%d);NoOfAddsInPkt = (%d)\n", RetVal, NoOfAddsInPkt);
|
|
|
|
FirstDelEntryIndex = pPnrStatus->NoOfPnrs;
|
|
pBody = pMcastMsg->Body;
|
|
|
|
IPAdd = *(PCOMM_IP_ADD_T)pBody;
|
|
pBody += COMM_IP_ADD_SIZE;
|
|
|
|
//
|
|
// Loop until either all ip addresses in packets are
|
|
// exhausted or we get an ip. address of 0. If somebody
|
|
// sent a 0 address, then it is ok to ignore the rest.
|
|
//
|
|
for(
|
|
;
|
|
(IPAdd != 0) && NoOfAddsInPkt;
|
|
IPAdd = *(PCOMM_IP_ADD_T)pBody, pBody += COMM_IP_ADD_SIZE,
|
|
NoOfAddsInPkt--
|
|
)
|
|
{
|
|
|
|
DBGPRINT1(MTCAST, "CheckMcastSock: Processing WINS address = %lx\n", ntohl(IPAdd));
|
|
fFound = FALSE;
|
|
pPnrStatusTmp = (PPNR_STATUS_T)(pPnrStatus->Pnrs);
|
|
if (pMcastMsg->Code == COMM_MCAST_WINS_UP)
|
|
{
|
|
for (i=0; i < pPnrStatus->NoOfPnrs; i++, pPnrStatusTmp++)
|
|
{
|
|
if ((FirstDelEntryIndex == pPnrStatus->NoOfPnrs)
|
|
&&
|
|
(pPnrStatusTmp->State == COMM_MCAST_WINS_DOWN))
|
|
{
|
|
FirstDelEntryIndex = i;
|
|
}
|
|
|
|
if (IPAdd == pPnrStatusTmp->IPAdd)
|
|
{
|
|
if (pPnrStatusTmp->State == COMM_MCAST_WINS_DOWN)
|
|
{
|
|
pPnrStatusTmp->State = COMM_MCAST_WINS_UP;
|
|
InAdd.s_addr = IPAdd;
|
|
pAdd = inet_ntoa(InAdd);
|
|
WinsCnfAddPnr(RPL_E_PULL, pAdd);
|
|
WinsCnfAddPnr(RPL_E_PUSH, pAdd);
|
|
}
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!fFound && (i <= pPnrStatus->NoOfPnrs))
|
|
{
|
|
DWORD FirstFreeIndex;
|
|
PPNR_STATUS_T pPnr;
|
|
//
|
|
// since disable loopback is not working we
|
|
// have to check for message sent by self
|
|
//
|
|
FUTURES("Remove the if when winsock is enhanced to allow loopback to be")
|
|
FUTURES("disabled")
|
|
if (!ChkMyAdd(ntohl(IPAdd)))
|
|
{
|
|
InAdd.s_addr = IPAdd;
|
|
pAdd = inet_ntoa(InAdd);
|
|
|
|
if (FirstDelEntryIndex < pPnrStatus->NoOfPnrs)
|
|
{
|
|
FirstFreeIndex = FirstDelEntryIndex;
|
|
}
|
|
else
|
|
{
|
|
FirstFreeIndex = pPnrStatus->NoOfPnrs++;
|
|
if (pPnrStatus->NoOfPnrs == pPnrStatus->NoOfPnrSlots)
|
|
{
|
|
|
|
WINSMSC_REALLOC_M(MCAST_PNR_STATUS_SIZE_M(pPnrStatus->NoOfPnrSlots * 2), (LPVOID *)&pPnrStatus);
|
|
pPnrStatus->NoOfPnrSlots *= 2;
|
|
DBGPRINT1(DET, "CheckMcastSock: NO OF PNR SLOTS INCREASED TO (%d)\n", pPnrStatus->NoOfPnrSlots);
|
|
|
|
}
|
|
}
|
|
pPnr = (PPNR_STATUS_T)(pPnrStatus->Pnrs);
|
|
(pPnr + FirstFreeIndex)->State = COMM_MCAST_WINS_UP;
|
|
(pPnr + FirstFreeIndex)->IPAdd = IPAdd;
|
|
|
|
WinsCnfAddPnr(RPL_E_PULL, pAdd);
|
|
WinsCnfAddPnr(RPL_E_PUSH, pAdd);
|
|
|
|
DBGPRINT1(MTCAST, "CheckMcastSock: ADDED WINS partner with address = %s\n", pAdd);
|
|
}
|
|
}
|
|
}
|
|
else //has to be COMM_MCAST_WINS_DOWN
|
|
{
|
|
for (i=0; i < pPnrStatus->NoOfPnrs; i++, pPnrStatusTmp++)
|
|
{
|
|
if (IPAdd == pPnrStatusTmp->IPAdd)
|
|
{
|
|
if (pPnrStatusTmp->State == COMM_MCAST_WINS_DOWN)
|
|
{
|
|
fFound = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pPnrStatusTmp->State = COMM_MCAST_WINS_DOWN;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!fFound)
|
|
{
|
|
InAdd.s_addr = IPAdd;
|
|
pAdd = inet_ntoa(InAdd);
|
|
DBGPRINT1(MTCAST, "CheckMcastSock: Will REMOVE WINS partner with address = %s IFF Untouched by admin\n", pAdd);
|
|
WinsCnfDelPnr(RPL_E_PULL, pAdd);
|
|
WinsCnfDelPnr(RPL_E_PUSH, pAdd);
|
|
}
|
|
}
|
|
} // end of for loop
|
|
DBGLEAVE("ChkMcastSock - 2\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
DBGLEAVE("ChkMcastSock - 3\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL
|
|
ChkMyAdd(
|
|
COMM_IP_ADD_T IpAdd
|
|
)
|
|
{
|
|
DWORD i;
|
|
PCOMM_IP_ADD_T pIpAdd = pWinsAddresses->IpAdd;
|
|
for (i=0; i<pWinsAddresses->NoOfAdds; i++)
|
|
{
|
|
if (IpAdd == *pIpAdd++)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
VOID
|
|
CommSendMcastMsg(
|
|
DWORD Code
|
|
)
|
|
{
|
|
|
|
PCOMM_MCAST_MSG_T pMcastMsg;
|
|
DWORD McastMsgLen;
|
|
LPBYTE pBody;
|
|
DWORD i;
|
|
COMM_IP_ADD_T Add = 0;
|
|
|
|
// --ft bug #103361: no need to send CommSendMcastMsg if there
|
|
// is no nic card here
|
|
if (pWinsAddresses == NULL)
|
|
return;
|
|
|
|
McastMsgLen = MCAST_PKT_LEN_M(pWinsAddresses->NoOfAdds + 1);
|
|
|
|
WinsMscAlloc(McastMsgLen, &pMcastMsg);
|
|
|
|
pMcastMsg->Code = Code;
|
|
pMcastMsg->Sign = COMM_MCAST_SIGN_START;
|
|
pBody = pMcastMsg->Body;
|
|
|
|
//
|
|
// Insert the count in net order.
|
|
//
|
|
// NMSMSGF_INSERT_ULONG_M(pBody, pWinsAddresses->NoOfAddresses);
|
|
|
|
//
|
|
// Insert the addresses in net order
|
|
//
|
|
for (i=0; i<pWinsAddresses->NoOfAdds; i++)
|
|
{
|
|
DBGPRINT1(MTCAST, "CommSendMcastMsg: Inserting Address = (%lx)\n",
|
|
pWinsAddresses->IpAdd[i]);
|
|
NMSMSGF_INSERT_IPADD_M(pBody, pWinsAddresses->IpAdd[i]);
|
|
}
|
|
NMSMSGF_INSERT_IPADD_M(pBody, Add);
|
|
|
|
|
|
DBGPRINT1(MTCAST, "CommSendMcastMsg: Sending MCAST msg of length = (%d)\n",
|
|
McastMsgLen);
|
|
CommSendUdp (CommUdpPortHandle, &McastAdd, (MSG_T)pMcastMsg, McastMsgLen);
|
|
|
|
WinsMscDealloc(pMcastMsg);
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|