1772 lines
50 KiB
C++
1772 lines
50 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1997 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
status.cpp
|
|
wins status scope pane node handler.
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "status.h"
|
|
#include "server.h"
|
|
#include "statnode.h"
|
|
#include "dhcp.h"
|
|
#include "statndpp.h"
|
|
|
|
#define WINS_MESSAGE_SIZE 576
|
|
#define ANSWER_TIMEOUT 20000
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CWinsStatusHandler
|
|
Description
|
|
---------------------------------------------------------------------------*/
|
|
CWinsStatusHandler::CWinsStatusHandler
|
|
(
|
|
ITFSComponentData * pCompData,
|
|
DWORD dwUpdateInterval
|
|
) : CMTWinsHandler(pCompData),
|
|
m_hListenThread(NULL),
|
|
m_hMainMonThread(NULL),
|
|
m_hPauseListening(NULL),
|
|
m_nServersUpdated(0)
|
|
{
|
|
m_bExpanded = FALSE;
|
|
m_nState = loaded;
|
|
m_dwUpdateInterval = dwUpdateInterval;
|
|
|
|
// from class ThreadHandler
|
|
m_uMsgBase = 0;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CWinsStatusHandler
|
|
Destructor
|
|
---------------------------------------------------------------------------*/
|
|
CWinsStatusHandler::~CWinsStatusHandler()
|
|
{
|
|
m_listServers.RemoveAll();
|
|
|
|
if (m_uMsgBase)
|
|
{
|
|
::SendMessage(m_hwndHidden, WM_HIDDENWND_REGISTER, FALSE, m_uMsgBase);
|
|
m_uMsgBase = 0;
|
|
}
|
|
|
|
CloseSockets();
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::DestroyHandler
|
|
Release and pointers we have here
|
|
Author: EricDav
|
|
----------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::DestroyHandler
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
m_spNode.Set(NULL);
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::OnCreateNodeId2
|
|
Returns a unique string for this node
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT CWinsStatusHandler::OnCreateNodeId2(ITFSNode * pNode, CString & strId, DWORD * dwFlags)
|
|
{
|
|
const GUID * pGuid = pNode->GetNodeType();
|
|
|
|
CString strGuid;
|
|
|
|
StringFromGUID2(*pGuid, strGuid.GetBuffer(256), 256);
|
|
strGuid.ReleaseBuffer();
|
|
|
|
strId = strGuid;
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::InitializeNode
|
|
Initializes node specific data
|
|
----------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::InitializeNode
|
|
(
|
|
ITFSNode * pNode
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
SPITFSNode spParent;
|
|
|
|
CString strTemp;
|
|
strTemp.LoadString(IDS_SERVER_STATUS_FOLDER);
|
|
|
|
SetDisplayName(strTemp);
|
|
|
|
// Make the node immediately visible
|
|
pNode->SetData(TFS_DATA_COOKIE, (LPARAM) pNode);
|
|
pNode->SetData(TFS_DATA_IMAGEINDEX, ICON_IDX_SERVER);
|
|
pNode->SetData(TFS_DATA_OPENIMAGEINDEX, ICON_IDX_SERVER);
|
|
pNode->SetData(TFS_DATA_USER, (LPARAM) this);
|
|
pNode->SetData(TFS_DATA_TYPE, WINSSNAP_SERVER_STATUS);
|
|
pNode->SetData(TFS_DATA_RELATIVE_FLAGS, SDI_FIRST);
|
|
pNode->SetData(TFS_DATA_SCOPE_LEAF_NODE, TRUE);
|
|
|
|
SetColumnStringIDs(&aColumns[WINSSNAP_SERVER_STATUS][0]);
|
|
SetColumnWidths(&aColumnWidths[WINSSNAP_SERVER_STATUS][0]);
|
|
|
|
// the event to signal the Listen thread to abort
|
|
m_hAbortListen = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hAbortListen == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::InitializeNode - CreateEvent Failed m_hAbortListen %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
// the event to signal the main thread to abort
|
|
m_hAbortMain = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hAbortListen == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::InitializeNode - CreateEvent Failed m_hAbortMain %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
// the event to signal the threads to wakeup
|
|
m_hWaitIntervalListen = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hWaitIntervalListen == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::InitializeNode - CreateEvent Failed m_hWaitIntervalListen %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
m_hWaitIntervalMain = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hWaitIntervalMain == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::InitializeNode - CreateEvent Failed m_hWaitIntervalMain %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
// when sending a probe, the thread waits for this
|
|
m_hAnswer = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hAnswer == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::InitializeNode - CreateEvent Failed m_hAnswer %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
Overridden base handler functions
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::GetString
|
|
Implementation of ITFSNodeHandler::GetString
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(LPCTSTR)
|
|
CWinsStatusHandler::GetString
|
|
(
|
|
ITFSNode * pNode,
|
|
int nCol
|
|
)
|
|
{
|
|
if (nCol == 0 || nCol == -1)
|
|
return GetDisplayName();
|
|
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::OnAddMenuItems
|
|
Description
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CWinsStatusHandler::OnAddMenuItems
|
|
(
|
|
ITFSNode * pNode,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LPDATAOBJECT lpDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType,
|
|
long * pInsertionAllowed
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsStatusHandler::HasPropertyPages
|
|
Implementation of ITFSNodeHandler::HasPropertyPages
|
|
NOTE: the root node handler has to over-ride this function to
|
|
handle the snapin manager property page (wizard) case!!!
|
|
|
|
Author: KennT
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CWinsStatusHandler::HasPropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DATA_OBJECT_TYPES type,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
if (dwType & TFS_COMPDATA_CREATE)
|
|
{
|
|
// This is the case where we are asked to bring up property
|
|
// pages when the user is adding a new snapin. These calls
|
|
// are forwarded to the root node to handle.
|
|
hr = hrOK;
|
|
}
|
|
else
|
|
{
|
|
// we have property pages in the normal case
|
|
hr = hrOK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CreatePropertyPages
|
|
Description
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP
|
|
CWinsStatusHandler::CreatePropertyPages
|
|
(
|
|
ITFSNode * pNode,
|
|
LPPROPERTYSHEETCALLBACK lpProvider,
|
|
LPDATAOBJECT pDataObject,
|
|
LONG_PTR handle,
|
|
DWORD dwType
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
Assert(pNode->GetData(TFS_DATA_COOKIE) != 0);
|
|
|
|
// Object gets deleted when the page is destroyed
|
|
SPIComponentData spComponentData;
|
|
m_spNodeMgr->GetComponentData(&spComponentData);
|
|
|
|
CStatusNodeProperties * pStatProp =
|
|
new CStatusNodeProperties(pNode,
|
|
spComponentData,
|
|
m_spTFSCompData,
|
|
NULL);
|
|
|
|
Assert(lpProvider != NULL);
|
|
|
|
return pStatProp->CreateModelessSheet(lpProvider, handle);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::OnPropertyChange
|
|
Description
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::OnPropertyChange
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataobject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
LONG_PTR changeMask = 0;
|
|
|
|
CStatusNodeProperties * pProp
|
|
= reinterpret_cast<CStatusNodeProperties *>(lParam);
|
|
|
|
// tell the property page to do whatever now that we are back on the
|
|
// main thread
|
|
pProp->OnPropertyChange(TRUE, &changeMask);
|
|
|
|
pProp->AcknowledgeNotify();
|
|
|
|
if (changeMask)
|
|
pNode->ChangeNode(changeMask);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
HRESULT
|
|
CWinsStatusHandler::OnExpand
|
|
(
|
|
ITFSNode * pNode,
|
|
LPDATAOBJECT pDataObject,
|
|
DWORD dwType,
|
|
LPARAM arg,
|
|
LPARAM param
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
|
|
if (m_bExpanded)
|
|
return hr;
|
|
|
|
m_spNode.Set(pNode);
|
|
|
|
// build the list to hold the list of the servers
|
|
BuildServerList(pNode);
|
|
|
|
// Create the result pane data here
|
|
CreateNodes(pNode);
|
|
|
|
// start monitoring
|
|
StartMonitoring(pNode);
|
|
|
|
m_bExpanded = TRUE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*!--------------------------------------------------------------------------
|
|
CWinsStatusHandler::OnNotifyHaveData
|
|
-
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::OnNotifyHaveData
|
|
(
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
// The background wins monitoring stuff sends us a message to update the
|
|
// status column information
|
|
UpdateStatusColumn(m_spNode);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::OnResultRefresh
|
|
Base handler override
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::OnResultRefresh
|
|
(
|
|
ITFSComponent * pComponent,
|
|
LPDATAOBJECT pDataObject,
|
|
MMC_COOKIE cookie,
|
|
LPARAM arg,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
// wait up the monitoring thread
|
|
SetEvent(m_hWaitIntervalMain);
|
|
|
|
return hrOK;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CompareItems
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
STDMETHODIMP_(int)
|
|
CWinsStatusHandler::CompareItems
|
|
(
|
|
ITFSComponent * pComponent,
|
|
MMC_COOKIE cookieA,
|
|
MMC_COOKIE cookieB,
|
|
int nCol
|
|
)
|
|
{
|
|
SPITFSNode spNode1, spNode2;
|
|
|
|
m_spNodeMgr->FindNode(cookieA, &spNode1);
|
|
m_spNodeMgr->FindNode(cookieB, &spNode2);
|
|
|
|
int nCompare = 0;
|
|
|
|
CServerStatus * pWins1 = GETHANDLER(CServerStatus, spNode1);
|
|
CServerStatus * pWins2 = GETHANDLER(CServerStatus, spNode2);
|
|
|
|
switch (nCol)
|
|
{
|
|
// name
|
|
case 0:
|
|
{
|
|
nCompare = lstrcmp(pWins1->GetServerName(), pWins2->GetServerName());
|
|
}
|
|
break;
|
|
|
|
// status
|
|
case 1:
|
|
{
|
|
CString str1;
|
|
|
|
str1 = pWins1->GetStatus();
|
|
nCompare = str1.CompareNoCase(pWins2->GetStatus());
|
|
}
|
|
break;
|
|
}
|
|
|
|
return nCompare;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::BuildServerList
|
|
Description
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::BuildServerList(ITFSNode *pNode)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
// get the root node
|
|
SPITFSNode spRootNode;
|
|
|
|
m_spNodeMgr->GetRootNode(&spRootNode);
|
|
|
|
// enumerate thro' all the nodes
|
|
HRESULT hr = hrOK;
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
BOOL bFound = FALSE;
|
|
|
|
// get the enumerator for this node
|
|
spRootNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
while (nNumReturned)
|
|
{
|
|
// iterate to teh next node, if the status handler node is seen
|
|
const GUID* pGuid;
|
|
|
|
pGuid = spCurrentNode->GetNodeType();
|
|
|
|
if (*pGuid != GUID_WinsServerStatusNodeType)
|
|
{
|
|
// add to the list
|
|
CServerStatus* pServ = NULL;
|
|
|
|
char szBuffer[MAX_PATH];
|
|
|
|
CWinsServerHandler * pServer
|
|
= GETHANDLER(CWinsServerHandler, spCurrentNode);
|
|
|
|
CString strTemp = pServer->GetServerAddress();
|
|
|
|
// this should be ACP
|
|
WideToMBCS(strTemp, szBuffer);
|
|
|
|
pServ = new CServerStatus(m_spTFSCompData);
|
|
|
|
strcpy(pServ->szServerName, szBuffer);
|
|
pServ->dwIPAddress = pServer->GetServerIP();
|
|
pServ->dwMsgCount = 0;
|
|
strcpy(pServ->szIPAddress, "");
|
|
|
|
m_listServers.Add(pServ);
|
|
}
|
|
|
|
// get the next Server in the list
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CreateListeningSockets( )
|
|
Abstract:
|
|
This function initializes Winsock and opens a socket that listens
|
|
to bcasts the DHCP srv sends to UDP port 68.
|
|
Arguments:
|
|
pListenSockCl - reference to the socket we're going to open
|
|
(argument passed by reference - clean but hidden)
|
|
this socket will listen on the DHCP client port
|
|
so that it can pick up bcasts on the local segmnt
|
|
pListenSockSrv - reference to the socket we're going to open
|
|
(argument passed by reference - clean but hidden)
|
|
this socket will listen on the DHCP server port
|
|
so that it can pick up unicasts to the "relay"
|
|
listenNameSvcSock - reference to the socket we're going to open
|
|
(argument passed by reference - clean but hidden)
|
|
this socket will listen on the NBT name svc port
|
|
so that it can pick up answers from the WINS srv
|
|
We have to do this on the socket layer because on
|
|
the NetBIOS layer we wouldn't notice that a name
|
|
query has been resolved by bcasting.
|
|
Return value:
|
|
none
|
|
--------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::CreateListeningSockets( )
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
int nResult = 0; // status info returned from function calls
|
|
WSADATA wsaData; // WinSock startup details buffer
|
|
DWORD optionValue; // helper var for setsockopt()
|
|
SOCKADDR_IN sockAddr; // struct holding source socket info
|
|
|
|
// the event to signal listening thread to pause
|
|
m_hPauseListening = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (m_hPauseListening == NULL)
|
|
{
|
|
Trace1("WinsStatusHandler::CreateListeningSockets - CreateEvent Failed m_hPauseListening %d\n", ::GetLastError());
|
|
return HRESULT_FROM_WIN32(::GetLastError());
|
|
}
|
|
|
|
// create socket to listen to the WINS servers on the client port (same subnet)
|
|
listenSockCl = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
|
if ( listenSockCl == INVALID_SOCKET )
|
|
{
|
|
Trace1("\nError %d creating socket to listen to WINS traffic.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = TRUE;
|
|
if ( setsockopt(listenSockCl, SOL_SOCKET, SO_REUSEADDR, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = TRUE;
|
|
if ( setsockopt(listenSockCl, SOL_SOCKET, SO_BROADCAST, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
sockAddr.sin_family = PF_INET;
|
|
sockAddr.sin_addr.s_addr = 0; // use any local address
|
|
sockAddr.sin_port = htons( DHCP_CLIENT_PORT );
|
|
RtlZeroMemory( sockAddr.sin_zero, 8 );
|
|
|
|
if ( bind(listenSockCl, (LPSOCKADDR )&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR )
|
|
{
|
|
Trace1("\nError %d binding the listening socket.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
|
|
// create socket to listen to the WINS servers on the server port (remote subnet, fake relay)
|
|
listenSockSrv = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
|
if ( listenSockSrv == INVALID_SOCKET )
|
|
{
|
|
Trace1("\nError %d creating socket to listen to DHCP traffic.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = TRUE;
|
|
if ( setsockopt(listenSockSrv, SOL_SOCKET, SO_REUSEADDR, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = TRUE;
|
|
if ( setsockopt(listenSockSrv, SOL_SOCKET, SO_BROADCAST, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
sockAddr.sin_family = PF_INET;
|
|
sockAddr.sin_addr.s_addr = 0; // use any local address
|
|
sockAddr.sin_port = htons( DHCP_SERVR_PORT );
|
|
RtlZeroMemory( sockAddr.sin_zero, 8 );
|
|
|
|
if ( bind(listenSockSrv, (LPSOCKADDR )&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR )
|
|
{
|
|
Trace1("\nError %d binding the listening socket.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
|
|
// create socket to listen to name svc responses from the WINS server
|
|
listenNameSvcSock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
|
if ( listenNameSvcSock == INVALID_SOCKET )
|
|
{
|
|
Trace1("\nError %d creating socket to listen to WINS traffic.\n", WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = TRUE;
|
|
if ( setsockopt(listenNameSvcSock, SOL_SOCKET, SO_REUSEADDR, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
optionValue = FALSE;
|
|
if ( setsockopt(listenNameSvcSock, SOL_SOCKET, SO_BROADCAST, (const char *)&optionValue, sizeof(optionValue)) )
|
|
{
|
|
Trace1("\nError %d setting SO_REUSEADDR option.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
sockAddr.sin_family = PF_INET;
|
|
sockAddr.sin_addr.s_addr = INADDR_ANY;
|
|
sockAddr.sin_port = 0;
|
|
RtlZeroMemory( sockAddr.sin_zero, 8 );
|
|
|
|
if ( bind(listenNameSvcSock, (LPSOCKADDR )&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR )
|
|
{
|
|
Trace1("\nError %d binding the listening socket.\n",
|
|
WSAGetLastError() );
|
|
return HRESULT_FROM_WIN32(WSAGetLastError());
|
|
}
|
|
|
|
return hrOK;
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::ListeningThreadFunc( )
|
|
Abstract:
|
|
A blocking recvfrom() is sitting in an infinite loop. Whenever we
|
|
receive anything on our listening socket we do a quick sanity chk
|
|
on the packet and then increment a counter.
|
|
The processing is kept minimal to spare the CPU cycles.
|
|
Arguments:
|
|
pListenSock - pointer to the socket set we've opened to listen for
|
|
xmits from the server
|
|
Return value:
|
|
none
|
|
---------------------------------------------------------------------------*/
|
|
DWORD WINAPI
|
|
CWinsStatusHandler::ListeningThreadFunc( )
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
SOCKADDR_IN senderSockAddr;
|
|
int nSockAddrSize = sizeof( senderSockAddr );
|
|
int nBytesRcvd = 0;
|
|
int nSocksReady;
|
|
char MsgBuf[WINS_MESSAGE_SIZE];
|
|
int nSockNdx;
|
|
LPBYTE MagicCookie;
|
|
SOCKET listenSock;
|
|
fd_set localSockSet; // to take care of reinit for select()
|
|
char szOutput[MAX_PATH];
|
|
|
|
while ( TRUE )
|
|
{
|
|
// check if the thread needs to be aborted
|
|
if (WaitForSingleObject(m_hPauseListening, 0) == WAIT_OBJECT_0)
|
|
{
|
|
Trace0("CWinsStatusHandler::ListenThreadFun - going to sleep\n");
|
|
|
|
// wait until we are woken up or the next time interval expires
|
|
WaitForSingleObject(m_hWaitIntervalListen, INFINITE);
|
|
Trace0("CWinsStatusHandler::ListenThreadFun - waking up\n");
|
|
}
|
|
|
|
if (WaitForSingleObject(m_hAbortListen, 0) == WAIT_OBJECT_0)
|
|
{
|
|
// we are going away.. break out man
|
|
Trace0("CWinsStatusHandler::ListenThreadFun - abort detected, bye bye\n");
|
|
break;
|
|
}
|
|
|
|
// reinit the select set in every loop
|
|
localSockSet = m_listenSockSet;
|
|
|
|
timeval tm;
|
|
tm.tv_sec = 5;
|
|
|
|
// number of sockets ready
|
|
nSocksReady = select( 0, &localSockSet, NULL, NULL, &tm );
|
|
if ( nSocksReady == SOCKET_ERROR )
|
|
{
|
|
Trace1("select() failed with error %d.\n", WSAGetLastError() );
|
|
}
|
|
|
|
for ( nSockNdx = 0; nSockNdx < nSocksReady; nSockNdx++ )
|
|
{
|
|
listenSock = localSockSet.fd_array[nSockNdx];
|
|
|
|
nBytesRcvd = recvfrom( listenSock, MsgBuf, sizeof(MsgBuf), 0, (LPSOCKADDR )&senderSockAddr, &nSockAddrSize );
|
|
if ( nBytesRcvd == SOCKET_ERROR )
|
|
{
|
|
Trace1( "recvfrom() failed with error %d.\n", WSAGetLastError() );
|
|
}
|
|
|
|
strcpy(szOutput, (LPSTR)inet_ntoa(senderSockAddr.sin_addr));
|
|
CString strOutput(szOutput);
|
|
|
|
Trace2("ListeningThreadFunc(): processing frame from %s port %d \n", strOutput, ntohs(senderSockAddr.sin_port));
|
|
|
|
// process incoming WINS
|
|
if ( (listenSock == listenNameSvcSock) &&
|
|
(senderSockAddr.sin_port == NBT_NAME_SERVICE_PORT)
|
|
)
|
|
{
|
|
strcpy(szOutput, (LPSTR)inet_ntoa(senderSockAddr.sin_addr));
|
|
CString str(szOutput);
|
|
|
|
Trace1("ListeningThreadFunc(): processing WINS frame from %s \n", str);
|
|
|
|
int nCount = GetListSize();
|
|
for ( int i=0; i < nCount ; i++)
|
|
{
|
|
CServerStatus *pWinsSrvEntry = GetServer(i);
|
|
|
|
// check if the server has been deleted in the scope pane
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
// get the iP address for the server
|
|
DWORD dwIPAdd = pWinsSrvEntry->dwIPAddress;
|
|
CString strIP;
|
|
::MakeIPAddress(dwIPAdd, strIP);
|
|
|
|
char szBuffer[MAX_PATH] = {0};
|
|
|
|
// convert to mbcs
|
|
// NOTE: this should be ACP because its being handed to a winsock call
|
|
WideToMBCS(strIP, szBuffer);
|
|
|
|
// check if the server has been deleted in the scope pane
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
if (dwIPAdd == 0)
|
|
strcpy(szBuffer, pWinsSrvEntry->szIPAddress);
|
|
|
|
DWORD dwSrvIPAdd = inet_addr( szBuffer );
|
|
|
|
if ( senderSockAddr.sin_addr.s_addr == dwSrvIPAdd )
|
|
{
|
|
// check if the server has been deleted in the scope pane
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
pWinsSrvEntry->dwMsgCount++;
|
|
|
|
struct in_addr addrStruct;
|
|
addrStruct.s_addr = dwSrvIPAdd;
|
|
|
|
strcpy(szOutput, inet_ntoa(addrStruct));
|
|
CString str(szOutput);
|
|
Trace1("ListeningThreadFunc(): WINS msg received from %s \n", str );
|
|
|
|
// notify the thread we got something
|
|
SetEvent(m_hAnswer);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
} /* END OF for() processing indicated sockets from select() */
|
|
|
|
} /* END OF while( TRUE ) */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
int CWinsHandler::Probe()
|
|
Assembles and sends a name query to the WINS server.
|
|
Arguments:
|
|
none
|
|
Return value:
|
|
TRUE if a response has been received from the server
|
|
FALSE otherwise
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CWinsStatusHandler::Probe(
|
|
CServerStatus *pServer,
|
|
SOCKET listenNameSvcSock
|
|
)
|
|
{
|
|
NM_FRAME_HDR *pNbtHeader = (NM_FRAME_HDR *)pServer->nbtFrameBuf;
|
|
NM_QUESTION_SECT *pNbtQuestion = (NM_QUESTION_SECT *)( pServer->nbtFrameBuf + sizeof(NM_FRAME_HDR) );
|
|
char *pDest, *pName;
|
|
struct sockaddr_in destSockAddr; // struct holding dest socket info
|
|
int nBytesSent = 0;
|
|
// char m_szNameToQry[MAX_PATH] = "Rhino1";
|
|
|
|
|
|
/* RFC 1002 section 4.2.12
|
|
|
|
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
|
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
| NAME_TRN_ID |0| 0x0 |0|0|1|0|0 0|B| 0x0 |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
| 0x0001 | 0x0000 |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
| 0x0000 | 0x0000 |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
| |
|
|
/ QUESTION_NAME /
|
|
/ /
|
|
| |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
| NB (0x0020) | IN (0x0001) |
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
*/
|
|
|
|
pNbtHeader->xid = NM_QRY_XID;
|
|
pNbtHeader->flags = NBT_NM_OPC_QUERY |
|
|
NBT_NM_OPC_REQUEST |
|
|
NBT_NM_FLG_RECURS_DESRD;
|
|
pNbtHeader->question_cnt = 0x0100;
|
|
pNbtHeader->answer_cnt = 0;
|
|
pNbtHeader->name_serv_cnt = 0;
|
|
pNbtHeader->additional_cnt = 0;
|
|
|
|
// pDest is filling nbtQuestion->q_name
|
|
pNbtQuestion->q_type = NBT_NM_QTYP_NB;
|
|
pNbtQuestion->q_class = NBT_NM_QCLASS_IN;
|
|
|
|
//
|
|
// translate the name
|
|
//
|
|
pDest = (char *)&(pNbtQuestion->q_name);
|
|
pName = pServer->szServerName;
|
|
// the first byte of the name is the length field = 2*16
|
|
*pDest++ = NBT_NAME_SIZE;
|
|
|
|
// step through name converting ascii to half ascii, for 32 times
|
|
|
|
for ( int i = 0; i < (NBT_NAME_SIZE / 2) ; i++ ) {
|
|
*pDest++ = (*pName >> 4) + 'A';
|
|
*pDest++ = (*pName++ & 0x0F) + 'A';
|
|
}
|
|
*pDest++ = '\0';
|
|
*pDest = '\0';
|
|
|
|
// check if the server has been deleted in the scope pane
|
|
if (IsServerDeleted(pServer))
|
|
return FALSE;
|
|
|
|
CString strIP;
|
|
DWORD dwIPAdd = pServer->dwIPAddress;
|
|
|
|
// even then 0 means, invalid server
|
|
if (dwIPAdd == 0 && strcmp(pServer->szIPAddress, "") == 0)
|
|
return FALSE;
|
|
|
|
::MakeIPAddress(dwIPAdd, strIP);
|
|
char szBuffer[MAX_PATH] = {0};
|
|
|
|
// convert to mbcs
|
|
// NOTE: this should be ACP because it is being used in a winsock call
|
|
WideToMBCS(strIP, szBuffer);
|
|
|
|
// if the name is not yet resolved
|
|
if (dwIPAdd == 0)
|
|
{
|
|
strcpy(szBuffer, pServer->szIPAddress);
|
|
}
|
|
|
|
DWORD dwSrvIPAdd = inet_addr( szBuffer );
|
|
|
|
//
|
|
// send the name query frame
|
|
//
|
|
destSockAddr.sin_family = PF_INET;
|
|
destSockAddr.sin_port = NBT_NAME_SERVICE_PORT;
|
|
destSockAddr.sin_addr.s_addr = dwSrvIPAdd;
|
|
for (int k = 0; k < 8 ; k++ ) { destSockAddr.sin_zero[k] = 0; }
|
|
|
|
struct in_addr addrStruct;
|
|
addrStruct.s_addr = dwSrvIPAdd;
|
|
Trace1( "CWinsSrv::Probe(): sending probe Name Query to %s \n", strIP);
|
|
|
|
nBytesSent = sendto( listenNameSvcSock,
|
|
(PCHAR )pServer->nbtFrameBuf,
|
|
sizeof(NM_FRAME_HDR) + sizeof(NM_QUESTION_SECT),
|
|
0,
|
|
(struct sockaddr *)&destSockAddr,
|
|
sizeof( struct sockaddr )
|
|
);
|
|
|
|
if ( nBytesSent == SOCKET_ERROR )
|
|
{
|
|
Trace1("CWinsSrv::Probe(): Error %d in sendto().\n", WSAGetLastError() );
|
|
}
|
|
|
|
//
|
|
// the other thread should see the incoming frame and increment dwMsgCount
|
|
//
|
|
WaitForSingleObject(m_hAnswer, ANSWER_TIMEOUT);
|
|
|
|
if ( pServer->dwMsgCount == 0 )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
} /* END OF Probe() */
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::ExecuteMonitoring()
|
|
Starts monitoring thread for the servers
|
|
Author: v-shubk
|
|
----------------------------------------------------------------------------*/
|
|
DWORD WINAPI
|
|
CWinsStatusHandler::ExecuteMonitoring()
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HANDLE hListeningThread;
|
|
CServerStatus *pWinsSrvEntry = NULL;
|
|
|
|
// create listening thread
|
|
FD_ZERO( &m_listenSockSet );
|
|
FD_SET( listenSockCl, &m_listenSockSet );
|
|
FD_SET( listenSockSrv, &m_listenSockSet );
|
|
FD_SET( listenNameSvcSock, &m_listenSockSet );
|
|
|
|
m_hListenThread = CreateThread( NULL, // handle can't be inherited
|
|
0, // default stack size
|
|
MonThreadProc, // thread function
|
|
this, // argument to the thread function
|
|
0, // start thread immediately
|
|
NULL
|
|
);
|
|
|
|
if (m_hListenThread == NULL )
|
|
{
|
|
Trace0("CWinsStatusHandler::ExecuteMonitoring() - Listening thread failed to start\n");
|
|
return hrOK;
|
|
}
|
|
|
|
// main checking loop
|
|
while ( TRUE )
|
|
{
|
|
// scanning the list of WINS servers
|
|
POSITION pos;
|
|
int nCount = GetListSize();
|
|
m_nServersUpdated = 0;
|
|
|
|
for (int i = 0; i < nCount; i++)
|
|
{
|
|
pWinsSrvEntry = GetServer(i);
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
UpdateStatus(i, IDS_ROOTNODE_STATUS_WORKING, ICON_IDX_SERVER_BUSY);
|
|
NotifyMainThread();
|
|
|
|
DWORD dwIPAdd = pWinsSrvEntry->dwIPAddress;
|
|
|
|
// if the server is not connected, try to get the host IP address
|
|
if (dwIPAdd == 0)
|
|
{
|
|
// get the server name and convert to MBCS. Get the IP for this server and try
|
|
// to check the status
|
|
char* dest_ip=NULL;
|
|
char hostname[MAX_PATH] ;
|
|
struct sockaddr_in dest;
|
|
unsigned addr =0;
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
strcpy(hostname,pWinsSrvEntry->szServerName);
|
|
|
|
HOSTENT *hp = gethostbyname(hostname);
|
|
|
|
if ((!hp) && (addr == INADDR_NONE) )
|
|
{
|
|
CString str(hostname);
|
|
Trace1("Unable to resolve %s \n",str);
|
|
SetIPAddress(i, NULL);
|
|
}
|
|
else if (!hp)
|
|
{
|
|
addr = inet_addr(hostname);
|
|
SetIPAddress(i, hostname);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (hp != NULL)
|
|
memcpy(&(dest.sin_addr),hp->h_addr, hp->h_length);
|
|
else
|
|
dest.sin_addr.s_addr = addr;
|
|
|
|
if (hp)
|
|
dest.sin_family = hp->h_addrtype;
|
|
else
|
|
dest.sin_family = AF_INET;
|
|
|
|
dest_ip = inet_ntoa(dest.sin_addr);
|
|
SetIPAddress(i, dest_ip);
|
|
}
|
|
}
|
|
|
|
CString strIP;
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
::MakeIPAddress(pWinsSrvEntry->dwIPAddress, strIP);
|
|
|
|
// TRY to probe max 3 times
|
|
if (pWinsSrvEntry->dwMsgCount == 0)
|
|
{
|
|
UINT uStatus = 0;
|
|
UINT uImage;
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
BOOL fResponding = FALSE;
|
|
|
|
if (pWinsSrvEntry->dwIPAddress != 0)
|
|
{
|
|
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
fResponding = Probe(pWinsSrvEntry, listenNameSvcSock);
|
|
if (fResponding)
|
|
break;
|
|
|
|
if (FCheckForAbort())
|
|
{
|
|
// we are going away.. break out man
|
|
Trace0("CWinsStatusHandler::ExecuteMonitoring() - abort detected, bye bye \n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check to see if we need to clear out
|
|
if (FCheckForAbort())
|
|
{
|
|
// we are going away.. break out man
|
|
Trace0("CWinsStatusHandler::ExecuteMonitoring() - abort detected, bye bye \n");
|
|
break;
|
|
}
|
|
|
|
if (!fResponding)
|
|
{
|
|
Trace1("Status is DOWN for the server %s \n", strIP);
|
|
uStatus = IDS_ROOTNODE_STATUS_DOWN;
|
|
uImage = ICON_IDX_SERVER_LOST_CONNECTION;
|
|
}
|
|
else
|
|
{
|
|
Trace1("Status is UP for the server %s \n", strIP);
|
|
uStatus = IDS_ROOTNODE_STATUS_UP;
|
|
uImage = ICON_IDX_SERVER_CONNECTED;
|
|
}
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
UpdateStatus(i, uStatus, uImage);
|
|
m_nServersUpdated++;
|
|
|
|
// update the last checked time
|
|
pWinsSrvEntry->m_timeLast = CTime::GetCurrentTime();
|
|
|
|
NotifyMainThread();
|
|
}
|
|
else
|
|
{
|
|
Trace2( "%d WINS msg from server %s - zeroing counter\n",
|
|
pWinsSrvEntry->dwMsgCount, strIP);
|
|
|
|
if (IsServerDeleted(pWinsSrvEntry))
|
|
continue;
|
|
|
|
pWinsSrvEntry->dwMsgCount = 0;
|
|
|
|
}
|
|
|
|
pWinsSrvEntry->dwMsgCount = 0;
|
|
|
|
}
|
|
|
|
// tell the listening thread to go to sleep
|
|
SetEvent(m_hPauseListening);
|
|
m_nServersUpdated = 0;
|
|
|
|
// wait for the next interval or if we are triggered
|
|
Trace1("CWinsStatusHandler::ExecuteMonitoring() - going to sleep for %d \n", m_dwUpdateInterval);
|
|
WaitForSingleObject(m_hWaitIntervalMain, m_dwUpdateInterval);
|
|
Trace0("CWinsStatusHandler::ExecuteMonitoring() - waking up\n");
|
|
|
|
// wake up the listening thread
|
|
SetEvent(m_hWaitIntervalListen);
|
|
|
|
if (FCheckForAbort())
|
|
{
|
|
// we are going away.. break out man
|
|
Trace0("CWinsStatusHandler::ExecuteMonitoring() - abort detected, bye bye \n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CloseSockets
|
|
Closes all the socket connections that were opened
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
BOOL
|
|
CWinsStatusHandler::FCheckForAbort()
|
|
{
|
|
BOOL fAbort = FALSE;
|
|
|
|
if (WaitForSingleObject(m_hAbortMain, 0) == WAIT_OBJECT_0)
|
|
{
|
|
// we are going away.. break out man
|
|
fAbort = TRUE;
|
|
}
|
|
|
|
return fAbort;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CloseSockets
|
|
Closes all the socket connections that were opened
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::CloseSockets()
|
|
{
|
|
// final clean up
|
|
if (closesocket(listenSockCl) == SOCKET_ERROR)
|
|
{
|
|
Trace1("closesocket(listenSockCl) failed with error %d.\n", WSAGetLastError());
|
|
}
|
|
|
|
if (closesocket(listenSockSrv) == SOCKET_ERROR)
|
|
{
|
|
Trace1("closesocket(listenSockSrv) failed with error %d.\n", WSAGetLastError());
|
|
}
|
|
|
|
if (closesocket(listenNameSvcSock) == SOCKET_ERROR)
|
|
{
|
|
Trace1("closesocket(listenNameSvcSock) failed with error %d \n", WSAGetLastError());
|
|
}
|
|
|
|
// we're going away...
|
|
Trace0("CWinsStatusHandler::CloseSockets() - Setting abort event.\n");
|
|
SetEvent(m_hAbortListen);
|
|
SetEvent(m_hAbortMain);
|
|
|
|
// wake everybody up
|
|
Trace0("CWinsStatusHandler::CloseSockets() - waking up threads.\n");
|
|
SetEvent(m_hWaitIntervalListen);
|
|
SetEvent(m_hWaitIntervalMain);
|
|
SetEvent(m_hAnswer);
|
|
|
|
// terminate the threads
|
|
if (m_hListenThread)
|
|
{
|
|
if (WaitForSingleObject(m_hListenThread, 5000) != WAIT_OBJECT_0)
|
|
{
|
|
Trace0("CWinsStatusHandler::CloseSockets() - ListenThread failed to cleanup!\n");
|
|
}
|
|
|
|
::CloseHandle(m_hListenThread);
|
|
m_hListenThread = NULL;
|
|
}
|
|
|
|
if (m_hMainMonThread)
|
|
{
|
|
if (WaitForSingleObject(m_hMainMonThread, 5000) != WAIT_OBJECT_0)
|
|
{
|
|
Trace0("CWinsStatusHandler::CloseSockets() - MainMonThread failed to cleanup!\n");
|
|
}
|
|
|
|
::CloseHandle(m_hMainMonThread);
|
|
m_hMainMonThread = NULL;
|
|
}
|
|
|
|
// clean up our events
|
|
if (m_hPauseListening)
|
|
{
|
|
::CloseHandle(m_hPauseListening);
|
|
m_hPauseListening = NULL;
|
|
}
|
|
|
|
if (m_hAbortListen)
|
|
{
|
|
::CloseHandle(m_hAbortListen);
|
|
m_hAbortListen = NULL;
|
|
}
|
|
|
|
if (m_hAbortMain)
|
|
{
|
|
::CloseHandle(m_hAbortMain);
|
|
m_hAbortMain = NULL;
|
|
}
|
|
|
|
if (m_hWaitIntervalListen)
|
|
{
|
|
::CloseHandle(m_hWaitIntervalListen);
|
|
m_hWaitIntervalListen = NULL;
|
|
}
|
|
|
|
if (m_hWaitIntervalMain)
|
|
{
|
|
::CloseHandle(m_hWaitIntervalMain);
|
|
m_hWaitIntervalMain = NULL;
|
|
}
|
|
|
|
if (m_hAnswer)
|
|
{
|
|
::CloseHandle(m_hAnswer);
|
|
m_hAnswer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::CreateNodes(ITFSNode *pNode)
|
|
Displays the result pane nodes for the servers
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::CreateNodes(ITFSNode *pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
POSITION pos = NULL;
|
|
|
|
int nCount = (int)m_listServers.GetSize();
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
{
|
|
SPITFSNode spStatLeaf;
|
|
|
|
CServerStatus *pWinsSrvEntry = m_listServers.GetAt(i);
|
|
|
|
CreateLeafTFSNode(&spStatLeaf,
|
|
&GUID_WinsServerStatusLeafNodeType,
|
|
pWinsSrvEntry,
|
|
pWinsSrvEntry,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pWinsSrvEntry->InitializeNode((ITFSNode *) spStatLeaf);
|
|
|
|
// Add the node as a child to the Active Leases container
|
|
pNode->AddChild(spStatLeaf);
|
|
|
|
pWinsSrvEntry->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::UpdateStatusColumn(ITFSNode *pNode)
|
|
Updates the status column of the servers in the result pane
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::UpdateStatusColumn(ITFSNode *pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
// enumerate thro' all the nodes
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
BOOL bFound = FALSE;
|
|
|
|
// get the enumerator for this node
|
|
pNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
|
|
while (nNumReturned)
|
|
{
|
|
CServerStatus * pStat = GETHANDLER(CServerStatus, spCurrentNode);
|
|
|
|
spCurrentNode->SetData(TFS_DATA_IMAGEINDEX, pStat->m_uImage);
|
|
spCurrentNode->SetData(TFS_DATA_OPENIMAGEINDEX, pStat->m_uImage);
|
|
|
|
// fillup the status column
|
|
spCurrentNode->ChangeNode(RESULT_PANE_CHANGE_ITEM);
|
|
|
|
// get the next Server in the list
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::AddNode(ITFSNode *pNode, CWinsServerHandler *pServer)
|
|
Adds a node to the result pane, used when a new server is added to
|
|
tree that has to be reflected for the status node
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::AddNode(ITFSNode *pNode, CWinsServerHandler *pServer)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
CServerStatus* pServ = NULL;
|
|
char szBuffer[MAX_PATH] = {0};
|
|
SPITFSNode spStatLeaf;
|
|
|
|
// if we haven't been expanded, don't add now. Will get done
|
|
// when we are expanded.
|
|
if (!m_bExpanded)
|
|
return hr;
|
|
|
|
// add to the list
|
|
// NOTE: this should be ACP because it's being used through winsock
|
|
CString strTemp = pServer->GetServerAddress();
|
|
WideToMBCS(strTemp, szBuffer);
|
|
|
|
// check if the server already exists, if so, just change the
|
|
// state stored to SERVER_ADDED and change the variables
|
|
// appropriately
|
|
if ((pServ = GetExistingServer(szBuffer)) == NULL)
|
|
{
|
|
pServ = new CServerStatus(m_spTFSCompData);
|
|
strcpy(pServ->szServerName, szBuffer);
|
|
AddServer(pServ);
|
|
}
|
|
else
|
|
{
|
|
// just add the related data to the CServerStatus and add the node
|
|
// to the UI
|
|
strcpy(pServ->szServerName, szBuffer);
|
|
// set the flag to SERVER_ADDED
|
|
MarkAsDeleted(szBuffer, FALSE);
|
|
}
|
|
|
|
pServ->dwIPAddress = pServer->GetServerIP();
|
|
pServ->dwMsgCount = 0;
|
|
strcpy(pServ->szIPAddress, "");
|
|
|
|
// create the new node here
|
|
CreateLeafTFSNode(&spStatLeaf,
|
|
&GUID_WinsServerStatusLeafNodeType,
|
|
pServ,
|
|
pServ,
|
|
m_spNodeMgr);
|
|
|
|
// Tell the handler to initialize any specific data
|
|
pServ->InitializeNode((ITFSNode *) spStatLeaf);
|
|
|
|
// Add the node as a child to the Active Leases container
|
|
pNode->AddChild(spStatLeaf);
|
|
|
|
pServ->Release();
|
|
|
|
spStatLeaf->ChangeNode(RESULT_PANE_CHANGE_ITEM_DATA);
|
|
pNode->ChangeNode(SCOPE_PANE_CHANGE_ITEM);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::DeleteNode(ITFSNode *pNode,
|
|
CWinsServerHandler *pServer)
|
|
Removes the particular server from tehresult pane
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
HRESULT
|
|
CWinsStatusHandler::DeleteNode(ITFSNode *pNode, CWinsServerHandler *pServer)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
HRESULT hr = hrOK;
|
|
CServerStatus* pServ = NULL;
|
|
char szBuffer[MAX_PATH];
|
|
SPITFSNode spStatLeaf;
|
|
|
|
// loop thro' the status nodes and set the flag to deleted so that this
|
|
// server is not seen in the result pane
|
|
|
|
SPITFSNodeEnum spNodeEnum;
|
|
SPITFSNode spCurrentNode;
|
|
ULONG nNumReturned = 0;
|
|
|
|
// get the enumerator
|
|
pNode->GetEnum(&spNodeEnum);
|
|
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
|
|
while (nNumReturned)
|
|
{
|
|
char szBuffer[MAX_PATH];
|
|
|
|
// iterate thro' all the nodes and get the one that matches the
|
|
// current server
|
|
CServerStatus * pStat = GETHANDLER(CServerStatus, spCurrentNode);
|
|
|
|
// convert to ANSI
|
|
CString strTemp = pServer->GetServerAddress();
|
|
WideToMBCS(strTemp, szBuffer);
|
|
|
|
// if found
|
|
if (_stricmp(szBuffer, pStat->szServerName) == 0)
|
|
{
|
|
// mark as deleted and break
|
|
MarkAsDeleted(szBuffer, TRUE);
|
|
|
|
// remove this node
|
|
spCurrentNode->SetVisibilityState(TFS_VIS_HIDE);
|
|
|
|
spCurrentNode->ChangeNode(RESULT_PANE_DELETE_ITEM);
|
|
|
|
// do the cleanup and break
|
|
//spCurrentNode.Release();
|
|
|
|
//break;
|
|
}
|
|
|
|
// get the next server in the list
|
|
spCurrentNode.Release();
|
|
spNodeEnum->Next(1, &spCurrentNode, &nNumReturned);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::StartMonitoring
|
|
Spawns off the monitoring thread
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::StartMonitoring(ITFSNode *pNode)
|
|
{
|
|
HRESULT hr = hrOK;
|
|
|
|
// create the sockets, they need to be closed at the end
|
|
hr = CreateListeningSockets();
|
|
|
|
if (hr != hrOK)
|
|
{
|
|
Trace0("CWinsStatusHandler::StartMonitoring, Initializing the sockets failed\n");
|
|
// no point continuing
|
|
return;
|
|
}
|
|
|
|
m_hMainMonThread = CreateThread(NULL,
|
|
0,
|
|
MainMonThread,
|
|
this,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (m_hMainMonThread == NULL)
|
|
{
|
|
Trace0("CWinsStatusHandler:: Main Monitoring thread failed to start\n");
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::GetServer(int i)
|
|
Returns the Server given the index
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
CServerStatus*
|
|
CWinsStatusHandler::GetServer(int i)
|
|
{
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
return m_listServers.GetAt(i);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::AddServer(CServerStatus* pServer)
|
|
Adds a server to the array maintained
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::AddServer(CServerStatus* pServer)
|
|
{
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
m_listServers.Add(pServer);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::RemoveServer(int i)
|
|
Removes a server from the array
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::RemoveServer(int i)
|
|
{
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
m_listServers.RemoveAt(i);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::UpdateStatus(UINT nID, int i)
|
|
Upadtes the status string for the server
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::UpdateStatus(int nIndex, UINT uStatusId, UINT uImage)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
CServerStatus *pStat = m_listServers.GetAt(nIndex);
|
|
|
|
pStat->m_strStatus.LoadString(uStatusId);
|
|
pStat->m_uImage = uImage;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::GetListSize()
|
|
Retruns the number of elements in the array
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
int
|
|
CWinsStatusHandler::GetListSize()
|
|
{
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
return (int)m_listServers.GetSize();
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::SetIPAddress(int i, LPSTR szIP)
|
|
Sets the iP Address of the server, this is the case when the server
|
|
is added with Do not connect option, but we still need to update the
|
|
status
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::SetIPAddress(int i, LPSTR szIP)
|
|
{
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
CServerStatus *pStat = m_listServers.GetAt(i);
|
|
|
|
strcpy(pStat->szIPAddress, szIP);
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::MarkAsDeleted(LPSTR szBuffer, BOOL bDelete)
|
|
Marks the flag to DELETED if bDelete is TRUE, else to ADDED
|
|
All the servers with the flag DELETED set are not processed
|
|
and are not shown in the UI.
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::MarkAsDeleted(LPSTR szBuffer, BOOL bDelete)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
int nCount = 0;
|
|
CServerStatus *pStat = NULL;
|
|
|
|
// get the list of the servers maintained
|
|
nCount = (int)m_listServers.GetSize();
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
{
|
|
pStat = m_listServers.GetAt(i);
|
|
|
|
if (_stricmp(szBuffer, pStat->szServerName) == 0)
|
|
{
|
|
// set the deleted flag
|
|
if (bDelete)
|
|
pStat->dwState = SERVER_DELETED;
|
|
else
|
|
pStat->dwState = SERVER_ADDED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::GetExistingServer(LPSTR szBuffer)
|
|
Gets the pointer to the existing server in the array
|
|
This function is useful when the server is deletd and again added back
|
|
to the scope tree.
|
|
Author: v-shubk
|
|
----------------------------------------------------------------------------*/
|
|
CServerStatus *
|
|
CWinsStatusHandler::GetExistingServer(LPSTR szBuffer)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
CSingleLock sl(&m_cs);
|
|
sl.Lock();
|
|
|
|
int nCount = 0;
|
|
CServerStatus *pStat = NULL;
|
|
|
|
for(int i = 0; i < nCount; i++)
|
|
{
|
|
pStat = m_listServers.GetAt(i);
|
|
|
|
if (_strcmpi(pStat->szServerName, szBuffer) == 0)
|
|
return pStat;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::IsServerDeleted(CServerStatus *pStat)
|
|
Checks if a server has been deleted, such servers
|
|
sre not considered for monitoring
|
|
Author: v-shubk
|
|
---------------------------------------------------------------------------*/
|
|
BOOL
|
|
CWinsStatusHandler::IsServerDeleted(CServerStatus *pStat)
|
|
{
|
|
return (pStat->dwState == SERVER_DELETED) ? TRUE : FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
CWinsStatusHandler::NotifyMainThread()
|
|
Description
|
|
Author: EricDav
|
|
---------------------------------------------------------------------------*/
|
|
void
|
|
CWinsStatusHandler::NotifyMainThread()
|
|
{
|
|
if (!m_uMsgBase)
|
|
{
|
|
m_uMsgBase = (INT) ::SendMessage(m_spTFSCompData->GetHiddenWnd(), WM_HIDDENWND_REGISTER, TRUE, 0);
|
|
}
|
|
|
|
::PostMessage(m_spTFSCompData->GetHiddenWnd(),
|
|
m_uMsgBase + WM_HIDDENWND_INDEX_HAVEDATA,
|
|
(WPARAM)(ITFSThreadHandler *)this,
|
|
NULL);
|
|
}
|
|
|
|
|
|
// listening thread for the main monitoring thread
|
|
DWORD WINAPI
|
|
MonThreadProc(LPVOID pParam)
|
|
{
|
|
DWORD dwReturn;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CWinsStatusHandler * pWinsStatus = (CWinsStatusHandler *) pParam;
|
|
|
|
Trace0("MonThreadProc - Thread started.\n");
|
|
|
|
dwReturn = pWinsStatus->ListeningThreadFunc();
|
|
|
|
Trace0("MonThreadProc - Thread ending.\n");
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
// main monitoring thread
|
|
DWORD WINAPI MainMonThread(LPVOID pParam)
|
|
{
|
|
DWORD dwReturn;
|
|
HRESULT hr = hrOK;
|
|
|
|
COM_PROTECT_TRY
|
|
{
|
|
CWinsStatusHandler * pWinsStatus = (CWinsStatusHandler *) pParam;
|
|
|
|
Trace0("MainMonThread - Thread started.\n");
|
|
|
|
dwReturn = pWinsStatus->ExecuteMonitoring();
|
|
|
|
Trace0("MainMonThread - Thread ending.\n");
|
|
}
|
|
COM_PROTECT_CATCH
|
|
|
|
return dwReturn;
|
|
}
|
|
|