[WS2_32]: More fixes:
[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 /* 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
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;
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 error;
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 provider */
388 ErrorCode = WsNcGetCatalogFromProviderId(Catalog,
389 Restrictions->lpNSProviderId,
390 &CatalogEntry);
391 /* Check for success */
392 if (ErrorCode != ERROR_SUCCESS)
393 {
394 /* Fail */
395 SetLastError(WSAEINVAL);
396 ErrorCode = SOCKET_ERROR;
397 goto error;
398 }
399 else
400 {
401 /* Add this provider */
402 WsNqAddProvider(NsQuery, CatalogEntry->Provider);
403 }
404 }
405 else
406 {
407 /* Setup the lookup context */
408 EnumContext.lpqsRestrictions = Restrictions;
409 EnumContext.ErrorCode = ERROR_SUCCESS;
410 EnumContext.NsQuery = NsQuery;
411 EnumContext.Catalog = Catalog;
412
413 /* Do a lookup for every entry */
414 WsNcEnumerateCatalogItems(Catalog,
415 WsNqBeginEnumerationProc,
416 &EnumContext);
417 ErrorCode = EnumContext.ErrorCode;
418
419 /* Check for success */
420 if (ErrorCode != ERROR_SUCCESS)
421 {
422 /* Fail */
423 SetLastError(WSAEINVAL);
424 ErrorCode = SOCKET_ERROR;
425 goto error;
426 }
427 }
428
429 /* Get the class information */
430 ClassInfo.lpServiceClassId = Restrictions->lpServiceClassId;
431 ErrorCode = WsNcGetServiceClassInfo(Catalog, &ClassInfoSize, pClassInfo);
432
433 /* Check if more buffer space is needed */
434 if ((ErrorCode == SOCKET_ERROR) && (GetLastError() == WSAEFAULT))
435 {
436 /* FIXME: The WS 2.2 spec hasn't been finalized yet on this... */
437 }
438 else
439 {
440 /* Assume success */
441 ErrorCode = ERROR_SUCCESS;
442 }
443
444 /* Check if the provider list is empty */
445 if (IsListEmpty(&NsQuery->ProviderList))
446 {
447 /* We don't have any providers to handle this! */
448 ErrorCode = SOCKET_ERROR;
449 SetLastError(WSASERVICE_NOT_FOUND);
450 goto error;
451 }
452
453 /* Get the first provider and loop */
454 Entry = NsQuery->ProviderList.Flink;
455 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
456 while (NextProvider)
457 {
458 /* Call it */
459 ErrorCode = WsNqProvLookupServiceBegin(NextProvider,
460 Restrictions,
461 pClassInfo,
462 ControlFlags);
463 /* Check for error */
464 if (ErrorCode == SOCKET_ERROR)
465 {
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);
471 }
472 else
473 {
474 /* Get the next provider */
475 NextProvider = WsNqNextProvider(NsQuery, NextProvider);
476 }
477 }
478
479 error:
480 /* Check if we had an error somewhere */
481 if (ErrorCode == SOCKET_ERROR)
482 {
483 /* Loop the list */
484 while (!IsListEmpty(&NsQuery->ProviderList))
485 {
486 /* Remove this provider */
487 Entry = RemoveHeadList(&NsQuery->ProviderList);
488
489 /* Get the failed provider and delete it */
490 Provider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
491 WsNqProvDelete(Provider);
492 }
493 }
494 else
495 {
496 /* Set the active provider */
497 Entry = NsQuery->ProviderList.Flink;
498 NsQuery->ActiveProvider = CONTAINING_RECORD(Entry,
499 NSQUERY_PROVIDER,
500 QueryLink);
501 }
502
503 /* Return */
504 return ErrorCode;
505 }
506
507 PNSQUERY_PROVIDER
508 WSAAPI
509 WsNqNextProvider(IN PNSQUERY Query,
510 IN PNSQUERY_PROVIDER Provider)
511 {
512 PNSQUERY_PROVIDER NextProvider = NULL;
513 PLIST_ENTRY Entry;
514
515 /* Get the first entry and get its provider */
516 Entry = Provider->QueryLink.Flink;
517 if (Entry != &Query->ProviderList)
518 {
519 /* Get the current provider */
520 NextProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
521 }
522
523 /* Return it */
524 return NextProvider;
525 }
526
527 PNSQUERY_PROVIDER
528 WSAAPI
529 WsNqPreviousProvider(IN PNSQUERY Query,
530 IN PNSQUERY_PROVIDER Provider)
531 {
532 PNSQUERY_PROVIDER PrevProvider = NULL;
533 PLIST_ENTRY Entry;
534
535 /* Get the last entry and get its provider */
536 Entry = Provider->QueryLink.Blink;
537 if (Entry != &Query->ProviderList)
538 {
539 /* Get the current provider */
540 PrevProvider = CONTAINING_RECORD(Entry, NSQUERY_PROVIDER, QueryLink);
541 }
542
543 /* Return it */
544 return PrevProvider;
545 }
546
547 BOOL
548 WSAAPI
549 WsNqAddProvider(IN PNSQUERY Query,
550 IN PNS_PROVIDER Provider)
551 {
552 BOOL Success = TRUE;
553 PNSQUERY_PROVIDER QueryProvider;
554
555 /* Allocate a new Query Provider */
556 if ((QueryProvider = WsNqProvAllocate()))
557 {
558 /* Initialize it */
559 WsNqProvInitialize(QueryProvider, Provider);
560
561 /* Insert it into the provider list */
562 InsertTailList(&Query->ProviderList, &QueryProvider->QueryLink);
563 }
564 else
565 {
566 /* We failed */
567 SetLastError(WSASYSCALLFAILURE);
568 Success = FALSE;
569 }
570
571 /* Return */
572 return Success;
573 }
574