2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dll/win32/ws2_32_new/src/nsquery.c
5 * PURPOSE: Namespace Query Object
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
13 /* DATA **********************************************************************/
15 #define WsNqLock() EnterCriticalSection(&NsQuery->Lock);
16 #define WsNqUnlock() LeaveCriticalSection(&NsQuery->Lock);
18 /* FUNCTIONS *****************************************************************/
26 /* Allocate the object */
27 NsQuery
= HeapAlloc(WsSockHeap
, HEAP_ZERO_MEMORY
, sizeof(*NsQuery
));
30 /* Set non-zero fields */
31 NsQuery
->Signature
= ~0xBEADFACE;
32 InitializeListHead(&NsQuery
->ProviderList
);
33 NsQuery
->TryAgain
= TRUE
;
42 WsNqInitialize(IN PNSQUERY Query
)
44 /* Initialize the lock */
45 InitializeCriticalSection(&Query
->Lock
);
47 /* Set initial reference count and signature */
49 Query
->Signature
= 0xBEADFACE;
57 WsNqValidateAndReference(IN PNSQUERY Query
)
59 /* Check the signature first */
60 if (Query
->Signature
!= 0xBEADFACE) return FALSE
;
62 /* Validate the reference count */
63 if (!Query
->RefCount
) return FALSE
;
65 /* Increase reference count */
66 InterlockedIncrement(&Query
->RefCount
);
74 WsNqDelete(IN PNSQUERY NsQuery
)
76 PNSQUERY_PROVIDER Provider
;
79 /* Make sure that we got initialized */
80 if (!NsQuery
->ProviderList
.Flink
) return;
82 /* Loop the provider list */
83 while (!IsListEmpty(&NsQuery
->ProviderList
))
85 /* Remove the entry */
86 Entry
= RemoveHeadList(&NsQuery
->ProviderList
);
88 /* Get the provider */
89 Provider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
92 WsNqProvDelete(Provider
);
95 /* Remove the signature and delete the lock */
96 NsQuery
->Signature
= ~0xBEADFACE;
97 DeleteCriticalSection(&NsQuery
->Lock
);
100 HeapFree(WsSockHeap
, 0, NsQuery
);
105 WsNqDereference(IN PNSQUERY Query
)
107 /* Decrease the reference count and check if it's zero */
108 if (!InterlockedDecrement(&Query
->RefCount
))
117 WsNqBeginEnumerationProc(PVOID Context
,
118 PNSCATALOG_ENTRY Entry
)
120 PNS_PROVIDER Provider
;
122 PENUM_CONTEXT EnumContext
= (PENUM_CONTEXT
)Context
;
123 PNSQUERY NsQuery
= EnumContext
->NsQuery
;
124 DWORD NamespaceId
= Entry
->NamespaceId
;
126 /* Match the namespace ID, protocols and make sure it's enabled */
127 if ((((EnumContext
->lpqsRestrictions
->dwNameSpace
== NamespaceId
) ||
128 (EnumContext
->lpqsRestrictions
->dwNameSpace
== NS_ALL
)) &&
129 (!(EnumContext
->lpqsRestrictions
->dwNumberOfProtocols
) ||
130 (WsNcMatchProtocols(NamespaceId
,
131 Entry
->AddressFamily
,
132 EnumContext
->lpqsRestrictions
)))) &&
135 /* Get the provider */
136 if (!(Provider
= Entry
->Provider
))
138 /* None was loaded, load it */
139 if (WsNcLoadProvider(EnumContext
->Catalog
, Entry
) != ERROR_SUCCESS
)
141 /* Return TRUE to continue enumerating */
145 /* Set the provider */
146 Provider
= Entry
->Provider
;
149 /* Add it to the query */
150 if (!WsNqAddProvider(NsQuery
, Provider
))
153 EnumContext
->ErrorCode
= WSASYSCALLFAILURE
;
158 /* Return to caller */
164 WsNqLookupServiceEnd(IN PNSQUERY NsQuery
)
166 PNSQUERY_PROVIDER Provider
;
169 /* Protect us from closure */
171 NsQuery
->ShuttingDown
= TRUE
;
173 /* Get the list and loop */
174 Entry
= NsQuery
->ProviderList
.Flink
;
175 while (Entry
!= &NsQuery
->ProviderList
)
177 /* Get the provider */
178 Provider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
180 /* Call its routine */
181 WsNqProvLookupServiceEnd(Provider
);
183 /* Move to the next one */
184 Entry
= Entry
->Flink
;
187 /* Release lock and return success */
189 return ERROR_SUCCESS
;
194 WsNqLookupServiceNext(IN PNSQUERY NsQuery
,
195 IN DWORD ControlFlags
,
196 OUT PDWORD BufferLength
,
197 OUT LPWSAQUERYSETW Results
)
199 INT ErrorCode
= SOCKET_ERROR
, OldErrorCode
;
200 PNSQUERY_PROVIDER Provider
, NextProvider
;
203 /* Make sure we're not shutting down */
204 if (NsQuery
->ShuttingDown
)
206 /* We are shutting down, fail */
207 SetLastError(WSAECANCELLED
);
211 /* Acquire query lock */
214 /* Check if we already have an active provider */
215 NextProvider
= NsQuery
->ActiveProvider
;
218 /* Make sure we have a current provider */
219 if (!NsQuery
->CurrentProvider
)
223 SetLastError(WSA_E_NO_MORE
);
227 /* Get the last provider in the list and start looping */
228 Entry
= NsQuery
->ProviderList
.Blink
;
229 NextProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
232 /* Check if this is a new-style provider */
233 if (NextProvider
->Provider
->Service
.NSPIoctl
)
235 /* Remove it and re-add it on top */
236 RemoveEntryList(&NextProvider
->QueryLink
);
237 InsertHeadList(&NsQuery
->ProviderList
, &NextProvider
->QueryLink
);
239 /* Set it as the active provider and exit the loop */
240 NsQuery
->ActiveProvider
= NextProvider
;
244 /* Get the previous provider */
245 NextProvider
= WsNqPreviousProvider(NsQuery
, NextProvider
);
249 /* Release the lock */
252 /* Restart and keep looping as long as there is an active provider */
255 /* Call its routine */
256 ErrorCode
= WsNqProvLookupServiceNext(NextProvider
,
260 /* Check for error or shutdown */
261 if ((ErrorCode
== ERROR_SUCCESS
) ||
262 (GetLastError() == WSAEFAULT
) || (NsQuery
->ShuttingDown
))
268 /* Acquire Query Lock */
271 /* Check if we have an active provider */
272 if (NsQuery
->ActiveProvider
)
274 /* Save the old provider and get the next one */
275 Provider
= NextProvider
;
276 NextProvider
= WsNqNextProvider(NsQuery
, NsQuery
->ActiveProvider
);
278 /* Was the old provider our active? */
279 if (Provider
== NsQuery
->ActiveProvider
)
281 /* Change our active provider to the new one */
282 NsQuery
->ActiveProvider
= NextProvider
;
287 /* No next provider */
291 /* Check if we failed and if we can try again */
292 if (!(NextProvider
) &&
293 (ErrorCode
== SOCKET_ERROR
) &&
296 /* Save the error code so RAS doesn't overwrite it */
297 OldErrorCode
= GetLastError();
299 /* Make sure we won't try for a 3rd time */
300 NsQuery
->TryAgain
= FALSE
;
302 /* Call the helper to auto-dial */
303 if (WSAttemptAutodialName(NsQuery
->QuerySet
))
305 /* It succeeded, so we'll delete the current state. */
306 while (!IsListEmpty(&NsQuery
->ProviderList
))
308 /* Remove the entry and get its provider */
309 Entry
= RemoveHeadList(&NsQuery
->ProviderList
);
310 Provider
= CONTAINING_RECORD(Entry
,
315 WsNqProvLookupServiceEnd(Provider
);
316 WsNqProvDelete(Provider
);
319 /* Start a new query */
320 if (WsNqLookupServiceBegin(NsQuery
,
322 NsQuery
->ControlFlags
,
323 NsQuery
->Catalog
) == ERROR_SUCCESS
)
325 /* New query succeeded, set active provider now */
326 NsQuery
->ActiveProvider
=
327 WsNqNextProvider(NsQuery
, NsQuery
->ActiveProvider
);
332 /* Reset the error code */
333 SetLastError(OldErrorCode
);
347 WsNqLookupServiceBegin(IN PNSQUERY NsQuery
,
348 IN LPWSAQUERYSETW Restrictions
,
349 IN DWORD ControlFlags
,
350 IN PNSCATALOG Catalog
)
352 WSASERVICECLASSINFOW ClassInfo
;
353 LPWSASERVICECLASSINFOW pClassInfo
= &ClassInfo
;
354 PNSQUERY_PROVIDER Provider
, NextProvider
;
358 PNSCATALOG_ENTRY CatalogEntry
;
359 ENUM_CONTEXT EnumContext
;
362 /* Check for RAS Auto-dial attempt */
363 if (NsQuery
->TryAgain
)
365 /* Make a copy of the query set */
366 ErrorCode
= CopyQuerySetW(Restrictions
, &NsQuery
->QuerySet
);
367 TryAgain
= (ErrorCode
== ERROR_SUCCESS
);
369 /* Check if we'll try again */
373 SetLastError(ErrorCode
);
374 ErrorCode
= SOCKET_ERROR
;
375 NsQuery
->TryAgain
= FALSE
;
379 /* Cache the information for a restart */
380 NsQuery
->ControlFlags
= ControlFlags
;
381 NsQuery
->Catalog
= Catalog
;
384 /* Check if we have a specific ID */
385 if (Restrictions
->lpNSProviderId
)
387 /* Get the provider */
388 ErrorCode
= WsNcGetCatalogFromProviderId(Catalog
,
389 Restrictions
->lpNSProviderId
,
391 /* Check for success */
392 if (ErrorCode
!= ERROR_SUCCESS
)
395 SetLastError(WSAEINVAL
);
396 ErrorCode
= SOCKET_ERROR
;
401 /* Add this provider */
402 WsNqAddProvider(NsQuery
, CatalogEntry
->Provider
);
407 /* Setup the lookup context */
408 EnumContext
.lpqsRestrictions
= Restrictions
;
409 EnumContext
.ErrorCode
= ERROR_SUCCESS
;
410 EnumContext
.NsQuery
= NsQuery
;
411 EnumContext
.Catalog
= Catalog
;
413 /* Do a lookup for every entry */
414 WsNcEnumerateCatalogItems(Catalog
,
415 WsNqBeginEnumerationProc
,
417 ErrorCode
= EnumContext
.ErrorCode
;
419 /* Check for success */
420 if (ErrorCode
!= ERROR_SUCCESS
)
423 SetLastError(WSAEINVAL
);
424 ErrorCode
= SOCKET_ERROR
;
429 /* Get the class information */
430 ClassInfo
.lpServiceClassId
= Restrictions
->lpServiceClassId
;
431 ErrorCode
= WsNcGetServiceClassInfo(Catalog
, &ClassInfoSize
, pClassInfo
);
433 /* Check if more buffer space is needed */
434 if ((ErrorCode
== SOCKET_ERROR
) && (GetLastError() == WSAEFAULT
))
436 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
441 ErrorCode
= ERROR_SUCCESS
;
444 /* Check if the provider list is empty */
445 if (IsListEmpty(&NsQuery
->ProviderList
))
447 /* We don't have any providers to handle this! */
448 ErrorCode
= SOCKET_ERROR
;
449 SetLastError(WSASERVICE_NOT_FOUND
);
453 /* Get the first provider and loop */
454 Entry
= NsQuery
->ProviderList
.Flink
;
455 NextProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
459 ErrorCode
= WsNqProvLookupServiceBegin(NextProvider
,
463 /* Check for error */
464 if (ErrorCode
== SOCKET_ERROR
)
466 /* Remove this provider, get the next one, delete the old one */
467 Provider
= NextProvider
;
468 NextProvider
= WsNqNextProvider(NsQuery
, NextProvider
);
469 RemoveEntryList(&Provider
->QueryLink
);
470 WsNqProvDelete(Provider
);
474 /* Get the next provider */
475 NextProvider
= WsNqNextProvider(NsQuery
, NextProvider
);
480 /* Check if we had an error somewhere */
481 if (ErrorCode
== SOCKET_ERROR
)
484 while (!IsListEmpty(&NsQuery
->ProviderList
))
486 /* Remove this provider */
487 Entry
= RemoveHeadList(&NsQuery
->ProviderList
);
489 /* Get the failed provider and delete it */
490 Provider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
491 WsNqProvDelete(Provider
);
496 /* Set the active provider */
497 Entry
= NsQuery
->ProviderList
.Flink
;
498 NsQuery
->ActiveProvider
= CONTAINING_RECORD(Entry
,
509 WsNqNextProvider(IN PNSQUERY Query
,
510 IN PNSQUERY_PROVIDER Provider
)
512 PNSQUERY_PROVIDER NextProvider
= NULL
;
515 /* Get the first entry and get its provider */
516 Entry
= Provider
->QueryLink
.Flink
;
517 if (Entry
!= &Query
->ProviderList
)
519 /* Get the current provider */
520 NextProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
529 WsNqPreviousProvider(IN PNSQUERY Query
,
530 IN PNSQUERY_PROVIDER Provider
)
532 PNSQUERY_PROVIDER PrevProvider
= NULL
;
535 /* Get the last entry and get its provider */
536 Entry
= Provider
->QueryLink
.Blink
;
537 if (Entry
!= &Query
->ProviderList
)
539 /* Get the current provider */
540 PrevProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
549 WsNqAddProvider(IN PNSQUERY Query
,
550 IN PNS_PROVIDER Provider
)
553 PNSQUERY_PROVIDER QueryProvider
;
555 /* Allocate a new Query Provider */
556 if ((QueryProvider
= WsNqProvAllocate()))
559 WsNqProvInitialize(QueryProvider
, Provider
);
561 /* Insert it into the provider list */
562 InsertTailList(&Query
->ProviderList
, &QueryProvider
->QueryLink
);
567 SetLastError(WSASYSCALLFAILURE
);