mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
577 lines
16 KiB
C
577 lines
16 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS WinSock 2 API
|
|
* FILE: dll/win32/ws2_32/src/nsquery.c
|
|
* PURPOSE: Namespace Query Object
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ws2_32.h>
|
|
|
|
/* DATA **********************************************************************/
|
|
|
|
#define WsNqLock() EnterCriticalSection(&NsQuery->Lock)
|
|
#define WsNqUnlock() LeaveCriticalSection(&NsQuery->Lock)
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
PNSQUERY
|
|
WSAAPI
|
|
WsNqAllocate(VOID)
|
|
{
|
|
PNSQUERY NsQuery;
|
|
|
|
/* Allocate the object */
|
|
NsQuery = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*NsQuery));
|
|
if (NsQuery)
|
|
{
|
|
/* Set non-zero fields */
|
|
NsQuery->Signature = ~0xBEADFACE;
|
|
InitializeListHead(&NsQuery->ProviderList);
|
|
NsQuery->TryAgain = TRUE;
|
|
}
|
|
|
|
/* Return it */
|
|
return NsQuery;
|
|
}
|
|
|
|
DWORD
|
|
WSAAPI
|
|
WsNqInitialize(IN PNSQUERY Query)
|
|
{
|
|
/* Initialize the lock */
|
|
InitializeCriticalSection(&Query->Lock);
|
|
|
|
/* Set initial reference count and signature */
|
|
Query->RefCount = 1;
|
|
Query->Signature = 0xBEADFACE;
|
|
|
|
/* Return success */
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
WSAAPI
|
|
WsNqValidateAndReference(IN PNSQUERY Query)
|
|
{
|
|
/* Check the signature first */
|
|
if (Query->Signature != 0xBEADFACE) return FALSE;
|
|
|
|
/* Validate the reference count */
|
|
if (!Query->RefCount) return FALSE;
|
|
|
|
/* Increase reference count */
|
|
InterlockedIncrement(&Query->RefCount);
|
|
|
|
/* Return success */
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsNqDelete(IN PNSQUERY NsQuery)
|
|
{
|
|
PNSQUERY_PROVIDER Provider;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Make sure that we got initialized */
|
|
if (!NsQuery->ProviderList.Flink) return;
|
|
|
|
/* Loop the provider list */
|
|
while (!IsListEmpty(&NsQuery->ProviderList))
|
|
{
|
|
/* Remove the entry */
|
|
Entry = RemoveHeadList(&NsQuery->ProviderList);
|
|
|
|
/* Get the provider */
|
|
Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
|
|
/* Delete it */
|
|
WsNqProvDelete(Provider);
|
|
}
|
|
|
|
/* Remove the signature and delete the lock */
|
|
NsQuery->Signature = ~0xBEADFACE;
|
|
DeleteCriticalSection(&NsQuery->Lock);
|
|
|
|
/* Free us */
|
|
HeapFree(WsSockHeap, 0, NsQuery);
|
|
}
|
|
|
|
VOID
|
|
WSAAPI
|
|
WsNqDereference(IN PNSQUERY Query)
|
|
{
|
|
/* Decrease the reference count and check if it's zero */
|
|
if (!InterlockedDecrement(&Query->RefCount))
|
|
{
|
|
/* Delete us*/
|
|
WsNqDelete(Query);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WSAAPI
|
|
WsNqBeginEnumerationProc(PVOID Context,
|
|
PNSCATALOG_ENTRY Entry)
|
|
{
|
|
PNS_PROVIDER Provider;
|
|
BOOLEAN GoOn = TRUE;
|
|
PENUM_CONTEXT EnumContext = (PENUM_CONTEXT)Context;
|
|
PNSQUERY NsQuery = EnumContext->NsQuery;
|
|
DWORD NamespaceId = Entry->NamespaceId;
|
|
|
|
/* Match the namespace ID, protocols and make sure it's enabled */
|
|
if ((((EnumContext->lpqsRestrictions->dwNameSpace == NamespaceId) ||
|
|
(EnumContext->lpqsRestrictions->dwNameSpace == NS_ALL)) &&
|
|
(!(EnumContext->lpqsRestrictions->dwNumberOfProtocols) ||
|
|
(WsNcMatchProtocols(NamespaceId,
|
|
Entry->AddressFamily,
|
|
EnumContext->lpqsRestrictions)))) &&
|
|
(Entry->Enabled))
|
|
{
|
|
/* Get the provider */
|
|
if (!(Provider = Entry->Provider))
|
|
{
|
|
/* None was loaded, load it */
|
|
if (WsNcLoadProvider(EnumContext->Catalog, Entry) != ERROR_SUCCESS)
|
|
{
|
|
/* Return TRUE to continue enumerating */
|
|
return TRUE;
|
|
}
|
|
|
|
/* Set the provider */
|
|
Provider = Entry->Provider;
|
|
}
|
|
|
|
/* Add it to the query */
|
|
if (!WsNqAddProvider(NsQuery, Provider))
|
|
{
|
|
/* We failed */
|
|
EnumContext->ErrorCode = WSASYSCALLFAILURE;
|
|
GoOn = FALSE;
|
|
}
|
|
}
|
|
|
|
/* Return to caller */
|
|
return GoOn;
|
|
}
|
|
|
|
DWORD
|
|
WSAAPI
|
|
WsNqLookupServiceEnd(IN PNSQUERY NsQuery)
|
|
{
|
|
PNSQUERY_PROVIDER Provider;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Protect us from closure */
|
|
WsNqLock();
|
|
NsQuery->ShuttingDown = TRUE;
|
|
|
|
/* Get the list and loop */
|
|
Entry = NsQuery->ProviderList.Flink;
|
|
while (Entry != &NsQuery->ProviderList)
|
|
{
|
|
/* Get the provider */
|
|
Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
|
|
/* Call its routine */
|
|
WsNqProvLookupServiceEnd(Provider);
|
|
|
|
/* Move to the next one */
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
/* Release lock and return success */
|
|
WsNqUnlock();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
WSAAPI
|
|
WsNqLookupServiceNext(IN PNSQUERY NsQuery,
|
|
IN DWORD ControlFlags,
|
|
OUT PDWORD BufferLength,
|
|
OUT LPWSAQUERYSETW Results)
|
|
{
|
|
INT ErrorCode = SOCKET_ERROR, OldErrorCode;
|
|
PNSQUERY_PROVIDER Provider, NextProvider;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Make sure we're not shutting down */
|
|
if (NsQuery->ShuttingDown)
|
|
{
|
|
/* We are shutting down, fail */
|
|
SetLastError(WSAECANCELLED);
|
|
return ErrorCode;
|
|
}
|
|
|
|
/* Acquire query lock */
|
|
WsNqLock();
|
|
|
|
/* Check if we already have an active provider */
|
|
NextProvider = NsQuery->ActiveProvider;
|
|
if (!NextProvider)
|
|
{
|
|
/* Make sure we have a current provider */
|
|
if (!NsQuery->CurrentProvider)
|
|
{
|
|
/* We don't; fail */
|
|
WsNqUnlock();
|
|
SetLastError(WSA_E_NO_MORE);
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/* Get the last provider in the list and start looping */
|
|
Entry = NsQuery->ProviderList.Blink;
|
|
NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
while (NextProvider)
|
|
{
|
|
/* Check if this is a new-style provider */
|
|
if (NextProvider->Provider->Service.NSPIoctl)
|
|
{
|
|
/* Remove it and re-add it on top */
|
|
RemoveEntryList(&NextProvider->QueryLink);
|
|
InsertHeadList(&NsQuery->ProviderList, &NextProvider->QueryLink);
|
|
|
|
/* Set it as the active provider and exit the loop */
|
|
NsQuery->ActiveProvider = NextProvider;
|
|
break;
|
|
}
|
|
|
|
/* Get the previous provider */
|
|
NextProvider = WsNqPreviousProvider(NsQuery, NextProvider);
|
|
}
|
|
}
|
|
|
|
/* Release the lock */
|
|
WsNqUnlock();
|
|
|
|
/* Restart and keep looping as long as there is an active provider */
|
|
while (NextProvider)
|
|
{
|
|
/* Call its routine */
|
|
ErrorCode = WsNqProvLookupServiceNext(NextProvider,
|
|
ControlFlags,
|
|
BufferLength,
|
|
Results);
|
|
/* Check for error or shutdown */
|
|
if ((ErrorCode == ERROR_SUCCESS) ||
|
|
(GetLastError() == WSAEFAULT) || (NsQuery->ShuttingDown))
|
|
{
|
|
/* Get out */
|
|
break;
|
|
}
|
|
|
|
/* Acquire Query Lock */
|
|
WsNqLock();
|
|
|
|
/* Check if we have an active provider */
|
|
if (NsQuery->ActiveProvider)
|
|
{
|
|
/* Save the old provider and get the next one */
|
|
Provider = NextProvider;
|
|
NextProvider = WsNqNextProvider(NsQuery, NsQuery->ActiveProvider);
|
|
|
|
/* Was the old provider our active? */
|
|
if (Provider == NsQuery->ActiveProvider)
|
|
{
|
|
/* Change our active provider to the new one */
|
|
NsQuery->ActiveProvider = NextProvider;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No next provider */
|
|
NextProvider = NULL;
|
|
}
|
|
|
|
/* Check if we failed and if we can try again */
|
|
if (!(NextProvider) &&
|
|
(ErrorCode == SOCKET_ERROR) &&
|
|
(NsQuery->TryAgain))
|
|
{
|
|
/* Save the error code so RAS doesn't overwrite it */
|
|
OldErrorCode = GetLastError();
|
|
|
|
/* Make sure we won't try for a 3rd time */
|
|
NsQuery->TryAgain = FALSE;
|
|
|
|
/* Call the helper to auto-dial */
|
|
if (WSAttemptAutodialName(NsQuery->QuerySet))
|
|
{
|
|
/* It succeeded, so we'll delete the current state. */
|
|
while (!IsListEmpty(&NsQuery->ProviderList))
|
|
{
|
|
/* Remove the entry and get its provider */
|
|
Entry = RemoveHeadList(&NsQuery->ProviderList);
|
|
Provider = CONTAINING_RECORD(Entry,
|
|
NSQUERY_PROVIDER,
|
|
QueryLink);
|
|
|
|
/* Reset it */
|
|
WsNqProvLookupServiceEnd(Provider);
|
|
WsNqProvDelete(Provider);
|
|
}
|
|
|
|
/* Start a new query */
|
|
if (WsNqLookupServiceBegin(NsQuery,
|
|
NsQuery->QuerySet,
|
|
NsQuery->ControlFlags,
|
|
NsQuery->Catalog) == ERROR_SUCCESS)
|
|
{
|
|
/* New query succeeded, set active provider now */
|
|
NsQuery->ActiveProvider =
|
|
WsNqNextProvider(NsQuery, NsQuery->ActiveProvider);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Reset the error code */
|
|
SetLastError(OldErrorCode);
|
|
}
|
|
}
|
|
|
|
/* Release lock */
|
|
WsNqUnlock();
|
|
}
|
|
|
|
/* Return */
|
|
return ErrorCode;
|
|
}
|
|
|
|
DWORD
|
|
WSAAPI
|
|
WsNqLookupServiceBegin(IN PNSQUERY NsQuery,
|
|
IN LPWSAQUERYSETW Restrictions,
|
|
IN DWORD ControlFlags,
|
|
IN PNSCATALOG Catalog)
|
|
{
|
|
WSASERVICECLASSINFOW ClassInfo;
|
|
LPWSASERVICECLASSINFOW pClassInfo = &ClassInfo;
|
|
PNSQUERY_PROVIDER Provider, NextProvider;
|
|
PLIST_ENTRY Entry;
|
|
INT ErrorCode;
|
|
DWORD ClassInfoSize;
|
|
PNSCATALOG_ENTRY CatalogEntry = NULL;
|
|
ENUM_CONTEXT EnumContext;
|
|
BOOLEAN TryAgain;
|
|
|
|
/* Check for RAS Auto-dial attempt */
|
|
if (NsQuery->TryAgain)
|
|
{
|
|
/* Make a copy of the query set */
|
|
ErrorCode = CopyQuerySetW(Restrictions, &NsQuery->QuerySet);
|
|
TryAgain = (ErrorCode == ERROR_SUCCESS);
|
|
|
|
/* Check if we'll try again */
|
|
if (!TryAgain)
|
|
{
|
|
/* We won't, fail */
|
|
SetLastError(ErrorCode);
|
|
ErrorCode = SOCKET_ERROR;
|
|
NsQuery->TryAgain = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
/* Cache the information for a restart */
|
|
NsQuery->ControlFlags = ControlFlags;
|
|
NsQuery->Catalog = Catalog;
|
|
}
|
|
|
|
/* Check if we have a specific ID */
|
|
if (Restrictions->lpNSProviderId)
|
|
{
|
|
/* Get the catalog entry */
|
|
ErrorCode = WsNcGetCatalogFromProviderId(Catalog,
|
|
Restrictions->lpNSProviderId,
|
|
&CatalogEntry);
|
|
/* Check for failure */
|
|
if (ErrorCode != ERROR_SUCCESS)
|
|
{
|
|
/* Fail */
|
|
SetLastError(WSAEINVAL);
|
|
ErrorCode = SOCKET_ERROR;
|
|
goto Exit;
|
|
}
|
|
/* We succeeded, add this provider */
|
|
else if (!WsNqAddProvider(NsQuery, CatalogEntry->Provider))
|
|
{
|
|
/* Fail */
|
|
SetLastError(WSA_NOT_ENOUGH_MEMORY);
|
|
ErrorCode = SOCKET_ERROR;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Setup the lookup context */
|
|
EnumContext.lpqsRestrictions = Restrictions;
|
|
EnumContext.ErrorCode = ERROR_SUCCESS;
|
|
EnumContext.NsQuery = NsQuery;
|
|
EnumContext.Catalog = Catalog;
|
|
|
|
/* Do a lookup for every entry */
|
|
WsNcEnumerateCatalogItems(Catalog,
|
|
WsNqBeginEnumerationProc,
|
|
&EnumContext);
|
|
ErrorCode = EnumContext.ErrorCode;
|
|
|
|
/* Check for success */
|
|
if (ErrorCode != ERROR_SUCCESS)
|
|
{
|
|
/* Fail */
|
|
SetLastError(WSAEINVAL);
|
|
ErrorCode = SOCKET_ERROR;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
/* Get the class information */
|
|
ClassInfo.lpServiceClassId = Restrictions->lpServiceClassId;
|
|
ErrorCode = WsNcGetServiceClassInfo(Catalog, &ClassInfoSize, pClassInfo);
|
|
|
|
/* Check if more buffer space is needed */
|
|
if ((ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT))
|
|
{
|
|
/* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
|
|
}
|
|
else
|
|
{
|
|
/* Assume success */
|
|
ErrorCode = ERROR_SUCCESS;
|
|
}
|
|
|
|
/* Check if the provider list is empty */
|
|
if (IsListEmpty(&NsQuery->ProviderList))
|
|
{
|
|
/* We don't have any providers to handle this! */
|
|
ErrorCode = SOCKET_ERROR;
|
|
SetLastError(WSASERVICE_NOT_FOUND);
|
|
goto Exit;
|
|
}
|
|
|
|
/* Get the first provider and loop */
|
|
Entry = NsQuery->ProviderList.Flink;
|
|
NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
while (NextProvider)
|
|
{
|
|
/* Call it */
|
|
ErrorCode = WsNqProvLookupServiceBegin(NextProvider,
|
|
Restrictions,
|
|
pClassInfo,
|
|
ControlFlags);
|
|
/* Check for error */
|
|
if (ErrorCode == SOCKET_ERROR)
|
|
{
|
|
/* Remove this provider, get the next one, delete the old one */
|
|
Provider = NextProvider;
|
|
NextProvider = WsNqNextProvider(NsQuery, NextProvider);
|
|
RemoveEntryList(&Provider->QueryLink);
|
|
WsNqProvDelete(Provider);
|
|
}
|
|
else
|
|
{
|
|
/* Get the next provider */
|
|
NextProvider = WsNqNextProvider(NsQuery, NextProvider);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
/* Check if we had an error somewhere */
|
|
if (ErrorCode == SOCKET_ERROR)
|
|
{
|
|
/* Loop the list */
|
|
while (!IsListEmpty(&NsQuery->ProviderList))
|
|
{
|
|
/* Remove this provider */
|
|
Entry = RemoveHeadList(&NsQuery->ProviderList);
|
|
|
|
/* Get the failed provider and delete it */
|
|
Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
WsNqProvDelete(Provider);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Set the active provider */
|
|
Entry = NsQuery->ProviderList.Flink;
|
|
NsQuery->ActiveProvider = CONTAINING_RECORD(Entry,
|
|
NSQUERY_PROVIDER,
|
|
QueryLink);
|
|
}
|
|
|
|
/* Return */
|
|
return ErrorCode;
|
|
}
|
|
|
|
PNSQUERY_PROVIDER
|
|
WSAAPI
|
|
WsNqNextProvider(IN PNSQUERY Query,
|
|
IN PNSQUERY_PROVIDER Provider)
|
|
{
|
|
PNSQUERY_PROVIDER NextProvider = NULL;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Get the first entry and get its provider */
|
|
Entry = Provider->QueryLink.Flink;
|
|
if (Entry != &Query->ProviderList)
|
|
{
|
|
/* Get the current provider */
|
|
NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
}
|
|
|
|
/* Return it */
|
|
return NextProvider;
|
|
}
|
|
|
|
PNSQUERY_PROVIDER
|
|
WSAAPI
|
|
WsNqPreviousProvider(IN PNSQUERY Query,
|
|
IN PNSQUERY_PROVIDER Provider)
|
|
{
|
|
PNSQUERY_PROVIDER PrevProvider = NULL;
|
|
PLIST_ENTRY Entry;
|
|
|
|
/* Get the last entry and get its provider */
|
|
Entry = Provider->QueryLink.Blink;
|
|
if (Entry != &Query->ProviderList)
|
|
{
|
|
/* Get the current provider */
|
|
PrevProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
|
|
}
|
|
|
|
/* Return it */
|
|
return PrevProvider;
|
|
}
|
|
|
|
BOOL
|
|
WSAAPI
|
|
WsNqAddProvider(IN PNSQUERY Query,
|
|
IN PNS_PROVIDER Provider)
|
|
{
|
|
BOOL Success = TRUE;
|
|
PNSQUERY_PROVIDER QueryProvider;
|
|
|
|
/* Allocate a new Query Provider */
|
|
if ((QueryProvider = WsNqProvAllocate()))
|
|
{
|
|
/* Initialize it */
|
|
WsNqProvInitialize(QueryProvider, Provider);
|
|
|
|
/* Insert it into the provider list */
|
|
InsertTailList(&Query->ProviderList, &QueryProvider->QueryLink);
|
|
}
|
|
else
|
|
{
|
|
/* We failed */
|
|
SetLastError(WSASYSCALLFAILURE);
|
|
Success = FALSE;
|
|
}
|
|
|
|
/* Return */
|
|
return Success;
|
|
}
|
|
|