xref: /reactos/dll/win32/ws2_32/src/nscatalo.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/nscatalo.c
5  * PURPOSE:     Namespace Catalog Object
6  * PROGRAMMER:  Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ws2_32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* DATA **********************************************************************/
17 
18 #define WsNcLock()          EnterCriticalSection(&Catalog->Lock)
19 #define WsNcUnlock()        LeaveCriticalSection(&Catalog->Lock)
20 
21 /* FUNCTIONS *****************************************************************/
22 
23 PNSCATALOG
24 WSAAPI
25 WsNcAllocate(VOID)
26 {
27     PNSCATALOG Catalog;
28 
29     /* Allocate the catalog */
30     Catalog = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*Catalog));
31 
32     /* Return it */
33     return Catalog;
34 }
35 
36 BOOLEAN
37 WSAAPI
38 WsNcOpen(IN PNSCATALOG Catalog,
39          IN HKEY ParentKey)
40 {
41     LONG ErrorCode;
42     DWORD CreateDisposition;
43     HKEY CatalogKey, NewKey;
44     DWORD RegType = REG_DWORD;
45     DWORD RegSize = sizeof(DWORD);
46     DWORD UniqueId = 0;
47     DWORD NewData = 0;
48     CHAR* CatalogKeyName;
49 
50     /* Initialize the catalog lock and namespace list */
51     InitializeCriticalSection(&Catalog->Lock);
52     InitializeListHead(&Catalog->CatalogList);
53 
54     /* Read the catalog name */
55     ErrorCode = RegQueryValueEx(ParentKey,
56                                 "Current_NameSpace_Catalog",
57                                 0,
58                                 &RegType,
59                                 NULL,
60                                 &RegSize);
61 
62     CatalogKeyName = HeapAlloc(WsSockHeap, 0, RegSize);
63 
64     /* Read the catalog name */
65     ErrorCode = RegQueryValueEx(ParentKey,
66                                 "Current_NameSpace_Catalog",
67                                 0,
68                                 &RegType,
69                                 (LPBYTE)CatalogKeyName,
70                                 &RegSize);
71 
72     /* Open the Catalog Key */
73     ErrorCode = RegOpenKeyEx(ParentKey,
74                              CatalogKeyName,
75                              0,
76                              MAXIMUM_ALLOWED,
77                              &CatalogKey);
78 
79     /* If we didn't find the key, create it */
80     if (ErrorCode == ERROR_SUCCESS)
81     {
82         /* Fake that we opened an existing key */
83         CreateDisposition = REG_OPENED_EXISTING_KEY;
84     }
85     else if (ErrorCode == ERROR_FILE_NOT_FOUND)
86     {
87         /* Create the Catalog Name */
88         ErrorCode = RegCreateKeyEx(ParentKey,
89                                    CatalogKeyName,
90                                    0,
91                                    NULL,
92                                    REG_OPTION_NON_VOLATILE,
93                                    KEY_ALL_ACCESS,
94                                    NULL,
95                                    &CatalogKey,
96                                    &CreateDisposition);
97     }
98 
99     HeapFree(WsSockHeap, 0, CatalogKeyName);
100     RegType = REG_DWORD;
101     RegSize = sizeof(DWORD);
102 
103     /* Fail if that didn't work */
104     if (ErrorCode != ERROR_SUCCESS) return FALSE;
105 
106     /* Check if we had to create the key */
107     if (CreateDisposition == REG_CREATED_NEW_KEY)
108     {
109         /* Write the count of entries (0 now) */
110         ErrorCode = RegSetValueEx(CatalogKey,
111                                   "Num_Catalog_Entries",
112                                   0,
113                                   REG_DWORD,
114                                   (LPBYTE)&NewData,
115                                   sizeof(NewData));
116         if (ErrorCode != ERROR_SUCCESS)
117         {
118             /* Close the key and fail */
119             RegCloseKey(CatalogKey);
120             return FALSE;
121         }
122 
123         /* Write the first catalog entry Uniqe ID */
124         NewData = 1;
125         ErrorCode = RegSetValueEx(CatalogKey,
126                                   "Serial_Access_Num",
127                                   0,
128                                   REG_DWORD,
129                                   (LPBYTE)&NewData,
130                                   sizeof(NewData));
131         if (ErrorCode != ERROR_SUCCESS)
132         {
133             /* Close the key and fail */
134             RegCloseKey(CatalogKey);
135             return FALSE;
136         }
137 
138         /* Create a key for this entry */
139         ErrorCode = RegCreateKeyEx(CatalogKey,
140                                    "Catalog_Entries",
141                                    0,
142                                    NULL,
143                                    REG_OPTION_NON_VOLATILE,
144                                    KEY_ALL_ACCESS,
145                                    NULL,
146                                    &NewKey,
147                                    &CreateDisposition);
148         if (ErrorCode != ERROR_SUCCESS)
149         {
150             /* Close the key and fail */
151             RegCloseKey(CatalogKey);
152             return FALSE;
153         }
154 
155         /* Close the key since we don't need it */
156         RegCloseKey(NewKey);
157     }
158     else
159     {
160         RegSize = sizeof(UniqueId);
161         /* Read the serial number */
162         ErrorCode = RegQueryValueEx(CatalogKey,
163                                     "Serial_Access_Num",
164                                     0,
165                                     &RegType,
166                                     (LPBYTE)&UniqueId,
167                                     &RegSize);
168 
169         /* Check if it's missing for some reason */
170         if (ErrorCode != ERROR_SUCCESS)
171         {
172             /* Write the first catalog entry Unique ID */
173             NewData = 1;
174             ErrorCode = RegSetValueEx(CatalogKey,
175                                       "Serial_Access_Num",
176                                       0,
177                                       REG_DWORD,
178                                       (LPBYTE)&NewData,
179                                       sizeof(NewData));
180         }
181     }
182 
183     /* Set the Catalog Key */
184     Catalog->CatalogKey = CatalogKey;
185     return TRUE;
186 }
187 
188 INT
189 WSAAPI
190 WsNcInitializeFromRegistry(IN PNSCATALOG Catalog,
191                            IN HKEY ParentKey,
192                            IN HANDLE CatalogEvent)
193 {
194     INT ErrorCode = WSASYSCALLFAILURE;
195 
196     /* Open the catalog */
197     if (WsNcOpen(Catalog, ParentKey))
198     {
199         /* Refresh it */
200         ErrorCode = WsNcRefreshFromRegistry(Catalog, CatalogEvent);
201     }
202 
203     /* Return the status */
204     return ErrorCode;
205 }
206 
207 INT
208 WSAAPI
209 WsNcRefreshFromRegistry(IN PNSCATALOG Catalog,
210                         IN HANDLE CatalogEvent)
211 {
212     INT ErrorCode;
213     BOOLEAN LocalEvent = FALSE;
214     LIST_ENTRY LocalList;
215     DWORD UniqueId;
216     HKEY EntriesKey;
217     DWORD CatalogEntries;
218     PNSCATALOG_ENTRY CatalogEntry;
219     BOOL NewChangesMade;
220     PLIST_ENTRY Entry;
221     DWORD RegType = REG_DWORD;
222     DWORD RegSize = sizeof(DWORD);
223     DWORD i;
224 
225     /* Check if we got an event */
226     if (!CatalogEvent)
227     {
228         /* Create an event ourselves */
229         CatalogEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
230         if (!CatalogEvent) return WSASYSCALLFAILURE;
231         LocalEvent = TRUE;
232     }
233 
234     /* Lock the catalog */
235     WsNcLock();
236 
237     /* Initialize our local list for the loop */
238     InitializeListHead(&LocalList);
239 
240     /* Start looping */
241     do
242     {
243         /* Setup notifications for the catalog entry */
244         ErrorCode = WsSetupCatalogProtection(Catalog->CatalogKey,
245                                              CatalogEvent,
246                                              &UniqueId);
247         if (ErrorCode != ERROR_SUCCESS) break;
248 
249         /* Check if we've changed till now */
250         if (UniqueId == Catalog->UniqueId)
251         {
252             /* We haven't, so return */
253             ErrorCode = ERROR_SUCCESS;
254             break;
255         }
256 
257         /* Now Open the Entries */
258         ErrorCode = RegOpenKeyEx(Catalog->CatalogKey,
259                                  "Catalog_Entries",
260                                  0,
261                                  MAXIMUM_ALLOWED,
262                                  &EntriesKey);
263         if (ErrorCode != ERROR_SUCCESS)
264         {
265             /* Critical failure */
266             ErrorCode = WSASYSCALLFAILURE;
267             break;
268         }
269 
270         /* Find out how many there are */
271         ErrorCode = RegQueryValueEx(Catalog->CatalogKey,
272                                     "Num_Catalog_Entries",
273                                     0,
274                                     &RegType,
275                                     (LPBYTE)&CatalogEntries,
276                                     &RegSize);
277         if (ErrorCode != ERROR_SUCCESS)
278         {
279             /* Critical failure */
280             ErrorCode = WSASYSCALLFAILURE;
281             break;
282         }
283 
284         /* Initialize them all */
285         for (i = 1; i <= CatalogEntries; i++)
286         {
287             /* Allocate a Catalog Entry Structure */
288             CatalogEntry = WsNcEntryAllocate();
289             if (!CatalogEntry)
290             {
291                 /* Not enough memory, fail */
292                 ErrorCode = WSA_NOT_ENOUGH_MEMORY;
293                 break;
294             }
295 
296             /* Initialize it from the Registry Key */
297             ErrorCode = WsNcEntryInitializeFromRegistry(CatalogEntry,
298                                                         EntriesKey,
299                                                         i);
300             if (ErrorCode != ERROR_SUCCESS)
301             {
302                 /* We failed to get it, dereference the entry and leave */
303                 WsNcEntryDereference(CatalogEntry);
304                 break;
305             }
306 
307             /* Insert it to our List */
308             InsertTailList(&LocalList, &CatalogEntry->CatalogLink);
309         }
310 
311         /* Close the catalog key */
312         RegCloseKey(EntriesKey);
313 
314         /* Check if we changed during our read and if we have success */
315         NewChangesMade = WsCheckCatalogState(CatalogEvent);
316         if (!NewChangesMade && ErrorCode == ERROR_SUCCESS)
317         {
318             /* All is good, update the protocol list */
319             WsNcUpdateNamespaceList(Catalog, &LocalList);
320 
321             /* Update and return */
322             Catalog->UniqueId = UniqueId;
323             break;
324         }
325 
326         /* We failed and/or catalog data changed, free what we did till now */
327         while (!IsListEmpty(&LocalList))
328         {
329             /* Get the LP Catalog Item */
330             Entry = RemoveHeadList(&LocalList);
331             CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
332 
333             /* Dereference it */
334             WsNcEntryDereference(CatalogEntry);
335         }
336     } while (NewChangesMade);
337 
338     /* Release the lock */
339     WsNcUnlock();
340 
341     /* Close the event, if any was created by us */
342     if (LocalEvent) CloseHandle(CatalogEvent);
343 
344     /* All Done */
345     return ErrorCode;
346 }
347 
348 VOID
349 WSAAPI
350 WsNcEnumerateCatalogItems(IN PNSCATALOG Catalog,
351                           IN PNSCATALOG_ENUMERATE_PROC Callback,
352                           IN PVOID Context)
353 {
354     PLIST_ENTRY Entry;
355     PNSCATALOG_ENTRY CatalogEntry;
356     BOOL GoOn = TRUE;
357 
358     /* Lock the catalog */
359     WsNcLock();
360 
361     /* Loop the entries */
362     Entry = Catalog->CatalogList.Flink;
363     while (GoOn && (Entry != &Catalog->CatalogList))
364     {
365         /* Get the entry */
366         CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
367 
368         /* Move to the next one and call the callback */
369         Entry = Entry->Flink;
370         GoOn = Callback(Context, CatalogEntry);
371     }
372 
373     /* Release the lock */
374     WsNcUnlock();
375 }
376 
377 INT
378 WSAAPI
379 WsNcLoadProvider(IN PNSCATALOG Catalog,
380                  IN PNSCATALOG_ENTRY CatalogEntry)
381 {
382     INT ErrorCode = ERROR_SUCCESS;
383     PNS_PROVIDER Provider;
384 
385     /* Lock the catalog */
386     WsNcLock();
387 
388     /* Check if we have a provider already */
389     if (!CatalogEntry->Provider)
390     {
391         /* Allocate a provider */
392         if ((Provider = WsNpAllocate()))
393         {
394             /* Initialize it */
395             ErrorCode = WsNpInitialize(Provider,
396                                        CatalogEntry->DllPath,
397                                        &CatalogEntry->ProviderId);
398 
399             /* Ensure success */
400             if (ErrorCode == ERROR_SUCCESS)
401             {
402                 /* Set the provider */
403                 WsNcEntrySetProvider(CatalogEntry, Provider);
404             }
405 
406             /* Dereference it */
407             WsNpDereference(Provider);
408         }
409         else
410         {
411             /* No memory */
412             ErrorCode = WSA_NOT_ENOUGH_MEMORY;
413         }
414     }
415 
416     /* Release the lock and return */
417     WsNcUnlock();
418     return ErrorCode;
419 }
420 
421 INT
422 WSAAPI
423 WsNcGetServiceClassInfo(IN PNSCATALOG Catalog,
424                         IN OUT LPDWORD BugSize,
425                         IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)
426 {
427     /* Not yet implemented in the spec? */
428     SetLastError(ERROR_SUCCESS);
429     return SOCKET_ERROR;
430 }
431 
432 VOID
433 WSAAPI
434 WsNcUpdateNamespaceList(IN PNSCATALOG Catalog,
435                         IN PLIST_ENTRY List)
436 {
437     LIST_ENTRY TempList;
438     PNSCATALOG_ENTRY CatalogEntry, OldCatalogEntry;
439     PLIST_ENTRY Entry;
440 
441     /* First move from our list to the old one */
442     InsertHeadList(&Catalog->CatalogList, &TempList);
443     RemoveEntryList(&Catalog->CatalogList);
444     InitializeListHead(&Catalog->CatalogList);
445 
446     /* Loop every item on the list */
447     while (!IsListEmpty(List))
448     {
449         /* Get the catalog entry */
450         Entry = RemoveHeadList(List);
451         CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
452 
453         /* Check if this item is already on our list */
454         Entry = TempList.Flink;
455         while (Entry != &TempList)
456         {
457             /* Get the catalog entry */
458             OldCatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
459             Entry = Entry->Flink;
460 
461             /* Check if they match */
462             if (IsEqualGUID(&CatalogEntry->ProviderId,
463                             &OldCatalogEntry->ProviderId))
464             {
465                 /* We have a match, use the old item instead */
466                 WsNcEntryDereference(CatalogEntry);
467                 CatalogEntry = OldCatalogEntry;
468                 RemoveEntryList(&CatalogEntry->CatalogLink);
469 
470                 /* Decrease the number of protocols we have */
471                 Catalog->ItemCount--;
472                 break;
473             }
474         }
475 
476         /* Add this item */
477         InsertTailList(&Catalog->CatalogList, &CatalogEntry->CatalogLink);
478         Catalog->ItemCount++;
479     }
480 
481     /* If there's anything left on the temporary list */
482     while (!IsListEmpty(&TempList))
483     {
484         /* Get the entry */
485         Entry = RemoveHeadList(&TempList);
486         CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
487 
488         /* Remove it */
489         Catalog->ItemCount--;
490         WsNcEntryDereference(CatalogEntry);
491     }
492 }
493 
494 INT
495 WSAAPI
496 WsNcGetCatalogFromProviderId(IN PNSCATALOG Catalog,
497                              IN LPGUID ProviderId,
498                              OUT PNSCATALOG_ENTRY *CatalogEntry)
499 {
500     INT ErrorCode = WSAEINVAL;
501     PLIST_ENTRY NextEntry;
502     PNSCATALOG_ENTRY Entry;
503 
504     /* Lock the catalog */
505     WsNcLock();
506 
507     /* Match the Id with all the entries in the List */
508     NextEntry = Catalog->CatalogList.Flink;
509     while (NextEntry != &Catalog->CatalogList)
510     {
511         /* Get the Current Entry */
512         Entry = CONTAINING_RECORD(NextEntry, NSCATALOG_ENTRY, CatalogLink);
513         NextEntry = NextEntry->Flink;
514 
515         /* Check if this is the Catalog Entry ID we want */
516         if (IsEqualGUID(&Entry->ProviderId, ProviderId))
517         {
518             /* If it doesn't already have a provider, load the provider */
519             if (!Entry->Provider)
520                 ErrorCode = WsNcLoadProvider(Catalog, Entry);
521 
522             /* If we succeeded, reference the entry and return it */
523             if (Entry->Provider /* || ErrorCode == ERROR_SUCCESS */)
524             {
525                 InterlockedIncrement(&Entry->RefCount);
526                 *CatalogEntry = Entry;
527                 ErrorCode = ERROR_SUCCESS;
528                 break;
529             }
530         }
531     }
532 
533     /* Release the lock and return */
534     WsNcUnlock();
535     return ErrorCode;
536 }
537 
538 BOOL
539 WSAAPI
540 WsNcMatchProtocols(IN DWORD NameSpace,
541                    IN LONG AddressFamily,
542                    IN LPWSAQUERYSETW QuerySet)
543 {
544     DWORD ProtocolCount = QuerySet->dwNumberOfProtocols;
545     LPAFPROTOCOLS AfpProtocols = QuerySet->lpafpProtocols;
546     LONG Family;
547 
548     /* Check for valid family */
549     if (AddressFamily != -1)
550     {
551         /* Check if it's the magic */
552         if (AddressFamily == AF_UNSPEC) return TRUE;
553         Family = AddressFamily;
554     }
555     else
556     {
557         /* No family given, check for namespace */
558         if (NameSpace == NS_SAP)
559         {
560             /* Use IPX family */
561             Family = AF_IPX;
562         }
563         else
564         {
565             /* Other namespace, it's valid */
566             return TRUE;
567         }
568     }
569 
570     /* Now try to get a match */
571     while (ProtocolCount--)
572     {
573         /* Check this protocol entry */
574         if ((AfpProtocols->iAddressFamily == AF_UNSPEC) ||
575             (AfpProtocols->iAddressFamily == Family))
576         {
577             /* Match found */
578             return TRUE;
579         }
580 
581         /* Move to the next one */
582         AfpProtocols++;
583     }
584 
585     /* No match */
586     return FALSE;
587 }
588 
589 VOID
590 WSAAPI
591 WsNcRemoveCatalogItem(IN PNSCATALOG Catalog,
592                       IN PNSCATALOG_ENTRY Entry)
593 {
594     /* Remove the entry from the list */
595     RemoveEntryList(&Entry->CatalogLink);
596 
597     /* Decrease our count */
598     Catalog->ItemCount--;
599 }
600 
601 VOID
602 WSAAPI
603 WsNcDelete(IN PNSCATALOG Catalog)
604 {
605     PLIST_ENTRY Entry;
606     PNSCATALOG_ENTRY CatalogEntry;
607 
608     /* Check if we're initialized */
609     if (!Catalog->CatalogList.Flink) return;
610 
611     /* Acquire lock */
612     WsNcLock();
613 
614     /* Loop every entry */
615     Entry = Catalog->CatalogList.Flink;
616     while (Entry != &Catalog->CatalogList)
617     {
618         /* Get this entry */
619         CatalogEntry = CONTAINING_RECORD(Entry, NSCATALOG_ENTRY, CatalogLink);
620 
621         /* Remove it and dereference it */
622         WsNcRemoveCatalogItem(Catalog, CatalogEntry);
623         WsNcEntryDereference(CatalogEntry);
624 
625         /* Move to the next entry */
626         Entry = Catalog->CatalogList.Flink;
627     }
628 
629     /* Check if the catalog key is opened */
630     if (Catalog->CatalogKey)
631     {
632         /* Close it */
633         RegCloseKey(Catalog->CatalogKey);
634         Catalog->CatalogKey = NULL;
635     }
636 
637     /* Release and delete the lock */
638     WsNcUnlock();
639     DeleteCriticalSection(&Catalog->Lock);
640 
641     /* Delete the object */
642     HeapFree(WsSockHeap, 0, Catalog);
643 }
644