|
|
/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/
/*
winsdb.cpp Wins database enumerator
FILE HISTORY: Oct 13 1997 EricDav Modified
*/
#include "stdafx.h"
#include "wins.h"
#include "search.h"
#include "winsdb.h"
#include "tfschar.h"
IMPLEMENT_ADDREF_RELEASE(CWinsDatabase);
IMPLEMENT_SIMPLE_QUERYINTERFACE(CWinsDatabase, IWinsDatabase)
DEBUG_DECLARE_INSTANCE_COUNTER(CWinsDatabase)
CWinsDatabase::CWinsDatabase() : m_cRef(1), m_fFiltered(FALSE), m_fInitialized(FALSE), m_bShutdown(FALSE), m_hrLastError(hrOK) { DEBUG_INCREMENT_INSTANCE_COUNTER(CWinsDatabase);
SetCurrentState(WINSDB_NORMAL);
m_hBinding = NULL; m_hThread = NULL; m_hStart = NULL; m_hAbort = NULL; m_dwOwner = (DWORD)-1; m_strPrefix = NULL; m_dwRecsCount = 0; m_bEnableCache = FALSE; }
CWinsDatabase::~CWinsDatabase() { DEBUG_DECREMENT_INSTANCE_COUNTER(CWinsDatabase); m_bShutdown = TRUE;
if (m_strPrefix != NULL) delete m_strPrefix; SetEvent(m_hAbort); SetEvent(m_hStart); if (WaitForSingleObject(m_hThread, 30000) != WAIT_OBJECT_0) { Trace0("WinsDatabase destructor thread never died!\n");
// TerminateThread
}
CloseHandle(m_hAbort); CloseHandle(m_hStart); CloseHandle(m_hThread); }
/*!--------------------------------------------------------------------------
CWinsDatabase::Init Implementation of IWinsDatabase::Init Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Init() { HRESULT hr = hrOK; WINSDB_STATE uCurrentState;
m_dwRecsCount = 0;
COM_PROTECT_TRY { CORg (GetCurrentState(&uCurrentState)); if (uCurrentState != WINSDB_NORMAL) { Trace1("WinsDatabase::Init - called when database busy - state %d\n", uCurrentState); return E_FAIL; }
CORg (m_cMemMan.Initialize()); CORg (m_IndexMgr.Initialize());
m_hrLastError = hrOK;
CORg (SetCurrentState(WINSDB_LOADING));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::Start Implementation of IWinsDatabase::Start Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Start() { // signal the thread to start loading
SetEvent(m_hStart);
return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::Initialize Implementation of IWinsDatabase::Initialize Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Initialize(LPCOLESTR pszName, LPCOLESTR pszIP) { HRESULT hr = hrOK; DWORD dwError; DWORD dwThreadId;
COM_PROTECT_TRY { m_strName = pszName; m_strIp = pszIP;
CORg (m_cMemMan.Initialize()); CORg (m_IndexMgr.Initialize());
m_hStart = ::CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hStart == NULL) { dwError = ::GetLastError(); Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hStart %d\n", dwError); return HRESULT_FROM_WIN32(dwError); }
m_hAbort = ::CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hAbort == NULL) { dwError = ::GetLastError(); Trace1("WinsDatabase::Initialize - CreateEvent Failed m_hAbort %d\n", dwError); return HRESULT_FROM_WIN32(dwError); }
m_hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, &dwThreadId); if (m_hThread == NULL) { dwError = ::GetLastError(); Trace1("WinsDatabase::Init - CreateThread Failed %d\n", dwError); return HRESULT_FROM_WIN32(dwError); }
m_fInitialized = TRUE; COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::GetName Implementation of IWinsDatabase::GetName Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetName(LPOLESTR pszName, UINT cchMax) { HRESULT hr = hrOK; LPCTSTR pBuf;
COM_PROTECT_TRY { if (cchMax < (UINT) (m_strName.GetLength() / sizeof(TCHAR))) return E_FAIL;
StrnCpy(pszName, (LPCTSTR) m_strName, cchMax); } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetIP Implementation of IWinsDatabase::GetIP Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetIP(LPOLESTR pszIP, UINT cchMax) { HRESULT hr = hrOK; LPCTSTR pBuf;
COM_PROTECT_TRY { if (cchMax < (UINT) (m_strIp.GetLength() / sizeof(TCHAR))) return E_FAIL;
StrnCpy(pszIP, (LPCTSTR) m_strIp, cchMax);
} COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::Stop Implementation of IWinsDatabase::Stop Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Stop() { HRESULT hr = hrOK; WINSDB_STATE uState;
COM_PROTECT_TRY { CORg (GetCurrentState(&uState));
if (uState != WINSDB_LOADING) return hr;
SetEvent(m_hAbort);
CORg (SetCurrentState(WINSDB_NORMAL));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::Clear Clears the wins DB of all records Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Clear() { HRESULT hr = hrOK; WINSDB_STATE uState;
COM_PROTECT_TRY { CORg (GetCurrentState(&uState));
if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING) return E_FAIL;
if (uState == WINSDB_LOADING) { SetEvent(m_hAbort); CORg (SetCurrentState(WINSDB_NORMAL)); }
CORg (m_cMemMan.Initialize()); CORg (m_IndexMgr.Initialize()); m_dwOwner = (DWORD)-1; if (m_strPrefix != NULL) delete m_strPrefix; m_strPrefix = NULL;
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::GetLastError Returns the last error for async calls Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetLastError(HRESULT * pLastError) { HRESULT hr = hrOK; WINSDB_STATE uState;
COM_PROTECT_TRY { if (pLastError) *pLastError = m_hrLastError;
} COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::Sort Implementation of IWinsDatabase::Sort Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::Sort(WINSDB_SORT_TYPE SortType, DWORD dwSortOptions) { HRESULT hr = hrOK; WINSDB_STATE uState;
COM_PROTECT_TRY { CORg (GetCurrentState(&uState));
if (uState != WINSDB_NORMAL) return E_FAIL;
CORg (SetCurrentState(WINSDB_SORTING));
m_IndexMgr.Sort(SortType, dwSortOptions);
CORg (SetCurrentState(WINSDB_NORMAL));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetHRow Implementation of IWinsDatabase::GetHRow returns the HRow in the current sorted index Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetHRow(UINT uIndex, LPHROW hRow) { Assert(uIndex >= 0);
HRESULT hr = hrOK; WINSDB_STATE uState; int nCurrentCount;
COM_PROTECT_TRY { CORg (GetCurrentCount(&nCurrentCount));
if (uIndex > (UINT) nCurrentCount) return E_FAIL;
CORg (GetCurrentState(&uState)); if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING) return E_FAIL;
m_IndexMgr.GetHRow(uIndex, hRow);
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::GetRows Implementation of IWinsDatabase::GetRows Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetRows( ULONG uNumberOfRows, ULONG uStartPos, HROW* pHRow, int* nNumberOfRowsReturned) { int nCurrentCount; WINSDB_STATE uState; HRESULT hr = hrOK; int nReturnedRows = 0; int i; HROW hrowCur;
Assert (uStartPos >= 0);
COM_PROTECT_TRY { CORg (GetCurrentState(&uState)); if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING) return E_FAIL;
CORg (GetCurrentCount(&nCurrentCount)); Assert ((int) uStartPos <= nCurrentCount); if (uStartPos > (UINT) nCurrentCount) return E_FAIL;
for (i = (int) uStartPos; i < (int) (uStartPos + uNumberOfRows); i++) { if( i > nCurrentCount ) { break; }
CORg (m_IndexMgr.GetHRow(i, &hrowCur));
// if the row is marked deleted, don't add it to the array
// REVIEW: directly accessing memory here.. we may want to change this
// to go through the memory manager
if ( ((LPWINSDBRECORD) hrowCur)->szRecordName[17] & WINSDB_INTERNAL_DELETED ) { continue; }
// fill in the data
pHRow[i-uStartPos] = hrowCur; nReturnedRows++; }
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
if (nNumberOfRowsReturned) *nNumberOfRowsReturned = nReturnedRows;
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetData Implementation of IWinsDatabase::GetData returns the HRow in the current sorted index Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetData(HROW hRow, LPWINSRECORD pRecordData) { HRESULT hr = E_FAIL;
COM_PROTECT_TRY { CORg (m_cMemMan.GetData(hRow, pRecordData));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::FindRow Implementation of IWinsDatabase::FindRow Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::FindRow(LPCOLESTR pszName, HROW hrowStart, HROW * phRow) { HRESULT hr = E_FAIL; WinsRecord ws; int nIndex, nPos, nCurrentCount; HROW hrowCur; HROW hrowFound = NULL; char szName[MAX_PATH];
CString strTemp(pszName);
// this should be OEM
WideToMBCS(strTemp, szName, WINS_NAME_CODE_PAGE);
COM_PROTECT_TRY { CORg (m_IndexMgr.GetIndex(hrowStart, &nIndex)); /////
CORg(GetHRow(nIndex, &hrowCur)); CORg (m_IndexMgr.GetIndex(hrowCur, &nIndex));
CORg (GetCurrentCount(&nCurrentCount));
if(nIndex != -1) {
CORg(GetHRow(nIndex, &hrowCur));
for (nPos = nIndex + 1; nPos < nCurrentCount; nPos++) { CORg(GetHRow(nPos, &hrowCur)); CORg(GetData(hrowCur, &ws)); if(!_strnicmp(ws.szRecordName, szName, strlen(szName) )) { hrowFound = hrowCur; hr = hrOK; break; } } }
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
if (phRow) *phRow = hrowFound;
return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::GetTotalCount Implementation of IWinsDatabase::GetTotalCount Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetTotalCount(int * nTotalCount) { HRESULT hr = hrOK; COM_PROTECT_TRY { *nTotalCount = m_IndexMgr.GetTotalCount(); } COM_PROTECT_CATCH return hr; } /*!--------------------------------------------------------------------------
CWinsDatabase::GetCurrentCount Implementation of IWinsDatabase::GetCurrentCount returns the HRow in the current sorted index Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetCurrentCount(int * nCurrentCount) { HRESULT hr = hrOK;
COM_PROTECT_TRY { if (m_DBState == WINSDB_SORTING) *nCurrentCount = 0; else *nCurrentCount = m_IndexMgr.GetCurrentCount(); } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetCurrentScanned(int * nCurrentScanned) Implementation of IWinsDatabase::GetCurrentScanned returns the total number of records that were read from the server Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetCurrentScanned(int * nCurrentCount) { HRESULT hr = hrOK;
COM_PROTECT_TRY { *nCurrentCount = m_dwRecsCount; } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::AddRecord Implementation of IWinsDatabase::AddRecord Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::AddRecord(const LPWINSRECORD pRecordData) { HRESULT hr = hrOK;
COM_PROTECT_TRY { // critical sections taken care by the memory manager
HROW hrow = NULL; CORg (m_cMemMan.AddData(*pRecordData, &hrow)); CORg (m_IndexMgr.AddHRow(hrow));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hrOK; } /*!--------------------------------------------------------------------------
CWinsDatabase::DeleteRecord Implementation of IWinsDatabase::DeleteRecord Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::DeleteRecord(HROW hrowRecord) { HRESULT hr = hrOK; WINSDB_STATE uState; COM_PROTECT_TRY { CORg (GetCurrentState(&uState));
if (uState != WINSDB_NORMAL) return E_FAIL;
// make sure the hrow is a valid one
if (!m_cMemMan.IsValidHRow(hrowRecord)) return E_FAIL;
// Tell the memmgr to delete this record
CORg (m_cMemMan.Delete(hrowRecord));
// now tell the index manager to remove this hrow
CORg (m_IndexMgr.RemoveHRow(hrowRecord));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetCurrentState Implementation of IWinsDatabase::GetCurrentState Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetCurrentState(WINSDB_STATE * pState) { CSingleLock cl(&m_csState); cl.Lock();
*pState = m_DBState; return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::SetCurrentState Helper function to set the current state, protected Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::SetCurrentState(WINSDB_STATE winsdbState) { CSingleLock cl(&m_csState); cl.Lock();
m_DBState = winsdbState; return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::FilterRecords Implementation of IWinsDatabase::FilterRecords Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::FilterRecords ( WINSDB_FILTER_TYPE FilterType, DWORD dwParam1, DWORD dwParam2) { HRESULT hr = E_NOTIMPL; WINSDB_STATE uState ;
COM_PROTECT_TRY { // fail if the state is other then WINSDB_NORMAL
CORg (GetCurrentState(&uState));
if (uState == WINSDB_SORTING || uState == WINSDB_FILTERING) return E_FAIL;
// if in the loading state the readrecords function takes care
if(uState != WINSDB_LOADING) CORg (SetCurrentState(WINSDB_FILTERING));
// do the filtering here, rebuild the filtered name Index
m_IndexMgr.Filter(FilterType, dwParam1, dwParam2);
if(uState != WINSDB_LOADING) CORg (SetCurrentState(WINSDB_NORMAL));
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::AddFilter Adds the filters specified to the list Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::AddFilter(WINSDB_FILTER_TYPE FilterType, DWORD dwParam1, DWORD dwParam2, LPCOLESTR strParam3) { HRESULT hr = hrOK; COM_PROTECT_TRY { // for filter by type, dwParam1 is the type, dwParam2 is show/not show
m_IndexMgr.AddFilter(FilterType, dwParam1, dwParam2, strParam3); } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::ClearFilter CLears all the filters Author: EricDav, v-shubk ---------------------------------------------------------------------------*/
HRESULT CWinsDatabase::ClearFilter(WINSDB_FILTER_TYPE FilterType) { HRESULT hr = hrOK;
COM_PROTECT_TRY { //CFilteredIndexName *pFilterName = (CFilteredIndexName *)m_IndexMgr.GetFilteredNameIndex();
//pFilterName->ClearFilter();
m_IndexMgr.ClearFilter(FilterType); } COM_PROTECT_CATCH
return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::SetActiveView Implementation of IWinsDatabase::SetActiveView Author: EricDav, v-shubk ---------------------------------------------------------------------------*/
HRESULT CWinsDatabase::SetActiveView(WINSDB_VIEW_TYPE ViewType) { HRESULT hr = hrOK;
COM_PROTECT_TRY { m_IndexMgr.SetActiveView(ViewType); } COM_PROTECT_CATCH
return hr;
}
/*!--------------------------------------------------------------------------
CWinsDatabase::Execute() The background thread calls into this to execute Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ DWORD CWinsDatabase::Execute() { DWORD dwStatus = 0;
// wait for the other thread to signal us to start doing something
while (::WaitForSingleObject(m_hStart, INFINITE) == WAIT_OBJECT_0) { if (m_bShutdown) break;
Trace0("WinsDatabase::Execute - start event signaled\n");
WINSINTF_BIND_DATA_T wbdBindData; handle_t hBinding = NULL;
do { // enumerate leases here
SetCurrentState(WINSDB_LOADING);
// now that the server name and ip are valid, call
// WINSBind function directly.
WINSINTF_ADD_T waWinsAddress;
DWORD dwStatus; CString strNetBIOSName;
// call WinsBind function with the IP address
wbdBindData.fTcpIp = 1; wbdBindData.pPipeName = NULL; // convert wbdBindData.pServerAdd to wide char again as one of the internal
// functions expects a wide char string, this is done in WinsABind which is bypassed for
// unicode compatible apps
wbdBindData.pServerAdd = (LPSTR) (LPCTSTR) m_strIp;
if ((hBinding = ::WinsBind(&wbdBindData)) == NULL) { dwStatus = ::GetLastError(); Trace1("WinsDatabase::Execute - WinsBind failed %lx\n", dwStatus); break; }
#ifdef WINS_CLIENT_APIS
dwStatus = ::WinsGetNameAndAdd( hBinding, &waWinsAddress, (BYTE *)strNetBIOSName.GetBuffer(128));
#else
dwStatus = ::WinsGetNameAndAdd( &waWinsAddress, (BYTE *)strNetBIOSName.GetBuffer(128));
#endif WINS_CLIENT_APIS
strNetBIOSName.ReleaseBuffer();
if (dwStatus == ERROR_SUCCESS) { if(m_dwOwner == (DWORD)-1) dwStatus = ReadRecords(hBinding); else dwStatus = ReadRecordsByOwner(hBinding);
break; } else { Trace1("WinsDatabase::Execute - WinsGetNameAndAdd failed %lx\n", dwStatus); break; } } while (FALSE);
SetCurrentState(WINSDB_NORMAL);
if(hBinding) { // call winsunbind here, the handle is invalid after this and that's fine
WinsUnbind(&wbdBindData, hBinding); hBinding = NULL; } Trace0("WinsDatabase::Execute - all done, going to sleep now...\n");
} // while !Start
Trace0("WinsDatabase::Execute - exiting\n"); return dwStatus; }
/*!--------------------------------------------------------------------------
CWinsDatabase::ReadRecords Reads records from the WINS server Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ DWORD CWinsDatabase::ReadRecords(handle_t hBinding) { DWORD dwStatus = ERROR_SUCCESS; DWORD err = ERROR_SUCCESS; CWinsResults winsResults; err = winsResults.Update(hBinding);
WINSINTF_RECS_T Recs; Recs.pRow = NULL; DWORD NoOfRecsDesired = 500; DWORD TypeOfRecs = 4; BOOL fReadAllRecords ;
PWINSINTF_RECORD_ACTION_T pRow; enum {ST_SCAN_1B_NAME, ST_SCAN_NORM_NAME} State; LPBYTE pLastName; UINT nLastNameLen, nLastBuffLen;
pLastName = NULL; nLastNameLen = 0; nLastBuffLen = 0;
#ifdef DEBUG
CTime timeStart, timeFinish; timeStart = CTime::GetCurrentTime(); #endif
m_dwRecsCount = 0;
// initialize the state machine. If we have a name prefix filter we
// start in ST_INIT_1B since we look first for the 1B names. These are
// particular in a sense their type byte - i.e. 0x1B - has been swapped
// with the first byte from the name. Consequently we need to do the same
// to allow WINS to look first for these names. Once we get over the 1B zone
// of our names, we restore the first byte and initiate another cycle for
// the rest of the name.
if (m_strPrefix != NULL) { nLastNameLen = nLastBuffLen = strlen(m_strPrefix) + 1; pLastName = (LPBYTE) new CHAR[nLastBuffLen]; strcpy((LPSTR)pLastName, m_strPrefix); pLastName[0] = 0x1B; State = ST_SCAN_1B_NAME; } else { State = ST_SCAN_NORM_NAME; }
do {
#ifdef WINS_CLIENT_APIS
err = ::WinsGetDbRecsByName( hBinding, NULL, WINSINTF_BEGINNING, pLastName, nLastNameLen, NoOfRecsDesired, TypeOfRecs, &Recs);
#else
err = ::WinsGetDbRecsByName( NULL, WINSINTF_BEGINNING, pFromName, LastNameLen, NoOfRecsDesired, TypeOfRecs, &Recs);
#endif WINS_CLIENT_APIS
// check to see if we need to abort
if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0) { Trace0("CWinsDatabase::ReadRecords - abort detected\n"); dwStatus = ERROR_OPERATION_ABORTED; break; }
if (err == ERROR_REC_NON_EXISTENT) { //
// Not a problem, there simply
// are no records in the database
//
Trace0("WinsDatabase::ReadRecords - no records in the Datbase\n"); fReadAllRecords = TRUE; err = ERROR_SUCCESS; break; }
if (err == ERROR_SUCCESS) { fReadAllRecords = Recs.NoOfRecs < NoOfRecsDesired; if (fReadAllRecords) Trace0("WinsDatabase::ReadRecords - Recs.NoOfRecs < NoOfRecsDesired, will exit\n");
TRY { DWORD i; pRow = Recs.pRow;
for (i = 0; i < Recs.NoOfRecs; ++i, ++pRow) { PWINSINTF_RECORD_ACTION_T pRow1 = Recs.pRow; WinsRecord wRecord; HROW hrow = NULL;
WinsIntfToWinsRecord(pRow, wRecord); if (pRow->OwnerId < (UINT) winsResults.AddVersMaps.GetSize()) { wRecord.dwOwner = winsResults.AddVersMaps[pRow->OwnerId].Add.IPAdd; } else { // having a record owned by a server which is not in the version map
// we got just earlier from WINS is not something that usually happens.
// It might happen only if the new owner was added right in between.
// Unlikely since this is a very small window - but if this happens
// just skip the record. From our point of view this owner doesn't exist
// hence the record doesn't belong to the view. It will show up with the
// first refresh.
continue; }
m_dwRecsCount++;
if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord)) continue;
// add the data to our memory store and
// to the sorted index
m_cMemMan.AddData(wRecord, &hrow); // if m_bEnableCache is 0 the the filter was checked
m_IndexMgr.AddHRow(hrow, TRUE, !m_bEnableCache);
//Trace1("%d records added to DB\n", m_dwRecsCount);
}
// if we reached the end of the DB there is no need to do
// anything from below. Is just pLastName that needs to be
// freed up - this is done outside the loop, before exiting
// the call.
if (!fReadAllRecords) { BOOL fRangeOver = FALSE;
// get to the last record that was retrieved.
--pRow;
// check if the last name retrieved from the server is still
// mathing the pattern prefix (if any) or the range has been
// passed over (fRangeOver)
if (m_strPrefix != NULL) { for (UINT i = 0; i < pRow->NameLen && m_strPrefix[i] != 0; i++) { if (m_strPrefix[i] != pRow->pName[i]) { fRangeOver = TRUE; break; } } }
// here fRangeOver is either TRUE if the name doesn't match the pattern
// prefix or FALSE if the range is not passed yet. This latter thing means
// either the name is included in the prefix or the prefix isn't included in the name
// !!! We might want to invalidate the "name included in the prefix" case.
if (fRangeOver) { switch(State) { case ST_SCAN_1B_NAME: // in this state pLastName is definitely not NULL and even more,
// it once copied m_strPrefix. Since pLastName can only grow, it is
// certain it is large enough to cotain m_strPrefix one more time.
strcpy((LPSTR)pLastName, m_strPrefix); nLastNameLen = strlen((LPCSTR)pLastName); State = ST_SCAN_NORM_NAME; break; case ST_SCAN_NORM_NAME: // we were scanning normal names and we passed
// over the range of names we are looking for
// so just get out of the loop.
fReadAllRecords = TRUE; break; } } else { // enlarge the pLastName if needed
if (nLastBuffLen < pRow->NameLen+2) { if (pLastName != NULL) delete pLastName; nLastBuffLen = pRow->NameLen+2; pLastName = (LPBYTE)new CHAR[nLastBuffLen]; } // copy in pLastName the name of the last record
strcpy((LPSTR)pLastName, (LPCSTR)(pRow->pName));
if (pRow->NameLen >= 16 && pLastName[15] == 0x1B) { CHAR ch = pLastName[15]; pLastName[15] = pLastName[0]; pLastName[0] = ch; }
strcat((LPSTR)pLastName, "\x01"); nLastNameLen = strlen((LPCSTR)pLastName); } } } CATCH_ALL(e) { err = ::GetLastError(); Trace1("WinsDatabase::ReadRecords - Exception! %d \n", err); m_hrLastError = HRESULT_FROM_WIN32(err); } END_CATCH_ALL } else { Trace1("WinsDatabase::ReadRecords - GetRecsByName failed! %d \n", err); m_hrLastError = HRESULT_FROM_WIN32(err); break; } if (Recs.pRow != NULL) { ::WinsFreeMem(Recs.pRow); }
} while(!fReadAllRecords );
if (pLastName != NULL) delete pLastName;
#ifdef DEBUG
timeFinish = CTime::GetCurrentTime(); CTimeSpan timeDelta = timeFinish - timeStart; CString strTempTime = timeDelta.Format(_T("%H:%M:%S")); Trace2("WINS DB - ReadRecords: %d records read, total time %s\n", m_dwRecsCount, strTempTime); #endif
return dwStatus; }
/*!--------------------------------------------------------------------------
ThreadProc - Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ DWORD WINAPI ThreadProc(LPVOID pParam) { DWORD dwReturn; HRESULT hr = hrOK;
COM_PROTECT_TRY { CWinsDatabase *pWinsDB = (CWinsDatabase *) pParam; Trace0("WinsDatabase Background Thread started.\n");
dwReturn = pWinsDB->Execute(); } COM_PROTECT_CATCH
return dwReturn; }
/*!--------------------------------------------------------------------------
WinsIntfToWinsRecord Converts a wins record from the server into the WinsRecord struct Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ void WinsIntfToWinsRecord(PWINSINTF_RECORD_ACTION_T pRecord, WinsRecord & wRecord) { ZeroMemory(&wRecord, sizeof(WinsRecord));
//::strcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName);
::memcpy(wRecord.szRecordName, (LPCSTR)pRecord->pName, pRecord->NameLen);
wRecord.dwExpiration = (ULONG) pRecord->TimeStamp; wRecord.liVersion = pRecord->VersNo; wRecord.dwOwner = pRecord->OwnerId; wRecord.dwNameLen = WINSINTF_NAME_LEN_M(pRecord->NameLen); wRecord.dwType |= (BYTE) wRecord.szRecordName[15];
// translate the state and types to our own definitions
switch (pRecord->State_e) { case WINSINTF_E_TOMBSTONE: wRecord.dwState |= WINSDB_REC_TOMBSTONE; break;
case WINSINTF_E_DELETED: //Trace0("WinsIntfToWinsRecord - deleted record.\n");
wRecord.dwState |= WINSDB_REC_DELETED; break;
case WINSINTF_E_RELEASED: //Trace0("WinsIntfToWinsRecord - released record.\n");
wRecord.dwState |= WINSDB_REC_RELEASED; break;
default: // WINSINTF_E_ACTIVE:
wRecord.dwState |= WINSDB_REC_ACTIVE; break; }
switch (pRecord->TypOfRec_e) { case WINSINTF_E_NORM_GROUP: wRecord.dwState |= WINSDB_REC_NORM_GROUP; break;
case WINSINTF_E_SPEC_GROUP: wRecord.dwState |= WINSDB_REC_SPEC_GROUP; break;
case WINSINTF_E_MULTIHOMED: wRecord.dwState |= WINSDB_REC_MULTIHOMED; break;
default: // WINSINTF_E_UNIQUE:
wRecord.dwState |= WINSDB_REC_UNIQUE; break; }
// now do the type -- move the value into the high word
DWORD dwTemp = (pRecord->TypOfRec_e << 16); wRecord.dwType |= dwTemp;
// now set the static flag
if (pRecord->fStatic) wRecord.dwState |= WINSDB_REC_STATIC;
// store all of the IP addrs
wRecord.dwNoOfAddrs = pRecord->NoOfAdds; if (pRecord->NoOfAdds > 1) { Assert(pRecord->NoOfAdds <= WINSDB_MAX_NO_IPADDRS); //if (wRecord.dwNoOfAddrs > 4)
// Trace1("WinsIntfToWinsRecord - record with multiple (>4) IP addrs: %d\n", wRecord.dwNoOfAddrs);
wRecord.dwState |= WINSDB_REC_MULT_ADDRS;
for (UINT i = 0; i < pRecord->NoOfAdds; i++) wRecord.dwIpAdd[i] = pRecord->pAdd[i].IPAdd; } else { if (pRecord->NoOfAdds == 0) { //Trace2("WinsIntfToWinsRecord - record with NoOfAdds == 0; IP: %lx State: %lx \n", pRecord->Add.IPAdd, wRecord.dwState);
}
if (pRecord->Add.IPAdd == 0) { Trace1("WinsIntfToWinsRecord - record with 0 IP Address! State: %lx \n", wRecord.dwState); }
wRecord.dwIpAdd[0] = pRecord->Add.IPAdd; } }
/*!--------------------------------------------------------------------------
CreateWinsDatabase - Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ HRESULT CreateWinsDatabase(CString& strName, CString& strIP, IWinsDatabase **ppWinsDB) { AFX_MANAGE_STATE(AfxGetModuleState()); CWinsDatabase * pWinsDB = NULL; HRESULT hr = hrOK;
SPIWinsDatabase spWinsDB;
COM_PROTECT_TRY { pWinsDB = new CWinsDatabase(); Assert(pWinsDB); spWinsDB = pWinsDB; CORg(pWinsDB->Initialize(strName, strIP)); *ppWinsDB = spWinsDB.Transfer();
COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH return hr; }
/*!--------------------------------------------------------------------------
CWinsDatabase::SetApiInfo Implementation of SetApiInfo of IWinsDatabase Author: FlorinT ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::SetApiInfo(DWORD dwOwner, LPCOLESTR strPrefix, BOOL bCache) { // first cleanup the old prefix
if (m_strPrefix != NULL) { delete m_strPrefix; m_strPrefix = NULL; }
if (strPrefix != NULL) { UINT nPxLen = 0; LPSTR pPrefix;
nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR); m_strPrefix = new char[nPxLen]; if (m_strPrefix != NULL) { #ifdef _UNICODE
if (WideCharToMultiByte(CP_OEMCP, 0, strPrefix, -1, m_strPrefix, nPxLen, NULL, NULL) == 0) { delete m_strPrefix; m_strPrefix = NULL; } #else
CharToOem(strPrefix, m_strPrefix); #endif
m_strPrefix = _strupr(m_strPrefix);
for (pPrefix = m_strPrefix; *pPrefix != '\0' && *pPrefix != '*' && *pPrefix != '?'; pPrefix++); *pPrefix = '\0'; } }
m_dwOwner = dwOwner;
m_bEnableCache = bCache;
return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::GetCachingFlag Implementation of GetCachingFlag of IWinsDatabase Author: FlorinT ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::GetCachingFlag(LPBOOL pbCache) { *pbCache = m_bEnableCache; return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::ReloadSuggested Implementation of ReloadSuggested of IWinsDatabase Author: FlorinT ---------------------------------------------------------------------------*/ HRESULT CWinsDatabase::ReloadSuggested(DWORD dwOwner, LPCOLESTR strPrefix, LPBOOL pbReload) { // check whether we filtered on a particular owner.
if (m_dwOwner != 0xFFFFFFFF) { // we did filter on owner previously, suggest RELOAD if we now
// don't want to filter on any owner (dwOwner == 0xffffffff)
// or the owner we want to filter is different from the original one
*pbReload = (m_dwOwner != dwOwner); } else { // we didn't filter on any owner previously so we either loaded
// all the records (if no name prefix was specified) or loaded
// all the records matching the given prefix
if (m_strPrefix != NULL) { // we did have a previous prefix to match so we need to see
// if the new prefix is not by any chance more specific than
// the original one. In which case there is no need to reload
LPSTR pPrefix; UINT nPxLen; UINT i;
if (strPrefix == NULL) { // if now we're not filtering by name, since we did previously
// we definitely need to reload the database
*pbReload = TRUE; return hrOK; }
nPxLen = (_tcslen(strPrefix)+1)*sizeof(TCHAR); pPrefix = new char[nPxLen]; if (pPrefix != NULL) { #ifdef _UNICODE
if (WideCharToMultiByte(CP_OEMCP, 0, strPrefix, -1, pPrefix, nPxLen, NULL, NULL) == 0) { delete pPrefix; *pbReload = TRUE; return hrOK; } #else
CharToOem(strPrefix, pPrefix); #endif
pPrefix = _strupr(pPrefix);
for (i = 0; pPrefix[i] != '\0' && pPrefix[i] != '*' && pPrefix[i] != '?'; i++); pPrefix[i] = '\0';
// we don't suggest database reloading only if the current prefix
// is a prefix for the new one to be applied. This way, whatever
// was retrieved previously already contains the names having the
// new prefix.
*pbReload = (strncmp(m_strPrefix, pPrefix, strlen(m_strPrefix)) != 0);
delete pPrefix; } else { // couldn't allocate memory -> serious enough to ask a full reload
*pbReload = TRUE; } } else { // well, there was no prefix specified last time the db was loaded so
// we should have the whole database in hand. No need to reload.
*pbReload = FALSE; } }
return hrOK; }
/*!--------------------------------------------------------------------------
CWinsDatabase::ReadRecordsByOwner Reads records from the WINS server for a particular owner Author: EricDav, v-shubk ---------------------------------------------------------------------------*/ #define MAX_DESIRED_RECORDS 400
#define LARGE_GAP_DETECT_COUNT 32
DWORD CWinsDatabase::ReadRecordsByOwner(handle_t hBinding) { DWORD err; CWinsResults winsResults; WINSINTF_RECS_T Recs; DWORD dwIP; LARGE_INTEGER MinVersNo, MaxVersNo; LARGE_INTEGER LowestVersNo; DWORD dwDesired; DWORD dwLargeGapCount; WINSINTF_ADD_T OwnerAdd; DWORD i;
err = winsResults.Update(hBinding); if (err != ERROR_SUCCESS) { m_hrLastError = HRESULT_FROM_WIN32(err); return err; }
MinVersNo.QuadPart= 0; for (i = 0; i < (int)winsResults.NoOfOwners; i++) { if (m_dwOwner == winsResults.AddVersMaps[i].Add.IPAdd) { MaxVersNo = winsResults.AddVersMaps[i].VersNo; break; } }
// if we couldn't find the owner (highly unlikely) get out
// with error INVALID_PARAMETER.
if (i == winsResults.NoOfOwners) { err = ERROR_INVALID_PARAMETER; m_hrLastError = HRESULT_FROM_WIN32(err); return err; }
m_dwRecsCount = 0;
OwnerAdd.Type = 0; OwnerAdd.Len = 4; OwnerAdd.IPAdd = m_dwOwner;
// This is what the server does to retrieve the records:
// 1. sets an ascending index on owner & version number.
// 2. goes to the first record owned by the given owner,
// having a version number larger or equal to MinVersNo.
// 3. stop if the record's vers num is higher than the range specified
// 4. stop if more than 1000 recs have been already received
// 5. add the new record to the set to return and go to 3.
//
dwDesired = MAX_DESIRED_RECORDS; dwLargeGapCount = LARGE_GAP_DETECT_COUNT; LowestVersNo.QuadPart = 0; if (MaxVersNo.QuadPart > dwDesired) MinVersNo.QuadPart = MaxVersNo.QuadPart-dwDesired; else MinVersNo.QuadPart = 0; Recs.pRow = NULL; while(MaxVersNo.QuadPart >= MinVersNo.QuadPart) { // clear up the previous array - if any
if (Recs.pRow != NULL) { ::WinsFreeMem(Recs.pRow); Recs.pRow = NULL; }
// go to WINS to get the data for the given Owner
#ifdef WINS_CLIENT_APIS
err = ::WinsGetDbRecs(hBinding, &OwnerAdd, MinVersNo, MaxVersNo, &Recs); #else
err = ::WinsGetDbRecs(&OwnerAdd, MinVersNo, MaxVersNo, &Recs); #endif WINS_CLIENT_APIS
// if abort was requested, break out with "ABORTED"
if (WaitForSingleObject(m_hAbort, 0) == WAIT_OBJECT_0) { err = ERROR_OPERATION_ABORTED; break; }
// if there is any kind of error break out
if (err != ERROR_SUCCESS) { if (err == ERROR_REC_NON_EXISTENT) { // I'm not sure this happens after all. The server side (WINS) has
// not code path returning such an error code.
err = ERROR_SUCCESS; } else { // if this happens, just get out with the error, and save the
// meaning of the error
m_hrLastError = HRESULT_FROM_WIN32(err); } break; }
// if got less than 1/4 of the size of the range, expand the range
// to double of what it was + 1. (+1 is important to avoid the effect
// of dramatic drop down because of DWORD roll-over
if (Recs.NoOfRecs <= (dwDesired >> 2)) { dwDesired <<= 1; dwDesired |= 1; } // else if got more than 3/4 of the size of the range, split the range in 2
// but not less than MAX_DESIRED_RECORDS
else if (Recs.NoOfRecs >= (dwDesired - (dwDesired >> 2))) { dwDesired = max (MAX_DESIRED_RECORDS, dwDesired >> 1); }
TRY { DWORD j; PWINSINTF_RECORD_ACTION_T pRow;
for (j = 0, pRow = Recs.pRow; j < Recs.NoOfRecs; j++, ++pRow) { WinsRecord wRecord; HROW hrow = NULL;
pRow->OwnerId = m_dwOwner; WinsIntfToWinsRecord(pRow, wRecord);
m_dwRecsCount++; if (!m_bEnableCache && !m_IndexMgr.AcceptWinsRecord(&wRecord)) continue;
// add the data to our memory store and
// to the sorted index
m_cMemMan.AddData(wRecord, &hrow); m_IndexMgr.AddHRow(hrow, FALSE, !m_bEnableCache); }
// now setup the new range to search..
//
// if this is not the gap boundary detection cycle, the next MaxVersNo
// needs to go right below the current MinVersNo. Otherwise, MaxVersNo
// needs to remain untouched!
if (dwLargeGapCount != 0) MaxVersNo.QuadPart = MinVersNo.QuadPart - 1;
// if no records were found..
if (Recs.NoOfRecs == 0) { // ..and we were already in the gap boundary detection cycle..
if (dwLargeGapCount == 0) // ..just break the loop - there are simply no more records
// for this owner in the database
break;
// ..otherwise just decrease the gap boundary detection counter.
// If it reaches 0, then next cycle we will attempt to see if
// there is any record closer to the lowest edge of the range by
// expanding for one time only the whole space.
dwLargeGapCount--; } else { // if we just exited the gap boundary detection cycle by finding some
// records, set the LowestVersNo to one more than the largest VersNo
// we found during this cycle.
if (dwLargeGapCount == 0) { pRow--; LowestVersNo.QuadPart = pRow->VersNo.QuadPart+1; }
// if there were any records found, just reset the gap boundary detection counter.
dwLargeGapCount = LARGE_GAP_DETECT_COUNT; }
// if the dwLargeGapCount counter is zero, it means the next cycle is a gap boundary detection one
// which means the range should be set for the whole unexplored space.
if (dwLargeGapCount != 0 && MaxVersNo.QuadPart > LowestVersNo.QuadPart + dwDesired) MinVersNo.QuadPart = MaxVersNo.QuadPart - dwDesired; else MinVersNo.QuadPart = LowestVersNo.QuadPart; } CATCH_ALL(e) { err = ::GetLastError(); m_hrLastError = HRESULT_FROM_WIN32(err); } END_CATCH_ALL }
if (Recs.pRow != NULL) ::WinsFreeMem(Recs.pRow);
return err; }
|