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
WsNcAllocate(VOID)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
WsNcOpen(IN PNSCATALOG Catalog,IN HKEY ParentKey)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
WsNcInitializeFromRegistry(IN PNSCATALOG Catalog,IN HKEY ParentKey,IN HANDLE CatalogEvent)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
WsNcRefreshFromRegistry(IN PNSCATALOG Catalog,IN HANDLE CatalogEvent)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
WsNcEnumerateCatalogItems(IN PNSCATALOG Catalog,IN PNSCATALOG_ENUMERATE_PROC Callback,IN PVOID Context)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
WsNcLoadProvider(IN PNSCATALOG Catalog,IN PNSCATALOG_ENTRY CatalogEntry)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
WsNcGetServiceClassInfo(IN PNSCATALOG Catalog,IN OUT LPDWORD BugSize,IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo)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
WsNcUpdateNamespaceList(IN PNSCATALOG Catalog,IN PLIST_ENTRY List)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
WsNcGetCatalogFromProviderId(IN PNSCATALOG Catalog,IN LPGUID ProviderId,OUT PNSCATALOG_ENTRY * CatalogEntry)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
WsNcMatchProtocols(IN DWORD NameSpace,IN LONG AddressFamily,IN LPWSAQUERYSETW QuerySet)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
WsNcRemoveCatalogItem(IN PNSCATALOG Catalog,IN PNSCATALOG_ENTRY Entry)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
WsNcDelete(IN PNSCATALOG Catalog)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