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 /* Save the current active provider */
272 Provider
= NsQuery
->ActiveProvider
;
274 /* Check if one exists */
277 /* Get the next one */
278 NextProvider
= WsNqNextProvider(NsQuery
,
279 NsQuery
->ActiveProvider
);
281 /* Was the old provider our active? */
282 if (Provider
== NsQuery
->ActiveProvider
)
284 /* Change our active provider to the new one */
285 NsQuery
->ActiveProvider
= NextProvider
;
290 /* No next provider */
294 /* Check if we failed and if we can try again */
295 if (!(NextProvider
) &&
296 (ErrorCode
== SOCKET_ERROR
) &&
299 /* Save the error code so RAS doesn't overwrite it */
300 OldErrorCode
= GetLastError();
302 /* Make sure we won't try for a 3rd time */
303 NsQuery
->TryAgain
= FALSE
;
305 /* Call the helper to auto-dial */
306 if (WSAttemptAutodialName(NsQuery
->QuerySet
))
308 /* It succeeded, so we'll delete the current state. */
309 while (!IsListEmpty(&NsQuery
->ProviderList
))
311 /* Remove the entry and get its provider */
312 Entry
= RemoveHeadList(&NsQuery
->ProviderList
);
313 Provider
= CONTAINING_RECORD(Entry
,
318 WsNqProvLookupServiceEnd(Provider
);
319 WsNqProvDelete(Provider
);
322 /* Start a new query */
323 if (WsNqLookupServiceBegin(NsQuery
,
325 NsQuery
->ControlFlags
,
326 NsQuery
->Catalog
) == ERROR_SUCCESS
)
328 /* New query succeeded, set active provider now */
329 NsQuery
->ActiveProvider
=
330 WsNqNextProvider(NsQuery
,
331 NsQuery
->ActiveProvider
);
336 /* Reset the error code */
337 SetLastError(OldErrorCode
);
351 WsNqLookupServiceBegin(IN PNSQUERY NsQuery
,
352 IN LPWSAQUERYSETW Restrictions
,
353 IN DWORD ControlFlags
,
354 IN PNSCATALOG Catalog
)
356 WSASERVICECLASSINFOW ClassInfo
;
357 LPWSASERVICECLASSINFOW pClassInfo
= &ClassInfo
;
358 PNSQUERY_PROVIDER Provider
, NextProvider
;
362 PNSCATALOG_ENTRY CatalogEntry
;
363 ENUM_CONTEXT EnumContext
;
366 /* Check for RAS Auto-dial attempt */
367 if (NsQuery
->TryAgain
)
369 /* Make a copy of the query set */
370 ErrorCode
= CopyQuerySetW(Restrictions
, &NsQuery
->QuerySet
);
371 TryAgain
= (ErrorCode
== ERROR_SUCCESS
);
373 /* Check if we'll try again */
377 SetLastError(ErrorCode
);
378 ErrorCode
= SOCKET_ERROR
;
379 NsQuery
->TryAgain
= FALSE
;
383 /* Cache the information for a restart */
384 NsQuery
->ControlFlags
= ControlFlags
;
385 NsQuery
->Catalog
= Catalog
;
388 /* Check if we have a specific ID */
389 if (Restrictions
->lpNSProviderId
)
391 /* Get the provider */
392 ErrorCode
= WsNcGetCatalogFromProviderId(Catalog
,
393 Restrictions
->lpNSProviderId
,
395 /* Check for success */
396 if (ErrorCode
!= ERROR_SUCCESS
)
399 SetLastError(WSAEINVAL
);
400 ErrorCode
= SOCKET_ERROR
;
405 /* Add this provider */
406 WsNqAddProvider(NsQuery
, CatalogEntry
->Provider
);
411 /* Setup the lookup context */
412 EnumContext
.lpqsRestrictions
= Restrictions
;
413 EnumContext
.ErrorCode
= ERROR_SUCCESS
;
414 EnumContext
.NsQuery
= NsQuery
;
415 EnumContext
.Catalog
= Catalog
;
417 /* Do a lookup for every entry */
418 WsNcEnumerateCatalogItems(Catalog
,
419 WsNqBeginEnumerationProc
,
421 ErrorCode
= EnumContext
.ErrorCode
;
423 /* Check for success */
424 if (ErrorCode
!= ERROR_SUCCESS
)
427 SetLastError(WSAEINVAL
);
428 ErrorCode
= SOCKET_ERROR
;
433 /* Get the class information */
434 ClassInfo
.lpServiceClassId
= Restrictions
->lpServiceClassId
;
435 ErrorCode
= WsNcGetServiceClassInfo(Catalog
, &ClassInfoSize
, pClassInfo
);
437 /* Check if more buffer space is needed */
438 if ((ErrorCode
== SOCKET_ERROR
) && (GetLastError() == WSAEFAULT
))
440 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
445 ErrorCode
= ERROR_SUCCESS
;
448 /* Check if the provider list is empty */
449 if (IsListEmpty(&NsQuery
->ProviderList
))
451 /* We don't have any providers to handle this! */
452 ErrorCode
= SOCKET_ERROR
;
453 SetLastError(WSASERVICE_NOT_FOUND
);
457 /* Get the first provider and loop */
458 Entry
= NsQuery
->ProviderList
.Flink
;
459 NextProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
463 ErrorCode
= WsNqProvLookupServiceBegin(NextProvider
,
467 /* Check for error */
468 if (ErrorCode
== SOCKET_ERROR
)
470 /* Remove this provider, get the next one, delete the old one */
471 Provider
= NextProvider
;
472 NextProvider
= WsNqNextProvider(NsQuery
, NextProvider
);
473 RemoveEntryList(&Provider
->QueryLink
);
474 WsNqProvDelete(Provider
);
478 /* Get the next provider */
479 NextProvider
= WsNqNextProvider(NsQuery
, NextProvider
);
484 /* Check if we had an error somewhere */
485 if (ErrorCode
== SOCKET_ERROR
)
488 while (!IsListEmpty(&NsQuery
->ProviderList
))
490 /* Remove this provider */
491 Entry
= RemoveHeadList(&NsQuery
->ProviderList
);
493 /* Get the failed provider and delete it */
494 Provider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
495 WsNqProvDelete(Provider
);
500 /* Set the active provider */
501 Entry
= NsQuery
->ProviderList
.Flink
;
502 NsQuery
->ActiveProvider
= CONTAINING_RECORD(Entry
,
513 WsNqNextProvider(IN PNSQUERY Query
,
514 IN PNSQUERY_PROVIDER Provider
)
516 PNSQUERY_PROVIDER NextProvider
= NULL
;
519 /* Get the first entry and get its provider */
520 Entry
= Provider
->QueryLink
.Flink
;
521 if (Entry
!= &Query
->ProviderList
)
523 /* Get the current provider */
524 NextProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
533 WsNqPreviousProvider(IN PNSQUERY Query
,
534 IN PNSQUERY_PROVIDER Provider
)
536 PNSQUERY_PROVIDER PrevProvider
= NULL
;
539 /* Get the last entry and get its provider */
540 Entry
= Provider
->QueryLink
.Blink
;
541 if (Entry
!= &Query
->ProviderList
)
543 /* Get the current provider */
544 PrevProvider
= CONTAINING_RECORD(Entry
, NSQUERY_PROVIDER
, QueryLink
);
553 WsNqAddProvider(IN PNSQUERY Query
,
554 IN PNS_PROVIDER Provider
)
557 PNSQUERY_PROVIDER QueryProvider
;
559 /* Allocate a new Query Provider */
560 if ((QueryProvider
= WsNqProvAllocate()))
563 WsNqProvInitialize(QueryProvider
, Provider
);
565 /* Insert it into the provider list */
566 InsertTailList(&Query
->ProviderList
, &QueryProvider
->QueryLink
);
571 SetLastError(WSASYSCALLFAILURE
);