1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dll/win32/ws2_32/src/nsquery.c
5 * PURPOSE: Namespace Query Object
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ws2_32.h>
12
13 /* DATA **********************************************************************/
14
15 #define WsNqLock() EnterCriticalSection(&NsQuery->Lock)
16 #define WsNqUnlock() LeaveCriticalSection(&NsQuery->Lock)
17
18 /* FUNCTIONS *****************************************************************/
19
20 PNSQUERY
21 WSAAPI
WsNqAllocate(VOID)22 WsNqAllocate(VOID)
23 {
24 PNSQUERY NsQuery;
25
26 /* Allocate the object */
27 NsQuery = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*NsQuery));
28 if (NsQuery)
29 {
30 /* Set non-zero fields */
31 NsQuery->Signature = ~0xBEADFACE;
32 InitializeListHead(&NsQuery->ProviderList);
33 NsQuery->TryAgain = TRUE;
34 }
35
36 /* Return it */
37 return NsQuery;
38 }
39
40 DWORD
41 WSAAPI
WsNqInitialize(IN PNSQUERY Query)42 WsNqInitialize(IN PNSQUERY Query)
43 {
44 /* Initialize the lock */
45 InitializeCriticalSection(&Query->Lock);
46
47 /* Set initial reference count and signature */
48 Query->RefCount = 1;
49 Query->Signature = 0xBEADFACE;
50
51 /* Return success */
52 return ERROR_SUCCESS;
53 }
54
55 BOOL
56 WSAAPI
WsNqValidateAndReference(IN PNSQUERY Query)57 WsNqValidateAndReference(IN PNSQUERY Query)
58 {
59 /* Check the signature first */
60 if (Query->Signature != 0xBEADFACE) return FALSE;
61
62 /* Validate the reference count */
63 if (!Query->RefCount) return FALSE;
64
65 /* Increase reference count */
66 InterlockedIncrement(&Query->RefCount);
67
68 /* Return success */
69 return TRUE;
70 }
71
72 VOID
73 WSAAPI
WsNqDelete(IN PNSQUERY NsQuery)74 WsNqDelete(IN PNSQUERY NsQuery)
75 {
76 PNSQUERY_PROVIDER Provider;
77 PLIST_ENTRY Entry;
78
79 /* Make sure that we got initialized */
80 if (!NsQuery->ProviderList.Flink) return;
81
82 /* Loop the provider list */
83 while (!IsListEmpty(&NsQuery->ProviderList))
84 {
85 /* Remove the entry */
86 Entry = RemoveHeadList(&NsQuery->ProviderList);
87
88 /* Get the provider */
89 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
90
91 /* Delete it */
92 WsNqProvDelete(Provider);
93 }
94
95 /* Remove the signature and delete the lock */
96 NsQuery->Signature = ~0xBEADFACE;
97 DeleteCriticalSection(&NsQuery->Lock);
98
99 /* Free us */
100 HeapFree(WsSockHeap, 0, NsQuery);
101 }
102
103 VOID
104 WSAAPI
WsNqDereference(IN PNSQUERY Query)105 WsNqDereference(IN PNSQUERY Query)
106 {
107 /* Decrease the reference count and check if it's zero */
108 if (!InterlockedDecrement(&Query->RefCount))
109 {
110 /* Delete us*/
111 WsNqDelete(Query);
112 }
113 }
114
115 BOOL
116 WSAAPI
WsNqBeginEnumerationProc(PVOID Context,PNSCATALOG_ENTRY Entry)117 WsNqBeginEnumerationProc(PVOID Context,
118 PNSCATALOG_ENTRY Entry)
119 {
120 PNS_PROVIDER Provider;
121 BOOLEAN GoOn = TRUE;
122 PENUM_CONTEXT EnumContext = (PENUM_CONTEXT)Context;
123 PNSQUERY NsQuery = EnumContext->NsQuery;
124 DWORD NamespaceId = Entry->NamespaceId;
125
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)))) &&
133 (Entry->Enabled))
134 {
135 /* Get the provider */
136 if (!(Provider = Entry->Provider))
137 {
138 /* None was loaded, load it */
139 if (WsNcLoadProvider(EnumContext->Catalog, Entry) != ERROR_SUCCESS)
140 {
141 /* Return TRUE to continue enumerating */
142 return TRUE;
143 }
144
145 /* Set the provider */
146 Provider = Entry->Provider;
147 }
148
149 /* Add it to the query */
150 if (!WsNqAddProvider(NsQuery, Provider))
151 {
152 /* We failed */
153 EnumContext->ErrorCode = WSASYSCALLFAILURE;
154 GoOn = FALSE;
155 }
156 }
157
158 /* Return to caller */
159 return GoOn;
160 }
161
162 DWORD
163 WSAAPI
WsNqLookupServiceEnd(IN PNSQUERY NsQuery)164 WsNqLookupServiceEnd(IN PNSQUERY NsQuery)
165 {
166 PNSQUERY_PROVIDER Provider;
167 PLIST_ENTRY Entry;
168
169 /* Protect us from closure */
170 WsNqLock();
171 NsQuery->ShuttingDown = TRUE;
172
173 /* Get the list and loop */
174 Entry = NsQuery->ProviderList.Flink;
175 while (Entry != &NsQuery->ProviderList)
176 {
177 /* Get the provider */
178 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
179
180 /* Call its routine */
181 WsNqProvLookupServiceEnd(Provider);
182
183 /* Move to the next one */
184 Entry = Entry->Flink;
185 }
186
187 /* Release lock and return success */
188 WsNqUnlock();
189 return ERROR_SUCCESS;
190 }
191
192 DWORD
193 WSAAPI
WsNqLookupServiceNext(IN PNSQUERY NsQuery,IN DWORD ControlFlags,OUT PDWORD BufferLength,OUT LPWSAQUERYSETW Results)194 WsNqLookupServiceNext(IN PNSQUERY NsQuery,
195 IN DWORD ControlFlags,
196 OUT PDWORD BufferLength,
197 OUT LPWSAQUERYSETW Results)
198 {
199 INT ErrorCode = SOCKET_ERROR, OldErrorCode;
200 PNSQUERY_PROVIDER Provider, NextProvider;
201 PLIST_ENTRY Entry;
202
203 /* Make sure we're not shutting down */
204 if (NsQuery->ShuttingDown)
205 {
206 /* We are shutting down, fail */
207 SetLastError(WSAECANCELLED);
208 return ErrorCode;
209 }
210
211 /* Acquire query lock */
212 WsNqLock();
213
214 /* Check if we already have an active provider */
215 NextProvider = NsQuery->ActiveProvider;
216 if (!NextProvider)
217 {
218 /* Make sure we have a current provider */
219 if (!NsQuery->CurrentProvider)
220 {
221 /* We don't; fail */
222 WsNqUnlock();
223 SetLastError(WSA_E_NO_MORE);
224 return SOCKET_ERROR;
225 }
226
227 /* Get the last provider in the list and start looping */
228 Entry = NsQuery->ProviderList.Blink;
229 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
230 while (NextProvider)
231 {
232 /* Check if this is a new-style provider */
233 if (NextProvider->Provider->Service.NSPIoctl)
234 {
235 /* Remove it and re-add it on top */
236 RemoveEntryList(&NextProvider->QueryLink);
237 InsertHeadList(&NsQuery->ProviderList, &NextProvider->QueryLink);
238
239 /* Set it as the active provider and exit the loop */
240 NsQuery->ActiveProvider = NextProvider;
241 break;
242 }
243
244 /* Get the previous provider */
245 NextProvider = WsNqPreviousProvider(NsQuery, NextProvider);
246 }
247 }
248
249 /* Release the lock */
250 WsNqUnlock();
251
252 /* Restart and keep looping as long as there is an active provider */
253 while (NextProvider)
254 {
255 /* Call its routine */
256 ErrorCode = WsNqProvLookupServiceNext(NextProvider,
257 ControlFlags,
258 BufferLength,
259 Results);
260 /* Check for error or shutdown */
261 if ((ErrorCode == ERROR_SUCCESS) ||
262 (GetLastError() == WSAEFAULT) || (NsQuery->ShuttingDown))
263 {
264 /* Get out */
265 break;
266 }
267
268 /* Acquire Query Lock */
269 WsNqLock();
270
271 /* Check if we have an active provider */
272 if (NsQuery->ActiveProvider)
273 {
274 /* Save the old provider and get the next one */
275 Provider = NextProvider;
276 NextProvider = WsNqNextProvider(NsQuery, NsQuery->ActiveProvider);
277
278 /* Was the old provider our active? */
279 if (Provider == NsQuery->ActiveProvider)
280 {
281 /* Change our active provider to the new one */
282 NsQuery->ActiveProvider = NextProvider;
283 }
284 }
285 else
286 {
287 /* No next provider */
288 NextProvider = NULL;
289 }
290
291 /* Check if we failed and if we can try again */
292 if (!(NextProvider) &&
293 (ErrorCode == SOCKET_ERROR) &&
294 (NsQuery->TryAgain))
295 {
296 /* Save the error code so RAS doesn't overwrite it */
297 OldErrorCode = GetLastError();
298
299 /* Make sure we won't try for a 3rd time */
300 NsQuery->TryAgain = FALSE;
301
302 /* Call the helper to auto-dial */
303 if (WSAttemptAutodialName(NsQuery->QuerySet))
304 {
305 /* It succeeded, so we'll delete the current state. */
306 while (!IsListEmpty(&NsQuery->ProviderList))
307 {
308 /* Remove the entry and get its provider */
309 Entry = RemoveHeadList(&NsQuery->ProviderList);
310 Provider = CONTAINING_RECORD(Entry,
311 NSQUERY_PROVIDER,
312 QueryLink);
313
314 /* Reset it */
315 WsNqProvLookupServiceEnd(Provider);
316 WsNqProvDelete(Provider);
317 }
318
319 /* Start a new query */
320 if (WsNqLookupServiceBegin(NsQuery,
321 NsQuery->QuerySet,
322 NsQuery->ControlFlags,
323 NsQuery->Catalog) == ERROR_SUCCESS)
324 {
325 /* New query succeeded, set active provider now */
326 NsQuery->ActiveProvider =
327 WsNqNextProvider(NsQuery, NsQuery->ActiveProvider);
328 }
329 }
330 else
331 {
332 /* Reset the error code */
333 SetLastError(OldErrorCode);
334 }
335 }
336
337 /* Release lock */
338 WsNqUnlock();
339 }
340
341 /* Return */
342 return ErrorCode;
343 }
344
345 DWORD
346 WSAAPI
WsNqLookupServiceBegin(IN PNSQUERY NsQuery,IN LPWSAQUERYSETW Restrictions,IN DWORD ControlFlags,IN PNSCATALOG Catalog)347 WsNqLookupServiceBegin(IN PNSQUERY NsQuery,
348 IN LPWSAQUERYSETW Restrictions,
349 IN DWORD ControlFlags,
350 IN PNSCATALOG Catalog)
351 {
352 WSASERVICECLASSINFOW ClassInfo;
353 LPWSASERVICECLASSINFOW pClassInfo = &ClassInfo;
354 PNSQUERY_PROVIDER Provider, NextProvider;
355 PLIST_ENTRY Entry;
356 INT ErrorCode;
357 DWORD ClassInfoSize;
358 PNSCATALOG_ENTRY CatalogEntry = NULL;
359 ENUM_CONTEXT EnumContext;
360 BOOLEAN TryAgain;
361
362 /* Check for RAS Auto-dial attempt */
363 if (NsQuery->TryAgain)
364 {
365 /* Make a copy of the query set */
366 ErrorCode = CopyQuerySetW(Restrictions, &NsQuery->QuerySet);
367 TryAgain = (ErrorCode == ERROR_SUCCESS);
368
369 /* Check if we'll try again */
370 if (!TryAgain)
371 {
372 /* We won't, fail */
373 SetLastError(ErrorCode);
374 ErrorCode = SOCKET_ERROR;
375 NsQuery->TryAgain = FALSE;
376 goto Exit;
377 }
378
379 /* Cache the information for a restart */
380 NsQuery->ControlFlags = ControlFlags;
381 NsQuery->Catalog = Catalog;
382 }
383
384 /* Check if we have a specific ID */
385 if (Restrictions->lpNSProviderId)
386 {
387 /* Get the catalog entry */
388 ErrorCode = WsNcGetCatalogFromProviderId(Catalog,
389 Restrictions->lpNSProviderId,
390 &CatalogEntry);
391 /* Check for failure */
392 if (ErrorCode != ERROR_SUCCESS)
393 {
394 /* Fail */
395 SetLastError(WSAEINVAL);
396 ErrorCode = SOCKET_ERROR;
397 goto Exit;
398 }
399 /* We succeeded, add this provider */
400 else if (!WsNqAddProvider(NsQuery, CatalogEntry->Provider))
401 {
402 /* Fail */
403 SetLastError(WSA_NOT_ENOUGH_MEMORY);
404 ErrorCode = SOCKET_ERROR;
405 goto Exit;
406 }
407 }
408 else
409 {
410 /* Setup the lookup context */
411 EnumContext.lpqsRestrictions = Restrictions;
412 EnumContext.ErrorCode = ERROR_SUCCESS;
413 EnumContext.NsQuery = NsQuery;
414 EnumContext.Catalog = Catalog;
415
416 /* Do a lookup for every entry */
417 WsNcEnumerateCatalogItems(Catalog,
418 WsNqBeginEnumerationProc,
419 &EnumContext);
420 ErrorCode = EnumContext.ErrorCode;
421
422 /* Check for success */
423 if (ErrorCode != ERROR_SUCCESS)
424 {
425 /* Fail */
426 SetLastError(WSAEINVAL);
427 ErrorCode = SOCKET_ERROR;
428 goto Exit;
429 }
430 }
431
432 /* Get the class information */
433 ClassInfo.lpServiceClassId = Restrictions->lpServiceClassId;
434 ErrorCode = WsNcGetServiceClassInfo(Catalog, &ClassInfoSize, pClassInfo);
435
436 /* Check if more buffer space is needed */
437 if ((ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT))
438 {
439 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
440 }
441 else
442 {
443 /* Assume success */
444 ErrorCode = ERROR_SUCCESS;
445 }
446
447 /* Check if the provider list is empty */
448 if (IsListEmpty(&NsQuery->ProviderList))
449 {
450 /* We don't have any providers to handle this! */
451 ErrorCode = SOCKET_ERROR;
452 SetLastError(WSASERVICE_NOT_FOUND);
453 goto Exit;
454 }
455
456 /* Get the first provider and loop */
457 Entry = NsQuery->ProviderList.Flink;
458 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
459 while (NextProvider)
460 {
461 /* Call it */
462 ErrorCode = WsNqProvLookupServiceBegin(NextProvider,
463 Restrictions,
464 pClassInfo,
465 ControlFlags);
466 /* Check for error */
467 if (ErrorCode == SOCKET_ERROR)
468 {
469 /* Remove this provider, get the next one, delete the old one */
470 Provider = NextProvider;
471 NextProvider = WsNqNextProvider(NsQuery, NextProvider);
472 RemoveEntryList(&Provider->QueryLink);
473 WsNqProvDelete(Provider);
474 }
475 else
476 {
477 /* Get the next provider */
478 NextProvider = WsNqNextProvider(NsQuery, NextProvider);
479 }
480 }
481
482 Exit:
483 /* Check if we had an error somewhere */
484 if (ErrorCode == SOCKET_ERROR)
485 {
486 /* Loop the list */
487 while (!IsListEmpty(&NsQuery->ProviderList))
488 {
489 /* Remove this provider */
490 Entry = RemoveHeadList(&NsQuery->ProviderList);
491
492 /* Get the failed provider and delete it */
493 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
494 WsNqProvDelete(Provider);
495 }
496 }
497 else
498 {
499 /* Set the active provider */
500 Entry = NsQuery->ProviderList.Flink;
501 NsQuery->ActiveProvider = CONTAINING_RECORD(Entry,
502 NSQUERY_PROVIDER,
503 QueryLink);
504 }
505
506 /* Return */
507 return ErrorCode;
508 }
509
510 PNSQUERY_PROVIDER
511 WSAAPI
WsNqNextProvider(IN PNSQUERY Query,IN PNSQUERY_PROVIDER Provider)512 WsNqNextProvider(IN PNSQUERY Query,
513 IN PNSQUERY_PROVIDER Provider)
514 {
515 PNSQUERY_PROVIDER NextProvider = NULL;
516 PLIST_ENTRY Entry;
517
518 /* Get the first entry and get its provider */
519 Entry = Provider->QueryLink.Flink;
520 if (Entry != &Query->ProviderList)
521 {
522 /* Get the current provider */
523 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
524 }
525
526 /* Return it */
527 return NextProvider;
528 }
529
530 PNSQUERY_PROVIDER
531 WSAAPI
WsNqPreviousProvider(IN PNSQUERY Query,IN PNSQUERY_PROVIDER Provider)532 WsNqPreviousProvider(IN PNSQUERY Query,
533 IN PNSQUERY_PROVIDER Provider)
534 {
535 PNSQUERY_PROVIDER PrevProvider = NULL;
536 PLIST_ENTRY Entry;
537
538 /* Get the last entry and get its provider */
539 Entry = Provider->QueryLink.Blink;
540 if (Entry != &Query->ProviderList)
541 {
542 /* Get the current provider */
543 PrevProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
544 }
545
546 /* Return it */
547 return PrevProvider;
548 }
549
550 BOOL
551 WSAAPI
WsNqAddProvider(IN PNSQUERY Query,IN PNS_PROVIDER Provider)552 WsNqAddProvider(IN PNSQUERY Query,
553 IN PNS_PROVIDER Provider)
554 {
555 BOOL Success = TRUE;
556 PNSQUERY_PROVIDER QueryProvider;
557
558 /* Allocate a new Query Provider */
559 if ((QueryProvider = WsNqProvAllocate()))
560 {
561 /* Initialize it */
562 WsNqProvInitialize(QueryProvider, Provider);
563
564 /* Insert it into the provider list */
565 InsertTailList(&Query->ProviderList, &QueryProvider->QueryLink);
566 }
567 else
568 {
569 /* We failed */
570 SetLastError(WSASYSCALLFAILURE);
571 Success = FALSE;
572 }
573
574 /* Return */
575 return Success;
576 }
577
578