a361819e3626e7435dd7adcc3f901b78575b5640
[reactos.git] / reactos / dll / win32 / ws2_32 / src / nsquery.c
1 /*
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)
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
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
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
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
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
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
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
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
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 /* Save the current active provider */
272 Provider = NsQuery->ActiveProvider;
273
274 /* Check if one exists */
275 if (Provider)
276 {
277 /* Get the next one */
278 NextProvider = WsNqNextProvider(NsQuery,
279 NsQuery->ActiveProvider);
280
281 /* Was the old provider our active? */
282 if (Provider == NsQuery->ActiveProvider)
283 {
284 /* Change our active provider to the new one */
285 NsQuery->ActiveProvider = NextProvider;
286 }
287 }
288 else
289 {
290 /* No next provider */
291 NextProvider = NULL;
292 }
293
294 /* Check if we failed and if we can try again */
295 if (!(NextProvider) &&
296 (ErrorCode == SOCKET_ERROR) &&
297 (NsQuery->TryAgain))
298 {
299 /* Save the error code so RAS doesn't overwrite it */
300 OldErrorCode = GetLastError();
301
302 /* Make sure we won't try for a 3rd time */
303 NsQuery->TryAgain = FALSE;
304
305 /* Call the helper to auto-dial */
306 if (WSAttemptAutodialName(NsQuery->QuerySet))
307 {
308 /* It succeeded, so we'll delete the current state. */
309 while (!IsListEmpty(&NsQuery->ProviderList))
310 {
311 /* Remove the entry and get its provider */
312 Entry = RemoveHeadList(&NsQuery->ProviderList);
313 Provider = CONTAINING_RECORD(Entry,
314 NSQUERY_PROVIDER,
315 QueryLink);
316
317 /* Reset it */
318 WsNqProvLookupServiceEnd(Provider);
319 WsNqProvDelete(Provider);
320 }
321
322 /* Start a new query */
323 if (WsNqLookupServiceBegin(NsQuery,
324 NsQuery->QuerySet,
325 NsQuery->ControlFlags,
326 NsQuery->Catalog) == ERROR_SUCCESS)
327 {
328 /* New query succeeded, set active provider now */
329 NsQuery->ActiveProvider =
330 WsNqNextProvider(NsQuery,
331 NsQuery->ActiveProvider);
332 }
333 }
334 else
335 {
336 /* Reset the error code */
337 SetLastError(OldErrorCode);
338 }
339 }
340
341 /* Release lock */
342 WsNqUnlock();
343 }
344
345 /* Return */
346 return ErrorCode;
347 }
348
349 DWORD
350 WSAAPI
351 WsNqLookupServiceBegin(IN PNSQUERY NsQuery,
352 IN LPWSAQUERYSETW Restrictions,
353 IN DWORD ControlFlags,
354 IN PNSCATALOG Catalog)
355 {
356 WSASERVICECLASSINFOW ClassInfo;
357 LPWSASERVICECLASSINFOW pClassInfo = &ClassInfo;
358 PNSQUERY_PROVIDER Provider, NextProvider;
359 PLIST_ENTRY Entry;
360 INT ErrorCode;
361 DWORD ClassInfoSize;
362 PNSCATALOG_ENTRY CatalogEntry;
363 ENUM_CONTEXT EnumContext;
364 BOOLEAN TryAgain;
365
366 /* Check for RAS Auto-dial attempt */
367 if (NsQuery->TryAgain)
368 {
369 /* Make a copy of the query set */
370 ErrorCode = CopyQuerySetW(Restrictions, &NsQuery->QuerySet);
371 TryAgain = (ErrorCode == ERROR_SUCCESS);
372
373 /* Check if we'll try again */
374 if (!TryAgain)
375 {
376 /* We won't, fail */
377 SetLastError(ErrorCode);
378 ErrorCode = SOCKET_ERROR;
379 NsQuery->TryAgain = FALSE;
380 goto error;
381 }
382
383 /* Cache the information for a restart */
384 NsQuery->ControlFlags = ControlFlags;
385 NsQuery->Catalog = Catalog;
386 }
387
388 /* Check if we have a specific ID */
389 if (Restrictions->lpNSProviderId)
390 {
391 /* Get the provider */
392 ErrorCode = WsNcGetCatalogFromProviderId(Catalog,
393 Restrictions->lpNSProviderId,
394 &CatalogEntry);
395 /* Check for success */
396 if (ErrorCode != ERROR_SUCCESS)
397 {
398 /* Fail */
399 SetLastError(WSAEINVAL);
400 ErrorCode = SOCKET_ERROR;
401 goto error;
402 }
403 else
404 {
405 /* Add this provider */
406 WsNqAddProvider(NsQuery, CatalogEntry->Provider);
407 }
408 }
409 else
410 {
411 /* Setup the lookup context */
412 EnumContext.lpqsRestrictions = Restrictions;
413 EnumContext.ErrorCode = ERROR_SUCCESS;
414 EnumContext.NsQuery = NsQuery;
415 EnumContext.Catalog = Catalog;
416
417 /* Do a lookup for every entry */
418 WsNcEnumerateCatalogItems(Catalog,
419 WsNqBeginEnumerationProc,
420 &EnumContext);
421 ErrorCode = EnumContext.ErrorCode;
422
423 /* Check for success */
424 if (ErrorCode != ERROR_SUCCESS)
425 {
426 /* Fail */
427 SetLastError(WSAEINVAL);
428 ErrorCode = SOCKET_ERROR;
429 goto error;
430 }
431 }
432
433 /* Get the class information */
434 ClassInfo.lpServiceClassId = Restrictions->lpServiceClassId;
435 ErrorCode = WsNcGetServiceClassInfo(Catalog, &ClassInfoSize, pClassInfo);
436
437 /* Check if more buffer space is needed */
438 if ((ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT))
439 {
440 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
441 }
442 else
443 {
444 /* Assume success */
445 ErrorCode = ERROR_SUCCESS;
446 }
447
448 /* Check if the provider list is empty */
449 if (IsListEmpty(&NsQuery->ProviderList))
450 {
451 /* We don't have any providers to handle this! */
452 ErrorCode = SOCKET_ERROR;
453 SetLastError(WSASERVICE_NOT_FOUND);
454 goto error;
455 }
456
457 /* Get the first provider and loop */
458 Entry = NsQuery->ProviderList.Flink;
459 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
460 while (NextProvider)
461 {
462 /* Call it */
463 ErrorCode = WsNqProvLookupServiceBegin(NextProvider,
464 Restrictions,
465 pClassInfo,
466 ControlFlags);
467 /* Check for error */
468 if (ErrorCode == SOCKET_ERROR)
469 {
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);
475 }
476 else
477 {
478 /* Get the next provider */
479 NextProvider = WsNqNextProvider(NsQuery, NextProvider);
480 }
481 }
482
483 error:
484 /* Check if we had an error somewhere */
485 if (ErrorCode == SOCKET_ERROR)
486 {
487 /* Loop the list */
488 while (!IsListEmpty(&NsQuery->ProviderList))
489 {
490 /* Remove this provider */
491 Entry = RemoveHeadList(&NsQuery->ProviderList);
492
493 /* Get the failed provider and delete it */
494 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
495 WsNqProvDelete(Provider);
496 }
497 }
498 else
499 {
500 /* Set the active provider */
501 Entry = NsQuery->ProviderList.Flink;
502 NsQuery->ActiveProvider = CONTAINING_RECORD(Entry,
503 NSQUERY_PROVIDER,
504 QueryLink);
505 }
506
507 /* Return */
508 return ErrorCode;
509 }
510
511 PNSQUERY_PROVIDER
512 WSAAPI
513 WsNqNextProvider(IN PNSQUERY Query,
514 IN PNSQUERY_PROVIDER Provider)
515 {
516 PNSQUERY_PROVIDER NextProvider = NULL;
517 PLIST_ENTRY Entry;
518
519 /* Get the first entry and get its provider */
520 Entry = Provider->QueryLink.Flink;
521 if (Entry != &Query->ProviderList)
522 {
523 /* Get the current provider */
524 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
525 }
526
527 /* Return it */
528 return NextProvider;
529 }
530
531 PNSQUERY_PROVIDER
532 WSAAPI
533 WsNqPreviousProvider(IN PNSQUERY Query,
534 IN PNSQUERY_PROVIDER Provider)
535 {
536 PNSQUERY_PROVIDER PrevProvider = NULL;
537 PLIST_ENTRY Entry;
538
539 /* Get the last entry and get its provider */
540 Entry = Provider->QueryLink.Blink;
541 if (Entry != &Query->ProviderList)
542 {
543 /* Get the current provider */
544 PrevProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
545 }
546
547 /* Return it */
548 return PrevProvider;
549 }
550
551 BOOL
552 WSAAPI
553 WsNqAddProvider(IN PNSQUERY Query,
554 IN PNS_PROVIDER Provider)
555 {
556 BOOL Success = TRUE;
557 PNSQUERY_PROVIDER QueryProvider;
558
559 /* Allocate a new Query Provider */
560 if ((QueryProvider = WsNqProvAllocate()))
561 {
562 /* Initialize it */
563 WsNqProvInitialize(QueryProvider, Provider);
564
565 /* Insert it into the provider list */
566 InsertTailList(&Query->ProviderList, &QueryProvider->QueryLink);
567 }
568 else
569 {
570 /* We failed */
571 SetLastError(WSASYSCALLFAILURE);
572 Success = FALSE;
573 }
574
575 /* Return */
576 return Success;
577 }
578