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