xref: /reactos/dll/win32/ws2_32/src/dcatalog.c (revision 53221834)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/dcatalog.c
5  * PURPOSE:     Transport 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 WsTcLock()          EnterCriticalSection(&Catalog->Lock)
19 #define WsTcUnlock()        LeaveCriticalSection(&Catalog->Lock)
20 
21 /* FUNCTIONS *****************************************************************/
22 
23 PTCATALOG
24 WSAAPI
25 WsTcAllocate(VOID)
26 {
27     PTCATALOG Catalog;
28 
29     /* Allocate the object */
30     Catalog = HeapAlloc(WsSockHeap, HEAP_ZERO_MEMORY, sizeof(*Catalog));
31 
32     /* Return it */
33     return Catalog;
34 }
35 
36 BOOL
37 WSAAPI
38 WsTcOpen(IN PTCATALOG Catalog,
39          IN HKEY ParentKey)
40 {
41     INT ErrorCode;
42     DWORD CreateDisposition;
43     HKEY CatalogKey, NewKey;
44     //DWORD CatalogEntries = 0;
45     DWORD RegType = REG_DWORD;
46     DWORD RegSize = sizeof(DWORD);
47     DWORD UniqueId = 0;
48     DWORD NewData = 0;
49     CHAR* CatalogKeyName;
50 
51     /* Initialize the catalog lock and namespace list */
52     InitializeCriticalSection(&Catalog->Lock);
53     InitializeListHead(&Catalog->ProtocolList);
54 
55     /* Read the catalog name */
56     ErrorCode = RegQueryValueEx(ParentKey,
57                                 "Current_Protocol_Catalog",
58                                 0,
59                                 &RegType,
60                                 NULL,
61                                 &RegSize);
62     if (ErrorCode == ERROR_FILE_NOT_FOUND)
63     {
64         static const CHAR DefaultCatalogName[] = "Protocol_Catalog9";
65         RegSize = sizeof(DefaultCatalogName);
66         CatalogKeyName = HeapAlloc(WsSockHeap, 0, RegSize);
67         memcpy(CatalogKeyName, DefaultCatalogName, RegSize);
68     }
69     else
70     {
71         if (ErrorCode != ERROR_SUCCESS)
72         {
73             DPRINT1("Failed to get protocol catalog name: %d.\n", ErrorCode);
74             return FALSE;
75         }
76 
77         if (RegType != REG_SZ)
78         {
79             DPRINT1("Protocol catalog name is not a string (Type %d).\n", RegType);
80             return FALSE;
81         }
82 
83         CatalogKeyName = HeapAlloc(WsSockHeap, 0, RegSize);
84 
85         /* Read the catalog name */
86         ErrorCode = RegQueryValueEx(ParentKey,
87                                     "Current_Protocol_Catalog",
88                                     0,
89                                     &RegType,
90                                     (LPBYTE)CatalogKeyName,
91                                     &RegSize);
92 
93         /* Open the Catalog Key */
94         ErrorCode = RegOpenKeyEx(ParentKey,
95                                  CatalogKeyName,
96                                  0,
97                                  MAXIMUM_ALLOWED,
98                                  &CatalogKey);
99     }
100 
101     /* If we didn't find the key, create it */
102     if (ErrorCode == ERROR_SUCCESS)
103     {
104         /* Fake that we opened an existing key */
105         CreateDisposition = REG_OPENED_EXISTING_KEY;
106     }
107     else if (ErrorCode == ERROR_FILE_NOT_FOUND)
108     {
109         /* Create the Catalog Name */
110         ErrorCode = RegCreateKeyEx(ParentKey,
111                                    CatalogKeyName,
112                                    0,
113                                    NULL,
114                                    REG_OPTION_NON_VOLATILE,
115                                    KEY_ALL_ACCESS,
116                                    NULL,
117                                    &CatalogKey,
118                                    &CreateDisposition);
119     }
120 
121     HeapFree(WsSockHeap, 0, CatalogKeyName);
122     RegType = REG_DWORD;
123     RegSize = sizeof(DWORD);
124 
125     /* Fail if that didn't work */
126     if (ErrorCode != ERROR_SUCCESS) return FALSE;
127 
128     /* Check if we had to create the key */
129     if (CreateDisposition == REG_CREATED_NEW_KEY)
130     {
131         /* Write the count of entries (0 now) */
132         ErrorCode = RegSetValueEx(CatalogKey,
133                                   "Num_Catalog_Entries",
134                                   0,
135                                   REG_DWORD,
136                                   (LPBYTE)&NewData,
137                                   sizeof(NewData));
138         if (ErrorCode != ERROR_SUCCESS)
139         {
140             /* Close the key and fail */
141             RegCloseKey(CatalogKey);
142             return FALSE;
143         }
144 
145         /* Write the first catalog entry ID */
146         NewData = 1001;
147         ErrorCode = RegSetValueEx(CatalogKey,
148                                   "Next_Catalog_Entry_ID",
149                                   0,
150                                   REG_DWORD,
151                                   (LPBYTE)&NewData,
152                                   sizeof(NewData));
153         if (ErrorCode != ERROR_SUCCESS)
154         {
155             /* Close the key and fail */
156             RegCloseKey(CatalogKey);
157             return FALSE;
158         }
159 
160         /* Write the first catalog entry Uniqe ID */
161         NewData = 1;
162         ErrorCode = RegSetValueEx(CatalogKey,
163                                   "Serial_Access_Num",
164                                   0,
165                                   REG_DWORD,
166                                   (LPBYTE)&NewData,
167                                   sizeof(NewData));
168         if (ErrorCode != ERROR_SUCCESS)
169         {
170             /* Close the key and fail */
171             RegCloseKey(CatalogKey);
172             return FALSE;
173         }
174 
175         /* Create a key for this entry */
176         ErrorCode = RegCreateKeyEx(CatalogKey,
177                                    "Catalog_Entries",
178                                    0,
179                                    NULL,
180                                    REG_OPTION_NON_VOLATILE,
181                                    KEY_ALL_ACCESS,
182                                    NULL,
183                                    &NewKey,
184                                    &CreateDisposition);
185         if (ErrorCode != ERROR_SUCCESS)
186         {
187             /* Close the key and fail */
188             RegCloseKey(CatalogKey);
189             return FALSE;
190         }
191 
192         /* Close the key since we don't need it */
193         RegCloseKey(NewKey);
194     }
195     else
196     {
197         RegSize = sizeof(DWORD);
198         /* Read the serial number */
199         ErrorCode = RegQueryValueEx(CatalogKey,
200                                     "Serial_Access_Num",
201                                     0,
202                                     &RegType,
203                                     (LPBYTE)&UniqueId,
204                                     &RegSize);
205 
206         /* Check if it's missing for some reason */
207         if (ErrorCode != ERROR_SUCCESS)
208         {
209             /* Write the first catalog entry Unique ID */
210             NewData = 1;
211             ErrorCode = RegSetValueEx(CatalogKey,
212                                       "Serial_Access_Num",
213                                       0,
214                                       REG_DWORD,
215                                       (LPBYTE)&NewData,
216                                       sizeof(NewData));
217         }
218     }
219 
220     /* Set the Catalog Key */
221     Catalog->CatalogKey = CatalogKey;
222     return TRUE;
223 }
224 
225 DWORD
226 WSAAPI
227 WsTcInitializeFromRegistry(IN PTCATALOG Catalog,
228                            IN HKEY ParentKey,
229                            IN HANDLE CatalogEvent)
230 {
231     INT ErrorCode = WSASYSCALLFAILURE;
232 
233     /* Open the catalog */
234     if (WsTcOpen(Catalog, ParentKey))
235     {
236         /* Refresh it */
237         ErrorCode = WsTcRefreshFromRegistry(Catalog, CatalogEvent);
238     }
239 
240     /* Return the status */
241     return ErrorCode;
242 }
243 
244 DWORD
245 WSAAPI
246 WsTcRefreshFromRegistry(IN PTCATALOG Catalog,
247                         IN HANDLE CatalogEvent)
248 {
249     INT ErrorCode;
250     BOOLEAN LocalEvent = FALSE;
251     LIST_ENTRY LocalList;
252     DWORD UniqueId;
253     HKEY EntriesKey;
254     DWORD CatalogEntries;
255     PTCATALOG_ENTRY CatalogEntry;
256     DWORD NextCatalogEntry;
257     BOOL NewChangesMade;
258     PLIST_ENTRY Entry;
259     DWORD RegType = REG_DWORD;
260     DWORD RegSize = sizeof(DWORD);
261     DWORD i;
262 
263     /* Check if we got an event */
264     if (!CatalogEvent)
265     {
266         /* Create an event ourselves */
267         CatalogEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
268         if (!CatalogEvent) return WSASYSCALLFAILURE;
269         LocalEvent = TRUE;
270     }
271 
272     /* Lock the catalog */
273     WsTcLock();
274 
275     /* Initialize our local list for the loop */
276     InitializeListHead(&LocalList);
277 
278     /* Start looping */
279     do
280     {
281         /* Setup notifications for the catalog entry */
282         ErrorCode = WsSetupCatalogProtection(Catalog->CatalogKey,
283                                              CatalogEvent,
284                                              &UniqueId);
285         if (ErrorCode != ERROR_SUCCESS) break;
286 
287         /* Check if we've changed till now */
288         if (UniqueId == Catalog->UniqueId)
289         {
290             /* We haven't, so return */
291             ErrorCode = ERROR_SUCCESS;
292             break;
293         }
294 
295         /* Now Open the Entries */
296         ErrorCode = RegOpenKeyEx(Catalog->CatalogKey,
297                                  "Catalog_Entries",
298                                  0,
299                                  MAXIMUM_ALLOWED,
300                                  &EntriesKey);
301         if (ErrorCode != ERROR_SUCCESS)
302         {
303             /* Critical failure */
304             ErrorCode = WSASYSCALLFAILURE;
305             break;
306         }
307 
308         /* Get the next entry */
309         ErrorCode = RegQueryValueEx(Catalog->CatalogKey,
310                                     "Next_Catalog_Entry_ID",
311                                     0,
312                                     &RegType,
313                                     (LPBYTE)&NextCatalogEntry,
314                                     &RegSize);
315         if (ErrorCode != ERROR_SUCCESS)
316         {
317             /* Critical failure */
318             ErrorCode = WSASYSCALLFAILURE;
319             break;
320         }
321 
322         /* Find out how many there are */
323         ErrorCode = RegQueryValueEx(Catalog->CatalogKey,
324                                     "Num_Catalog_Entries",
325                                     0,
326                                     &RegType,
327                                     (LPBYTE)&CatalogEntries,
328                                     &RegSize);
329         if (ErrorCode != ERROR_SUCCESS)
330         {
331             /* Critical failure */
332             ErrorCode = WSASYSCALLFAILURE;
333             break;
334         }
335 
336         /* Initialize them all */
337         for (i = 1; i <= CatalogEntries; i++)
338         {
339             /* Allocate a Catalog Entry Structure */
340             CatalogEntry = WsTcEntryAllocate();
341             if (!CatalogEntry)
342             {
343                 /* Not enough memory, fail */
344                 ErrorCode = WSA_NOT_ENOUGH_MEMORY;
345                 break;
346             }
347 
348             /* Initialize it from the Registry Key */
349             ErrorCode = WsTcEntryInitializeFromRegistry(CatalogEntry,
350                                                         EntriesKey,
351                                                         i);
352             if (ErrorCode != ERROR_SUCCESS)
353             {
354                 /* We failed to get it, dereference the entry and leave */
355                 WsTcEntryDereference(CatalogEntry);
356                 break;
357             }
358 
359             /* Insert it to our List */
360             InsertTailList(&LocalList, &CatalogEntry->CatalogLink);
361         }
362 
363         /* Close the catalog key */
364         RegCloseKey(EntriesKey);
365 
366         /* Check if we changed during our read and if we have success */
367         NewChangesMade = WsCheckCatalogState(CatalogEvent);
368         if (!NewChangesMade && ErrorCode == ERROR_SUCCESS)
369         {
370             /* All is good, update the protocol list */
371             WsTcUpdateProtocolList(Catalog, &LocalList);
372 
373             /* Update and return */
374             Catalog->UniqueId = UniqueId;
375             Catalog->NextId = NextCatalogEntry;
376             break;
377         }
378 
379         /* We failed and/or catalog data changed, free what we did till now */
380         while (!IsListEmpty(&LocalList))
381         {
382             /* Get the LP Catalog Item */
383             Entry = RemoveHeadList(&LocalList);
384             CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
385 
386             /* Dereference it */
387             WsTcEntryDereference(CatalogEntry);
388         }
389     } while (NewChangesMade);
390 
391     /* Release the lock */
392     WsTcUnlock();
393 
394     /* Close the event, if any was created by us */
395     if (LocalEvent) CloseHandle(CatalogEvent);
396 
397     /* All Done */
398     return ErrorCode;
399 }
400 
401 DWORD
402 WSAAPI
403 WsTcGetEntryFromAf(IN PTCATALOG Catalog,
404                    IN INT AddressFamily,
405                    IN PTCATALOG_ENTRY *CatalogEntry)
406 {
407     INT ErrorCode = WSAEINVAL;
408     PLIST_ENTRY NextEntry;
409     PTCATALOG_ENTRY Entry;
410 
411     /* Assume failure */
412     *CatalogEntry = NULL;
413 
414     /* Lock the catalog */
415     WsTcLock();
416 
417     /* Match the Id with all the entries in the List */
418     NextEntry = Catalog->ProtocolList.Flink;
419     while (NextEntry != &Catalog->ProtocolList)
420     {
421         /* Get the Current Entry */
422         Entry = CONTAINING_RECORD(NextEntry, TCATALOG_ENTRY, CatalogLink);
423         NextEntry = NextEntry->Flink;
424 
425         /* Check if this is the Catalog Entry ID we want */
426         if (Entry->ProtocolInfo.iAddressFamily == AddressFamily)
427         {
428             /* Check if it doesn't already have a provider */
429             if (!Entry->Provider)
430             {
431                 /* Match, load the Provider */
432                 ErrorCode = WsTcLoadProvider(Catalog, Entry);
433 
434                 /* Make sure this didn't fail */
435                 if (ErrorCode != ERROR_SUCCESS) break;
436             }
437 
438             /* Reference the entry and return it */
439             InterlockedIncrement(&Entry->RefCount);
440             *CatalogEntry = Entry;
441             ErrorCode = ERROR_SUCCESS;
442             break;
443         }
444     }
445 
446     /* Release the catalog */
447     WsTcUnlock();
448 
449     /* Return */
450     return ErrorCode;
451 }
452 
453 DWORD
454 WSAAPI
455 WsTcGetEntryFromCatalogEntryId(IN PTCATALOG Catalog,
456                                IN DWORD CatalogEntryId,
457                                IN PTCATALOG_ENTRY *CatalogEntry)
458 {
459     INT ErrorCode = WSAEINVAL;
460     PLIST_ENTRY NextEntry;
461     PTCATALOG_ENTRY Entry;
462 
463     /* Lock the catalog */
464     WsTcLock();
465 
466     /* Match the Id with all the entries in the List */
467     NextEntry = Catalog->ProtocolList.Flink;
468     while (NextEntry != &Catalog->ProtocolList)
469     {
470         /* Get the Current Entry */
471         Entry = CONTAINING_RECORD(NextEntry, TCATALOG_ENTRY, CatalogLink);
472         NextEntry = NextEntry->Flink;
473 
474         /* Check if this is the Catalog Entry ID we want */
475         if (Entry->ProtocolInfo.dwCatalogEntryId == CatalogEntryId)
476         {
477             /* Check if it doesn't already have a provider */
478             if (!Entry->Provider)
479             {
480                 /* Match, load the Provider */
481                 WsTcLoadProvider(Catalog, Entry);
482             }
483 
484             /* Reference the entry and return it */
485             InterlockedIncrement(&Entry->RefCount);
486             *CatalogEntry = Entry;
487             ErrorCode = ERROR_SUCCESS;
488             break;
489         }
490     }
491 
492     /* Release the catalog */
493     WsTcUnlock();
494 
495     /* Return */
496     return ErrorCode;
497 }
498 
499 DWORD
500 WSAAPI
501 WsTcGetEntryFromTriplet(IN PTCATALOG Catalog,
502                         IN INT af,
503                         IN INT type,
504                         IN INT protocol,
505                         IN DWORD StartId,
506                         IN PTCATALOG_ENTRY *CatalogEntry)
507 {
508     INT ErrorCode = WSAEINVAL;
509     PLIST_ENTRY NextEntry;
510     PTCATALOG_ENTRY Entry;
511     DPRINT("WsTcGetEntryFromTriplet: %lx, %lx, %lx, %lx\n", af, type, protocol, StartId);
512 
513     /* Assume failure */
514     *CatalogEntry = NULL;
515 
516     /* Lock the catalog */
517     WsTcLock();
518 
519     NextEntry = Catalog->ProtocolList.Flink;
520 
521     /* Check if we are starting past 0 */
522     if (StartId)
523     {
524         /* Loop the list */
525         while (NextEntry != &Catalog->ProtocolList)
526         {
527             /* Get the Current Entry */
528             Entry = CONTAINING_RECORD(NextEntry, TCATALOG_ENTRY, CatalogLink);
529             NextEntry = NextEntry->Flink;
530 
531             /* Check if this is the ID where we are starting */
532             if (Entry->ProtocolInfo.dwCatalogEntryId == StartId) break;
533         }
534     }
535 
536     /* Match the Id with all the entries in the List */
537     while (NextEntry != &Catalog->ProtocolList)
538     {
539         /* Get the Current Entry */
540         Entry = CONTAINING_RECORD(NextEntry, TCATALOG_ENTRY, CatalogLink);
541         NextEntry = NextEntry->Flink;
542 
543         /* Check if Address Family Matches or if it's wildcard */
544         if ((Entry->ProtocolInfo.iAddressFamily == af) || (af == AF_UNSPEC))
545         {
546             /* Check if Socket Type Matches or if it's wildcard */
547             if ((Entry->ProtocolInfo.iSocketType == type) || (type == 0))
548             {
549                 /* Check if Protocol is In Range or if it's wildcard */
550                 if (((Entry->ProtocolInfo.iProtocol <= protocol) &&
551                     ((Entry->ProtocolInfo.iProtocol +
552                       Entry->ProtocolInfo.iProtocolMaxOffset) >= protocol)) ||
553                     (protocol == 0))
554                 {
555                     /* Check if it doesn't already have a provider */
556                     if (!Entry->Provider)
557                     {
558                         /* Match, load the Provider */
559                         ErrorCode = WsTcLoadProvider(Catalog, Entry);
560 
561                         /* Make sure this didn't fail */
562                         if (ErrorCode != ERROR_SUCCESS) break;
563                     }
564 
565                     /* Reference the entry and return it */
566                     InterlockedIncrement(&Entry->RefCount);
567                     *CatalogEntry = Entry;
568                     ErrorCode = ERROR_SUCCESS;
569                     break;
570                 }
571                 else
572                 {
573                     ErrorCode = WSAEPROTONOSUPPORT;
574                 }
575             }
576             else
577             {
578                 ErrorCode = WSAESOCKTNOSUPPORT;
579             }
580         }
581         else
582         {
583             ErrorCode = WSAEAFNOSUPPORT;
584         }
585     }
586 
587     /* Release the catalog */
588     WsTcUnlock();
589 
590     /* Return */
591     return ErrorCode;
592 }
593 
594 PTPROVIDER
595 WSAAPI
596 WsTcFindProvider(IN PTCATALOG Catalog,
597                  IN LPGUID ProviderId)
598 {
599     PTPROVIDER Provider;
600     PLIST_ENTRY Entry;
601     PTCATALOG_ENTRY CatalogEntry;
602 
603     /* Loop the provider list */
604     Entry = Catalog->ProtocolList.Flink;
605     while (Entry != &Catalog->ProtocolList)
606     {
607         /* Get the entry */
608         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
609 
610         /* Move to the next one, get the provider */
611         Entry = Entry->Flink;
612         Provider = CatalogEntry->Provider;
613 
614         /* Check for a match */
615         if (Provider &&
616             IsEqualGUID(&CatalogEntry->ProtocolInfo.ProviderId, ProviderId))
617         {
618             /* Found a match */
619             return Provider;
620         }
621     }
622 
623     /* No match here */
624     return NULL;
625 }
626 
627 DWORD
628 WSAAPI
629 WsTcLoadProvider(IN PTCATALOG Catalog,
630                  IN PTCATALOG_ENTRY CatalogEntry)
631 {
632     INT ErrorCode = ERROR_SUCCESS;
633     PTPROVIDER Provider;
634     DPRINT("WsTcLoadProvider: %p, %p\n", Catalog, CatalogEntry);
635 
636     /* Lock the catalog */
637     WsTcLock();
638 
639     /* Check if we have a provider already */
640     if (!CatalogEntry->Provider)
641     {
642         /* Try to find another instance */
643         Provider = WsTcFindProvider(Catalog,
644                                     &CatalogEntry->ProtocolInfo.ProviderId);
645 
646         /* Check if we found one now */
647         if (Provider)
648         {
649             /* Set this one as the provider */
650             WsTcEntrySetProvider(CatalogEntry, Provider);
651             ErrorCode = ERROR_SUCCESS;
652         }
653         else
654         {
655             /* Nothing found, Allocate a provider */
656             if ((Provider = WsTpAllocate()))
657             {
658                 /* Initialize it */
659                 ErrorCode = WsTpInitialize(Provider,
660                                            CatalogEntry->DllPath,
661                                            &CatalogEntry->ProtocolInfo);
662 
663                 /* Ensure success */
664                 if (ErrorCode == ERROR_SUCCESS)
665                 {
666                     /* Set the provider */
667                     WsTcEntrySetProvider(CatalogEntry, Provider);
668                 }
669 
670                 /* Dereference it */
671                 WsTpDereference(Provider);
672             }
673             else
674             {
675                 /* No memory */
676                 ErrorCode = WSA_NOT_ENOUGH_MEMORY;
677             }
678         }
679     }
680 
681     /* Release the lock */
682     WsTcUnlock();
683     return ErrorCode;
684 }
685 
686 VOID
687 WSAAPI
688 WsTcUpdateProtocolList(IN PTCATALOG Catalog,
689                        IN PLIST_ENTRY List)
690 {
691     LIST_ENTRY TempList;
692     PTCATALOG_ENTRY CatalogEntry, OldCatalogEntry;
693     PLIST_ENTRY Entry;
694 
695     /* First move from our list to the old one */
696     InsertHeadList(&Catalog->ProtocolList, &TempList);
697     RemoveEntryList(&Catalog->ProtocolList);
698     InitializeListHead(&Catalog->ProtocolList);
699 
700     /* Loop every item in the list */
701     while (!IsListEmpty(List))
702     {
703         /* Get the catalog entry */
704         Entry = RemoveHeadList(List);
705         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
706 
707         /* Check if this item is already in our list */
708         Entry = TempList.Flink;
709         while (Entry != &TempList)
710         {
711             /* Get the catalog entry */
712             OldCatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
713             Entry = Entry->Flink;
714 
715             /* Check if they match */
716             if (CatalogEntry->ProtocolInfo.dwCatalogEntryId ==
717                 OldCatalogEntry->ProtocolInfo.dwCatalogEntryId)
718             {
719                 /* We have a match, use the old item instead */
720                 WsTcEntryDereference(CatalogEntry);
721                 CatalogEntry = OldCatalogEntry;
722                 RemoveEntryList(&CatalogEntry->CatalogLink);
723 
724                 /* Decrease the number of protocols we have */
725                 Catalog->ItemCount--;
726                 break;
727             }
728         }
729 
730         /* Add this item */
731         InsertTailList(&Catalog->ProtocolList, &CatalogEntry->CatalogLink);
732         Catalog->ItemCount++;
733     }
734 
735     /* If there's anything left in the temporary list */
736     while (!IsListEmpty(&TempList))
737     {
738         /* Get the entry */
739         Entry = RemoveHeadList(&TempList);
740         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
741 
742         /* Remove it */
743         Catalog->ItemCount--;
744         WsTcEntryDereference(CatalogEntry);
745     }
746 }
747 
748 VOID
749 WSAAPI
750 WsTcEnumerateCatalogItems(IN PTCATALOG Catalog,
751                           IN PTCATALOG_ENUMERATE_PROC Callback,
752                           IN PVOID Context)
753 {
754     PLIST_ENTRY Entry;
755     PTCATALOG_ENTRY CatalogEntry;
756     BOOL GoOn = TRUE;
757 
758     /* Lock the catalog */
759     WsTcLock();
760 
761     /* Loop the entries */
762     Entry = Catalog->ProtocolList.Flink;
763     while (GoOn && (Entry != &Catalog->ProtocolList))
764     {
765         /* Get the entry */
766         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
767 
768         /* Move to the next one and call the callback */
769         Entry = Entry->Flink;
770         GoOn = Callback(Context, CatalogEntry);
771     }
772 
773     /* Release lock */
774     WsTcUnlock();
775 }
776 
777 DWORD
778 WSAAPI
779 WsTcFindIfsProviderForSocket(IN PTCATALOG Catalog,
780                              IN SOCKET Handle)
781 {
782     PTPROVIDER Provider;
783     IN SOCKET NewHandle;
784     INT Error;
785     INT OptionLength;
786     PLIST_ENTRY Entry;
787     WSAPROTOCOL_INFOW ProtocolInfo;
788     DWORD UniqueId;
789     INT ErrorCode;
790     PTCATALOG_ENTRY CatalogEntry;
791 
792     /* Get the catalog lock */
793     WsTcLock();
794 
795     /* Loop as long as the catalog changes */
796 CatalogChanged:
797 
798     /* Loop every provider */
799     Entry = Catalog->ProtocolList.Flink;
800     while (Entry != &Catalog->ProtocolList)
801     {
802         /* Get the catalog entry */
803         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
804 
805         /* Move to the next entry */
806         Entry = Entry->Flink;
807 
808         /* Skip it if it doesn't support IFS */
809         if (!(CatalogEntry->ProtocolInfo.dwServiceFlags1 & XP1_IFS_HANDLES)) continue;
810 
811         /* Check if we need to load it */
812         if (!(Provider = CatalogEntry->Provider))
813         {
814             /* Load it */
815             ErrorCode = WsTcLoadProvider(Catalog, CatalogEntry);
816 
817             /* Skip it if we failed to load it */
818             if (ErrorCode != ERROR_SUCCESS) continue;
819 
820             /* Get the provider again */
821             Provider = CatalogEntry->Provider;
822         }
823 
824         /* Reference the entry and get our unique id */
825         InterlockedIncrement(&CatalogEntry->RefCount);
826         UniqueId = Catalog->UniqueId;
827 
828         /* Release the lock now */
829         WsTcUnlock();
830 
831         /* Get the catalog entry ID */
832         OptionLength = sizeof(ProtocolInfo);
833         ErrorCode = Provider->Service.lpWSPGetSockOpt(Handle,
834                                                       SOL_SOCKET,
835                                                       SO_PROTOCOL_INFOW,
836                                                       (PCHAR)&ProtocolInfo,
837                                                       &OptionLength,
838                                                       &Error);
839 
840         /* Dereference the entry and check the result */
841         WsTcEntryDereference(CatalogEntry);
842         if (ErrorCode != ERROR_SUCCESS)
843         {
844             /* Lock and make sure this provider is still valid */
845             WsTcLock();
846             if (UniqueId == Catalog->UniqueId) continue;
847 
848             /* It changed! We need to start over */
849             goto CatalogChanged;
850         }
851 
852         /* Now get the IFS handle */
853         NewHandle = WPUModifyIFSHandle(ProtocolInfo.dwCatalogEntryId,
854                                        Handle,
855                                        &Error);
856 
857         /* Check if the socket is invalid */
858         if (NewHandle == INVALID_SOCKET) return WSAENOTSOCK;
859 
860         /* We succeeded, get out of here */
861         return ERROR_SUCCESS;
862     }
863 
864     /* Unrecognized socket if we get here: note, we still have the lock */
865     WsTcUnlock();
866     return WSAENOTSOCK;
867 }
868 
869 VOID
870 WSAAPI
871 WsTcRemoveCatalogItem(IN PTCATALOG Catalog,
872                       IN PTCATALOG_ENTRY Entry)
873 {
874     /* Remove the entry from the list */
875     RemoveEntryList(&Entry->CatalogLink);
876 
877     /* Decrease our count */
878     Catalog->ItemCount--;
879 }
880 
881 VOID
882 WSAAPI
883 WsTcDelete(IN PTCATALOG Catalog)
884 {
885     PLIST_ENTRY Entry;
886     PTCATALOG_ENTRY CatalogEntry;
887 
888     /* Check if we're initialized */
889     if (!Catalog->ProtocolList.Flink) return;
890 
891     /* Acquire lock */
892     WsTcLock();
893 
894     /* Loop every entry */
895     Entry = Catalog->ProtocolList.Flink;
896     while (Entry != &Catalog->ProtocolList)
897     {
898         /* Get this entry */
899         CatalogEntry = CONTAINING_RECORD(Entry, TCATALOG_ENTRY, CatalogLink);
900 
901         /* Remove it and dereference it */
902         WsTcRemoveCatalogItem(Catalog, CatalogEntry);
903         WsTcEntryDereference(CatalogEntry);
904 
905         /* Move to the next entry */
906         Entry = Catalog->ProtocolList.Flink;
907     }
908 
909     /* Check if the catalog key is opened */
910     if (Catalog->CatalogKey)
911     {
912         /* Close it */
913         RegCloseKey(Catalog->CatalogKey);
914         Catalog->CatalogKey = NULL;
915     }
916 
917     /* Release and delete the lock */
918     WsTcUnlock();
919     DeleteCriticalSection(&Catalog->Lock);
920 
921     /* Delete the object */
922     HeapFree(WsSockHeap, 0, Catalog);
923 }
924