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