xref: /reactos/dll/win32/ws2_32/src/nsquery.c (revision 40462c92)
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 = 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
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
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
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