2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
5 * PURPOSE: Transport Catalog Object
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
12 /* DATA **********************************************************************/
14 #define TCCATALOG_NAME "Protocol_Catalog9"
16 #define WsTcLock() EnterCriticalSection((LPCRITICAL_SECTION)&Catalog->Lock);
17 #define WsTcUnlock() LeaveCriticalSection((LPCRITICAL_SECTION)&Catalog->Lock);
19 /* FUNCTIONS *****************************************************************/
27 /* Allocate the object */
28 Catalog
= HeapAlloc(WsSockHeap
, HEAP_ZERO_MEMORY
, sizeof(*Catalog
));
36 WsTcOpen(IN PTCATALOG Catalog
,
40 DWORD CreateDisposition
;
41 HKEY CatalogKey
, NewKey
;
42 //DWORD CatalogEntries = 0;
43 DWORD RegType
= REG_DWORD
;
44 DWORD RegSize
= sizeof(DWORD
);
48 /* Initialize the catalog lock and namespace list */
49 InitializeCriticalSection((LPCRITICAL_SECTION
)&Catalog
->Lock
);
50 InitializeListHead(&Catalog
->ProtocolList
);
52 /* Open the Catalog Key */
53 ErrorCode
= RegOpenKeyEx(ParentKey
,
59 /* If we didn't find the key, create it */
60 if (ErrorCode
== ERROR_SUCCESS
)
62 /* Fake that we opened an existing key */
63 CreateDisposition
= REG_OPENED_EXISTING_KEY
;
65 else if (ErrorCode
== ERROR_FILE_NOT_FOUND
)
67 /* Create the Catalog Name */
68 ErrorCode
= RegCreateKeyEx(ParentKey
,
72 REG_OPTION_NON_VOLATILE
,
79 /* Fail if that didn't work */
80 if (ErrorCode
!= ERROR_SUCCESS
) return FALSE
;
82 /* Check if we had to create the key */
83 if (CreateDisposition
== REG_CREATED_NEW_KEY
)
85 /* Write the count of entries (0 now) */
86 ErrorCode
= RegSetValueEx(CatalogKey
,
87 "Num_Catalog_Entries",
92 if (ErrorCode
!= ERROR_SUCCESS
)
94 /* Close the key and fail */
95 RegCloseKey(CatalogKey
);
99 /* Write the first catalog entry ID */
101 ErrorCode
= RegSetValueEx(CatalogKey
,
102 "Next_Catalog_Entry_ID",
107 if (ErrorCode
!= ERROR_SUCCESS
)
109 /* Close the key and fail */
110 RegCloseKey(CatalogKey
);
114 /* Write the first catalog entry Uniqe ID */
116 ErrorCode
= RegSetValueEx(CatalogKey
,
122 if (ErrorCode
!= ERROR_SUCCESS
)
124 /* Close the key and fail */
125 RegCloseKey(CatalogKey
);
129 /* Create a key for this entry */
130 ErrorCode
= RegCreateKeyEx(CatalogKey
,
134 REG_OPTION_NON_VOLATILE
,
139 if (ErrorCode
!= ERROR_SUCCESS
)
141 /* Close the key and fail */
142 RegCloseKey(CatalogKey
);
146 /* Close the key since we don't need it */
151 /* Read the serial number */
152 ErrorCode
= RegQueryValueEx(CatalogKey
,
159 /* Check if it's missing for some reason */
160 if (ErrorCode
!= ERROR_SUCCESS
)
162 /* Write the first catalog entry Unique ID */
164 ErrorCode
= RegSetValueEx(CatalogKey
,
173 /* Set the Catalog Key */
174 Catalog
->CatalogKey
= CatalogKey
;
180 WsTcInitializeFromRegistry(IN PTCATALOG Catalog
,
182 IN HANDLE CatalogEvent
)
184 INT ErrorCode
= WSASYSCALLFAILURE
;
186 /* Open the catalog */
187 if (WsTcOpen(Catalog
, ParentKey
))
190 ErrorCode
= WsTcRefreshFromRegistry(Catalog
, CatalogEvent
);
193 /* Return the status */
199 WsTcRefreshFromRegistry(IN PTCATALOG Catalog
,
200 IN HANDLE CatalogEvent
)
203 BOOLEAN LocalEvent
= FALSE
;
204 LIST_ENTRY LocalList
;
207 DWORD CatalogEntries
;
208 PTCATALOG_ENTRY CatalogEntry
;
209 DWORD NextCatalogEntry
;
212 DWORD RegType
= REG_DWORD
;
213 DWORD RegSize
= sizeof(DWORD
);
216 /* Check if we got an event */
219 /* Create an event ourselves */
220 CatalogEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
221 if (!CatalogEvent
) return WSASYSCALLFAILURE
;
225 /* Lock the catalog */
228 /* Initialize our local list for the loop */
229 InitializeListHead(&LocalList
);
234 /* Setup notifications for the catalog entry */
235 ErrorCode
= WsSetupCatalogProtection(Catalog
->CatalogKey
,
238 if (ErrorCode
!= ERROR_SUCCESS
) break;
240 /* Check if we've changed till now */
241 if (UniqueId
== Catalog
->UniqueId
)
243 /* We haven't, so return */
244 ErrorCode
= ERROR_SUCCESS
;
248 /* Now Open the Entries */
249 ErrorCode
= RegOpenKeyEx(Catalog
->CatalogKey
,
254 if (ErrorCode
!= ERROR_SUCCESS
)
256 /* Critical failure */
257 ErrorCode
= WSASYSCALLFAILURE
;
261 /* Get the next entry */
262 ErrorCode
= RegQueryValueEx(Catalog
->CatalogKey
,
263 "Next_Catalog_Entry_ID",
266 (LPBYTE
)&NextCatalogEntry
,
268 if (ErrorCode
!= ERROR_SUCCESS
)
270 /* Critical failure */
271 ErrorCode
= WSASYSCALLFAILURE
;
275 /* Find out how many there are */
276 ErrorCode
= RegQueryValueEx(Catalog
->CatalogKey
,
277 "Num_Catalog_Entries",
280 (LPBYTE
)&CatalogEntries
,
282 if (ErrorCode
!= ERROR_SUCCESS
)
284 /* Critical failure */
285 ErrorCode
= WSASYSCALLFAILURE
;
289 /* Initialize them all */
290 for (i
= 1; i
<= CatalogEntries
; i
++)
292 /* Allocate a Catalog Entry Structure */
293 CatalogEntry
= WsTcEntryAllocate();
296 /* Not enough memory, fail */
297 ErrorCode
= WSA_NOT_ENOUGH_MEMORY
;
301 /* Initialize it from the Registry Key */
302 ErrorCode
= WsTcEntryInitializeFromRegistry(CatalogEntry
,
305 if (ErrorCode
!= ERROR_SUCCESS
)
307 /* We failed to get it, dereference the entry and leave */
308 WsTcEntryDereference(CatalogEntry
);
312 /* Insert it to our List */
313 InsertTailList(&LocalList
, &CatalogEntry
->CatalogLink
);
316 /* Close the catalog key */
317 RegCloseKey(EntriesKey
);
319 /* Check if we changed during our read and if we have success */
320 NewChangesMade
= WsCheckCatalogState(CatalogEvent
);
321 if (!NewChangesMade
&& ErrorCode
== ERROR_SUCCESS
)
323 /* All is good, update the protocol list */
324 WsTcUpdateProtocolList(Catalog
, &LocalList
);
326 /* Update and return */
327 Catalog
->UniqueId
= UniqueId
;
328 Catalog
->NextId
= NextCatalogEntry
;
332 /* We failed and/or catalog data changed, free what we did till now */
333 while (!IsListEmpty(&LocalList
))
335 /* Get the LP Catalog Item */
336 Entry
= RemoveHeadList(&LocalList
);
337 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
340 WsTcEntryDereference(CatalogEntry
);
342 } while (NewChangesMade
);
344 /* Release the lock */
347 /* Close the event, if any was created by us */
348 if (LocalEvent
) CloseHandle(CatalogEvent
);
356 WsTcGetEntryFromAf(IN PTCATALOG Catalog
,
357 IN INT AddressFamily
,
358 IN PTCATALOG_ENTRY
*CatalogEntry
)
360 INT ErrorCode
= WSAEINVAL
;
361 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
362 PTCATALOG_ENTRY Entry
;
365 *CatalogEntry
= NULL
;
367 /* Lock the catalog */
370 /* Match the Id with all the entries in the List */
371 while (NextEntry
!= &Catalog
->ProtocolList
)
373 /* Get the Current Entry */
374 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
375 NextEntry
= NextEntry
->Flink
;
377 /* Check if this is the Catalog Entry ID we want */
378 if (Entry
->ProtocolInfo
.iAddressFamily
== AddressFamily
)
380 /* Check if it doesn't already have a provider */
381 if (!Entry
->Provider
)
383 /* Match, load the Provider */
384 ErrorCode
= WsTcLoadProvider(Catalog
, Entry
);
386 /* Make sure this didn't fail */
387 if (ErrorCode
!= ERROR_SUCCESS
) break;
390 /* Reference the entry and return it */
391 InterlockedIncrement(&Entry
->RefCount
);
392 *CatalogEntry
= Entry
;
393 ErrorCode
= ERROR_SUCCESS
;
398 /* Release the catalog */
407 WsTcGetEntryFromCatalogEntryId(IN PTCATALOG Catalog
,
408 IN DWORD CatalogEntryId
,
409 IN PTCATALOG_ENTRY
*CatalogEntry
)
411 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
412 PTCATALOG_ENTRY Entry
;
414 /* Lock the catalog */
417 /* Match the Id with all the entries in the List */
418 while (NextEntry
!= &Catalog
->ProtocolList
)
420 /* Get the Current Entry */
421 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
422 NextEntry
= NextEntry
->Flink
;
424 /* Check if this is the Catalog Entry ID we want */
425 if (Entry
->ProtocolInfo
.dwCatalogEntryId
== CatalogEntryId
)
427 /* Check if it doesn't already have a provider */
428 if (!Entry
->Provider
)
430 /* Match, load the Provider */
431 WsTcLoadProvider(Catalog
, Entry
);
434 /* Reference the entry and return it */
435 InterlockedIncrement(&Entry
->RefCount
);
436 *CatalogEntry
= Entry
;
441 /* Release the catalog */
445 return ERROR_SUCCESS
;
450 WsTcGetEntryFromTriplet(IN PTCATALOG Catalog
,
455 IN PTCATALOG_ENTRY
*CatalogEntry
)
457 INT ErrorCode
= WSAEINVAL
;
458 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
459 PTCATALOG_ENTRY Entry
;
462 *CatalogEntry
= NULL
;
464 /* Lock the catalog */
467 /* Check if we are starting past 0 */
471 while (NextEntry
!= &Catalog
->ProtocolList
)
473 /* Get the Current Entry */
474 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
475 NextEntry
= NextEntry
->Flink
;
477 /* Check if this is the ID where we are starting */
478 if (Entry
->ProtocolInfo
.dwCatalogEntryId
== StartId
) break;
482 /* Match the Id with all the entries in the List */
483 while (NextEntry
!= &Catalog
->ProtocolList
)
485 /* Get the Current Entry */
486 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
487 NextEntry
= NextEntry
->Flink
;
489 /* Check if Address Family Matches or if it's wildcard */
490 if ((Entry
->ProtocolInfo
.iAddressFamily
== af
) || (af
== AF_UNSPEC
))
492 /* Check if Socket Type Matches or if it's wildcard */
493 if ((Entry
->ProtocolInfo
.iSocketType
== type
) || (type
== 0))
495 /* Check if Protocol is In Range or if it's wildcard */
496 if (((Entry
->ProtocolInfo
.iProtocol
>= protocol
) &&
497 ((Entry
->ProtocolInfo
.iProtocol
+
498 Entry
->ProtocolInfo
.iProtocolMaxOffset
) <= protocol
)) ||
501 /* Check if it doesn't already have a provider */
502 if (!Entry
->Provider
)
504 /* Match, load the Provider */
505 ErrorCode
= WsTcLoadProvider(Catalog
, Entry
);
507 /* Make sure this didn't fail */
508 if (ErrorCode
!= ERROR_SUCCESS
) break;
511 /* Reference the entry and return it */
512 InterlockedIncrement(&Entry
->RefCount
);
513 *CatalogEntry
= Entry
;
514 ErrorCode
= ERROR_SUCCESS
;
519 ErrorCode
= WSAEPROTONOSUPPORT
;
524 ErrorCode
= WSAESOCKTNOSUPPORT
;
529 ErrorCode
= WSAEAFNOSUPPORT
;
533 /* Release the catalog */
542 WsTcFindProvider(IN PTCATALOG Catalog
,
543 IN LPGUID ProviderId
)
547 PTCATALOG_ENTRY CatalogEntry
;
549 /* Loop the provider list */
550 Entry
= Catalog
->ProtocolList
.Flink
;
551 while (Entry
!= &Catalog
->ProtocolList
)
554 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
556 /* Move to the next one, get the provider */
557 Entry
= Entry
->Flink
;
558 Provider
= CatalogEntry
->Provider
;
560 /* Check for a match */
562 !(memcmp(&CatalogEntry
->ProtocolInfo
.ProviderId
,
577 WsTcLoadProvider(IN PTCATALOG Catalog
,
578 IN PTCATALOG_ENTRY CatalogEntry
)
580 INT ErrorCode
= ERROR_SUCCESS
;
583 /* Lock the catalog */
586 /* Check if we have a provider already */
587 if (!CatalogEntry
->Provider
)
589 /* Try to find another instance */
590 Provider
= WsTcFindProvider(Catalog
,
591 &CatalogEntry
->ProtocolInfo
.ProviderId
);
593 /* Check if we found one now */
596 /* Set this one as the provider */
597 WsTcEntrySetProvider(CatalogEntry
, Provider
);
598 ErrorCode
= ERROR_SUCCESS
;
602 /* Nothing found, Allocate a provider */
603 if ((Provider
= WsTpAllocate()))
606 ErrorCode
= WsTpInitialize(Provider
,
607 CatalogEntry
->DllPath
,
608 &CatalogEntry
->ProtocolInfo
);
611 if (ErrorCode
== ERROR_SUCCESS
)
613 /* Set the provider */
614 WsTcEntrySetProvider(CatalogEntry
, Provider
);
618 WsTpDereference(Provider
);
623 ErrorCode
= WSA_NOT_ENOUGH_MEMORY
;
628 /* Release the lock */
635 WsTcUpdateProtocolList(IN PTCATALOG Catalog
,
639 PTCATALOG_ENTRY CatalogEntry
, OldCatalogEntry
;
642 /* First move from our list to the old one */
643 InsertHeadList(&Catalog
->ProtocolList
, &TempList
);
644 RemoveEntryList(&Catalog
->ProtocolList
);
645 InitializeListHead(&Catalog
->ProtocolList
);
647 /* Loop every item on the list */
648 while (!IsListEmpty(List
))
650 /* Get the catalog entry */
651 Entry
= RemoveHeadList(List
);
652 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
654 /* Check if this item is already on our list */
655 Entry
= TempList
.Flink
;
656 while (Entry
!= &TempList
)
658 /* Get the catalog entry */
659 OldCatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
660 Entry
= Entry
->Flink
;
662 /* Check if they match */
663 if (CatalogEntry
->ProtocolInfo
.dwCatalogEntryId
==
664 OldCatalogEntry
->ProtocolInfo
.dwCatalogEntryId
)
666 /* We have a match, use the old item instead */
667 WsTcEntryDereference(CatalogEntry
);
668 CatalogEntry
= OldCatalogEntry
;
669 RemoveEntryList(&CatalogEntry
->CatalogLink
);
671 /* Decrease the number of protocols we have */
672 Catalog
->ItemCount
--;
678 InsertTailList(&Catalog
->ProtocolList
, &CatalogEntry
->CatalogLink
);
679 Catalog
->ItemCount
++;
682 /* If there's anything left on the temporary list */
683 while (!IsListEmpty(&TempList
))
686 Entry
= RemoveHeadList(&TempList
);
687 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
690 Catalog
->ItemCount
--;
691 WsTcEntryDereference(CatalogEntry
);
697 WsTcEnumerateCatalogItems(IN PTCATALOG Catalog
,
698 IN PTCATALOG_ENUMERATE_PROC Callback
,
702 PTCATALOG_ENTRY CatalogEntry
;
705 /* Lock the catalog */
708 /* Loop the entries */
709 Entry
= Catalog
->ProtocolList
.Flink
;
710 while (GoOn
&& (Entry
!= &Catalog
->ProtocolList
))
713 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
715 /* Move to the next one and call the callback */
716 Entry
= Entry
->Flink
;
717 GoOn
= Callback(Context
, CatalogEntry
);
726 WsTcFindIfsProviderForSocket(IN PTCATALOG Catalog
,
734 WSAPROTOCOL_INFOW ProtocolInfo
;
737 PTCATALOG_ENTRY CatalogEntry
;
739 /* Get the catalog lock */
742 /* Loop as long as the catalog changes */
745 /* Loop every provider */
746 Entry
= Catalog
->ProtocolList
.Flink
;
747 while (Entry
!= &Catalog
->ProtocolList
)
749 /* Get the catalog entry */
750 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
752 /* Move to the next entry */
753 Entry
= Entry
->Flink
;
755 /* Skip it if it doesn't support IFS */
756 if (!(CatalogEntry
->ProtocolInfo
.dwServiceFlags1
& XP1_IFS_HANDLES
)) continue;
758 /* Check if we need to load it */
759 if (!(Provider
= CatalogEntry
->Provider
))
762 ErrorCode
= WsTcLoadProvider(Catalog
, CatalogEntry
);
764 /* Skip it if we failed to load it */
765 if (ErrorCode
!= ERROR_SUCCESS
) continue;
767 /* Get the provider again */
768 Provider
= CatalogEntry
->Provider
;
771 /* Reference the entry and get our unique id */
772 InterlockedIncrement(&CatalogEntry
->RefCount
);
773 UniqueId
= Catalog
->UniqueId
;
775 /* Release the lock now */
778 /* Get the catalog entry ID */
779 OptionLength
= sizeof(ProtocolInfo
);
780 ErrorCode
= Provider
->Service
.lpWSPGetSockOpt(Handle
,
783 (PCHAR
)&ProtocolInfo
,
784 (LPINT
)&OptionLength
,
787 /* Dereference the entry and check the result */
788 WsTcEntryDereference(CatalogEntry
);
789 if (ErrorCode
!= ERROR_SUCCESS
)
791 /* Lock and make sure this provider is still valid */
793 if (UniqueId
== Catalog
->UniqueId
) continue;
795 /* It changed! We need to start over */
799 /* Now get the IFS handle */
800 NewHandle
= WPUModifyIFSHandle(ProtocolInfo
.dwCatalogEntryId
,
804 /* Check if the socket is invalid */
805 if (NewHandle
== INVALID_SOCKET
) return WSAENOTSOCK
;
807 /* We suceeded, get out of here */
808 return ERROR_SUCCESS
;
811 /* Unrecognized socket if we get here: note, we still have the lock */
818 WsTcRemoveCatalogItem(IN PTCATALOG Catalog
,
819 IN PTCATALOG_ENTRY Entry
)
821 /* Remove the entry from the list */
822 RemoveEntryList(&Entry
->CatalogLink
);
824 /* Decrease our count */
825 Catalog
->ItemCount
--;
830 WsTcDelete(IN PTCATALOG Catalog
)
833 PTCATALOG_ENTRY CatalogEntry
;
835 /* Check if we're initialized */
836 if (!Catalog
->ProtocolList
.Flink
) return;
841 /* Loop every entry */
842 Entry
= Catalog
->ProtocolList
.Flink
;
843 while (Entry
!= &Catalog
->ProtocolList
)
846 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
849 WsTcRemoveCatalogItem(Catalog
, CatalogEntry
);
852 WsTcEntryDereference(CatalogEntry
);
854 /* Move to the next entry */
855 Entry
= Catalog
->ProtocolList
.Flink
;
858 /* Check if the catalog key is opened */
859 if (Catalog
->CatalogKey
)
862 RegCloseKey(Catalog
->CatalogKey
);
863 Catalog
->CatalogKey
= NULL
;
866 /* Release and delete the lock */
868 DeleteCriticalSection((LPCRITICAL_SECTION
)&Catalog
->Lock
);
870 /* Delete the object */
871 HeapFree(WsSockHeap
, 0, Catalog
);