2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dll/win32/ws2_32_new/src/dcatalog.c
5 * PURPOSE: Transport Catalog Object
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
16 /* DATA **********************************************************************/
18 #define WsTcLock() EnterCriticalSection((LPCRITICAL_SECTION)&Catalog->Lock);
19 #define WsTcUnlock() LeaveCriticalSection((LPCRITICAL_SECTION)&Catalog->Lock);
21 /* FUNCTIONS *****************************************************************/
29 /* Allocate the object */
30 Catalog
= HeapAlloc(WsSockHeap
, HEAP_ZERO_MEMORY
, sizeof(*Catalog
));
38 WsTcOpen(IN PTCATALOG Catalog
,
42 DWORD CreateDisposition
;
43 HKEY CatalogKey
, NewKey
;
44 //DWORD CatalogEntries = 0;
45 DWORD RegType
= REG_DWORD
;
46 DWORD RegSize
= sizeof(DWORD
);
51 /* Initialize the catalog lock and namespace list */
52 InitializeCriticalSection((LPCRITICAL_SECTION
)&Catalog
->Lock
);
53 InitializeListHead(&Catalog
->ProtocolList
);
55 /* Read the catalog name */
56 ErrorCode
= RegQueryValueEx(ParentKey
,
57 "Current_Protocol_Catalog",
63 CatalogKeyName
= HeapAlloc(WsSockHeap
, 0, RegSize
);
65 /* Read the catalog name */
66 ErrorCode
= RegQueryValueEx(ParentKey
,
67 "Current_Protocol_Catalog",
70 (LPBYTE
)CatalogKeyName
,
73 /* Open the Catalog Key */
74 ErrorCode
= RegOpenKeyEx(ParentKey
,
80 /* If we didn't find the key, create it */
81 if (ErrorCode
== ERROR_SUCCESS
)
83 /* Fake that we opened an existing key */
84 CreateDisposition
= REG_OPENED_EXISTING_KEY
;
86 else if (ErrorCode
== ERROR_FILE_NOT_FOUND
)
88 /* Create the Catalog Name */
89 ErrorCode
= RegCreateKeyEx(ParentKey
,
93 REG_OPTION_NON_VOLATILE
,
100 HeapFree(WsSockHeap
, 0, CatalogKeyName
);
102 RegSize
= sizeof(DWORD
);
104 /* Fail if that didn't work */
105 if (ErrorCode
!= ERROR_SUCCESS
) return FALSE
;
107 /* Check if we had to create the key */
108 if (CreateDisposition
== REG_CREATED_NEW_KEY
)
110 /* Write the count of entries (0 now) */
111 ErrorCode
= RegSetValueEx(CatalogKey
,
112 "Num_Catalog_Entries",
117 if (ErrorCode
!= ERROR_SUCCESS
)
119 /* Close the key and fail */
120 RegCloseKey(CatalogKey
);
124 /* Write the first catalog entry ID */
126 ErrorCode
= RegSetValueEx(CatalogKey
,
127 "Next_Catalog_Entry_ID",
132 if (ErrorCode
!= ERROR_SUCCESS
)
134 /* Close the key and fail */
135 RegCloseKey(CatalogKey
);
139 /* Write the first catalog entry Uniqe ID */
141 ErrorCode
= RegSetValueEx(CatalogKey
,
147 if (ErrorCode
!= ERROR_SUCCESS
)
149 /* Close the key and fail */
150 RegCloseKey(CatalogKey
);
154 /* Create a key for this entry */
155 ErrorCode
= RegCreateKeyEx(CatalogKey
,
159 REG_OPTION_NON_VOLATILE
,
164 if (ErrorCode
!= ERROR_SUCCESS
)
166 /* Close the key and fail */
167 RegCloseKey(CatalogKey
);
171 /* Close the key since we don't need it */
176 RegSize
= sizeof(DWORD
);
177 /* Read the serial number */
178 ErrorCode
= RegQueryValueEx(CatalogKey
,
185 /* Check if it's missing for some reason */
186 if (ErrorCode
!= ERROR_SUCCESS
)
188 /* Write the first catalog entry Unique ID */
190 ErrorCode
= RegSetValueEx(CatalogKey
,
199 /* Set the Catalog Key */
200 Catalog
->CatalogKey
= CatalogKey
;
206 WsTcInitializeFromRegistry(IN PTCATALOG Catalog
,
208 IN HANDLE CatalogEvent
)
210 INT ErrorCode
= WSASYSCALLFAILURE
;
212 /* Open the catalog */
213 if (WsTcOpen(Catalog
, ParentKey
))
216 ErrorCode
= WsTcRefreshFromRegistry(Catalog
, CatalogEvent
);
219 /* Return the status */
225 WsTcRefreshFromRegistry(IN PTCATALOG Catalog
,
226 IN HANDLE CatalogEvent
)
229 BOOLEAN LocalEvent
= FALSE
;
230 LIST_ENTRY LocalList
;
233 DWORD CatalogEntries
;
234 PTCATALOG_ENTRY CatalogEntry
;
235 DWORD NextCatalogEntry
;
238 DWORD RegType
= REG_DWORD
;
239 DWORD RegSize
= sizeof(DWORD
);
242 /* Check if we got an event */
245 /* Create an event ourselves */
246 CatalogEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
247 if (!CatalogEvent
) return WSASYSCALLFAILURE
;
251 /* Lock the catalog */
254 /* Initialize our local list for the loop */
255 InitializeListHead(&LocalList
);
260 /* Setup notifications for the catalog entry */
261 ErrorCode
= WsSetupCatalogProtection(Catalog
->CatalogKey
,
264 if (ErrorCode
!= ERROR_SUCCESS
) break;
266 /* Check if we've changed till now */
267 if (UniqueId
== Catalog
->UniqueId
)
269 /* We haven't, so return */
270 ErrorCode
= ERROR_SUCCESS
;
274 /* Now Open the Entries */
275 ErrorCode
= RegOpenKeyEx(Catalog
->CatalogKey
,
280 if (ErrorCode
!= ERROR_SUCCESS
)
282 /* Critical failure */
283 ErrorCode
= WSASYSCALLFAILURE
;
287 /* Get the next entry */
288 ErrorCode
= RegQueryValueEx(Catalog
->CatalogKey
,
289 "Next_Catalog_Entry_ID",
292 (LPBYTE
)&NextCatalogEntry
,
294 if (ErrorCode
!= ERROR_SUCCESS
)
296 /* Critical failure */
297 ErrorCode
= WSASYSCALLFAILURE
;
301 /* Find out how many there are */
302 ErrorCode
= RegQueryValueEx(Catalog
->CatalogKey
,
303 "Num_Catalog_Entries",
306 (LPBYTE
)&CatalogEntries
,
308 if (ErrorCode
!= ERROR_SUCCESS
)
310 /* Critical failure */
311 ErrorCode
= WSASYSCALLFAILURE
;
315 /* Initialize them all */
316 for (i
= 1; i
<= CatalogEntries
; i
++)
318 /* Allocate a Catalog Entry Structure */
319 CatalogEntry
= WsTcEntryAllocate();
322 /* Not enough memory, fail */
323 ErrorCode
= WSA_NOT_ENOUGH_MEMORY
;
327 /* Initialize it from the Registry Key */
328 ErrorCode
= WsTcEntryInitializeFromRegistry(CatalogEntry
,
331 if (ErrorCode
!= ERROR_SUCCESS
)
333 /* We failed to get it, dereference the entry and leave */
334 WsTcEntryDereference(CatalogEntry
);
338 /* Insert it to our List */
339 InsertTailList(&LocalList
, &CatalogEntry
->CatalogLink
);
342 /* Close the catalog key */
343 RegCloseKey(EntriesKey
);
345 /* Check if we changed during our read and if we have success */
346 NewChangesMade
= WsCheckCatalogState(CatalogEvent
);
347 if (!NewChangesMade
&& ErrorCode
== ERROR_SUCCESS
)
349 /* All is good, update the protocol list */
350 WsTcUpdateProtocolList(Catalog
, &LocalList
);
352 /* Update and return */
353 Catalog
->UniqueId
= UniqueId
;
354 Catalog
->NextId
= NextCatalogEntry
;
358 /* We failed and/or catalog data changed, free what we did till now */
359 while (!IsListEmpty(&LocalList
))
361 /* Get the LP Catalog Item */
362 Entry
= RemoveHeadList(&LocalList
);
363 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
366 WsTcEntryDereference(CatalogEntry
);
368 } while (NewChangesMade
);
370 /* Release the lock */
373 /* Close the event, if any was created by us */
374 if (LocalEvent
) CloseHandle(CatalogEvent
);
382 WsTcGetEntryFromAf(IN PTCATALOG Catalog
,
383 IN INT AddressFamily
,
384 IN PTCATALOG_ENTRY
*CatalogEntry
)
386 INT ErrorCode
= WSAEINVAL
;
387 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
388 PTCATALOG_ENTRY Entry
;
391 *CatalogEntry
= NULL
;
393 /* Lock the catalog */
396 /* Match the Id with all the entries in the List */
397 while (NextEntry
!= &Catalog
->ProtocolList
)
399 /* Get the Current Entry */
400 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
401 NextEntry
= NextEntry
->Flink
;
403 /* Check if this is the Catalog Entry ID we want */
404 if (Entry
->ProtocolInfo
.iAddressFamily
== AddressFamily
)
406 /* Check if it doesn't already have a provider */
407 if (!Entry
->Provider
)
409 /* Match, load the Provider */
410 ErrorCode
= WsTcLoadProvider(Catalog
, Entry
);
412 /* Make sure this didn't fail */
413 if (ErrorCode
!= ERROR_SUCCESS
) break;
416 /* Reference the entry and return it */
417 InterlockedIncrement(&Entry
->RefCount
);
418 *CatalogEntry
= Entry
;
419 ErrorCode
= ERROR_SUCCESS
;
424 /* Release the catalog */
433 WsTcGetEntryFromCatalogEntryId(IN PTCATALOG Catalog
,
434 IN DWORD CatalogEntryId
,
435 IN PTCATALOG_ENTRY
*CatalogEntry
)
437 INT ErrorCode
= WSAEINVAL
;
438 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
439 PTCATALOG_ENTRY Entry
;
441 /* Lock the catalog */
444 /* Match the Id with all the entries in the List */
445 while (NextEntry
!= &Catalog
->ProtocolList
)
447 /* Get the Current Entry */
448 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
449 NextEntry
= NextEntry
->Flink
;
451 /* Check if this is the Catalog Entry ID we want */
452 if (Entry
->ProtocolInfo
.dwCatalogEntryId
== CatalogEntryId
)
454 /* Check if it doesn't already have a provider */
455 if (!Entry
->Provider
)
457 /* Match, load the Provider */
458 WsTcLoadProvider(Catalog
, Entry
);
461 /* Reference the entry and return it */
462 InterlockedIncrement(&Entry
->RefCount
);
463 *CatalogEntry
= Entry
;
464 ErrorCode
= ERROR_SUCCESS
;
469 /* Release the catalog */
478 WsTcGetEntryFromTriplet(IN PTCATALOG Catalog
,
483 IN PTCATALOG_ENTRY
*CatalogEntry
)
485 INT ErrorCode
= WSAEINVAL
;
486 PLIST_ENTRY NextEntry
= Catalog
->ProtocolList
.Flink
;
487 PTCATALOG_ENTRY Entry
;
488 DPRINT("WsTcGetEntryFromTriplet: %lx, %lx, %lx, %lx\n", af
, type
, protocol
, StartId
);
491 *CatalogEntry
= NULL
;
493 /* Params can't be all wildcards */
494 if (af
== AF_UNSPEC
&& type
== 0 && protocol
== 0)
497 /* FIXME: AF_NETDES should be AF_MAX */
498 if (af
< AF_UNSPEC
|| af
> AF_NETDES
)
501 if (type
< 0 && type
> SOCK_SEQPACKET
)
504 if (protocol
< 0 && protocol
> IPPROTO_MAX
)
507 /* Lock the catalog */
510 /* Check if we are starting past 0 */
514 while (NextEntry
!= &Catalog
->ProtocolList
)
516 /* Get the Current Entry */
517 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
518 NextEntry
= NextEntry
->Flink
;
520 /* Check if this is the ID where we are starting */
521 if (Entry
->ProtocolInfo
.dwCatalogEntryId
== StartId
) break;
525 /* Match the Id with all the entries in the List */
526 while (NextEntry
!= &Catalog
->ProtocolList
)
528 /* Get the Current Entry */
529 Entry
= CONTAINING_RECORD(NextEntry
, TCATALOG_ENTRY
, CatalogLink
);
530 NextEntry
= NextEntry
->Flink
;
532 /* Check if Address Family Matches or if it's wildcard */
533 if ((Entry
->ProtocolInfo
.iAddressFamily
== af
) || (af
== AF_UNSPEC
))
535 /* Check if Socket Type Matches or if it's wildcard */
536 if ((Entry
->ProtocolInfo
.iSocketType
== type
) || (type
== 0))
538 /* Check if Protocol is In Range or if it's wildcard */
539 if (((Entry
->ProtocolInfo
.iProtocol
<= protocol
) &&
540 ((Entry
->ProtocolInfo
.iProtocol
+
541 Entry
->ProtocolInfo
.iProtocolMaxOffset
) >= protocol
)) ||
544 /* Check that if type and protocol are 0 provider entry has PFL_MATCHES_PROTOCOL_ZERO flag set */
545 if (type
== 0 && protocol
== 0 && (Entry
->ProtocolInfo
.dwProviderFlags
& PFL_MATCHES_PROTOCOL_ZERO
) == 0)
547 ErrorCode
= WSAEPROTONOSUPPORT
;
551 /* Check if it doesn't already have a provider */
552 if (!Entry
->Provider
)
554 /* Match, load the Provider */
555 ErrorCode
= WsTcLoadProvider(Catalog
, Entry
);
557 /* Make sure this didn't fail */
558 if (ErrorCode
!= ERROR_SUCCESS
) break;
561 /* Reference the entry and return it */
562 InterlockedIncrement(&Entry
->RefCount
);
563 *CatalogEntry
= Entry
;
564 ErrorCode
= ERROR_SUCCESS
;
569 ErrorCode
= WSAEPROTONOSUPPORT
;
574 if (ErrorCode
!= WSAEPROTONOSUPPORT
)
575 ErrorCode
= WSAESOCKTNOSUPPORT
;
580 if (ErrorCode
!= WSAEPROTONOSUPPORT
&& ErrorCode
!= WSAESOCKTNOSUPPORT
)
581 ErrorCode
= WSAEAFNOSUPPORT
;
585 /* Release the catalog */
594 WsTcFindProvider(IN PTCATALOG Catalog
,
595 IN LPGUID ProviderId
)
599 PTCATALOG_ENTRY CatalogEntry
;
601 /* Loop the provider list */
602 Entry
= Catalog
->ProtocolList
.Flink
;
603 while (Entry
!= &Catalog
->ProtocolList
)
606 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
608 /* Move to the next one, get the provider */
609 Entry
= Entry
->Flink
;
610 Provider
= CatalogEntry
->Provider
;
612 /* Check for a match */
614 !(memcmp(&CatalogEntry
->ProtocolInfo
.ProviderId
,
629 WsTcLoadProvider(IN PTCATALOG Catalog
,
630 IN PTCATALOG_ENTRY CatalogEntry
)
632 INT ErrorCode
= ERROR_SUCCESS
;
634 DPRINT("WsTcLoadProvider: %p, %p\n", Catalog
, CatalogEntry
);
636 /* Lock the catalog */
639 /* Check if we have a provider already */
640 if (!CatalogEntry
->Provider
)
642 /* Try to find another instance */
643 Provider
= WsTcFindProvider(Catalog
,
644 &CatalogEntry
->ProtocolInfo
.ProviderId
);
646 /* Check if we found one now */
649 /* Set this one as the provider */
650 WsTcEntrySetProvider(CatalogEntry
, Provider
);
651 ErrorCode
= ERROR_SUCCESS
;
655 /* Nothing found, Allocate a provider */
656 if ((Provider
= WsTpAllocate()))
659 ErrorCode
= WsTpInitialize(Provider
,
660 CatalogEntry
->DllPath
,
661 &CatalogEntry
->ProtocolInfo
);
664 if (ErrorCode
== ERROR_SUCCESS
)
666 /* Set the provider */
667 WsTcEntrySetProvider(CatalogEntry
, Provider
);
671 WsTpDereference(Provider
);
676 ErrorCode
= WSA_NOT_ENOUGH_MEMORY
;
681 /* Release the lock */
688 WsTcUpdateProtocolList(IN PTCATALOG Catalog
,
692 PTCATALOG_ENTRY CatalogEntry
, OldCatalogEntry
;
695 /* First move from our list to the old one */
696 InsertHeadList(&Catalog
->ProtocolList
, &TempList
);
697 RemoveEntryList(&Catalog
->ProtocolList
);
698 InitializeListHead(&Catalog
->ProtocolList
);
700 /* Loop every item on the list */
701 while (!IsListEmpty(List
))
703 /* Get the catalog entry */
704 Entry
= RemoveHeadList(List
);
705 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
707 /* Check if this item is already on our list */
708 Entry
= TempList
.Flink
;
709 while (Entry
!= &TempList
)
711 /* Get the catalog entry */
712 OldCatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
713 Entry
= Entry
->Flink
;
715 /* Check if they match */
716 if (CatalogEntry
->ProtocolInfo
.dwCatalogEntryId
==
717 OldCatalogEntry
->ProtocolInfo
.dwCatalogEntryId
)
719 /* We have a match, use the old item instead */
720 WsTcEntryDereference(CatalogEntry
);
721 CatalogEntry
= OldCatalogEntry
;
722 RemoveEntryList(&CatalogEntry
->CatalogLink
);
724 /* Decrease the number of protocols we have */
725 Catalog
->ItemCount
--;
731 InsertTailList(&Catalog
->ProtocolList
, &CatalogEntry
->CatalogLink
);
732 Catalog
->ItemCount
++;
735 /* If there's anything left on the temporary list */
736 while (!IsListEmpty(&TempList
))
739 Entry
= RemoveHeadList(&TempList
);
740 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
743 Catalog
->ItemCount
--;
744 WsTcEntryDereference(CatalogEntry
);
750 WsTcEnumerateCatalogItems(IN PTCATALOG Catalog
,
751 IN PTCATALOG_ENUMERATE_PROC Callback
,
755 PTCATALOG_ENTRY CatalogEntry
;
758 /* Lock the catalog */
761 /* Loop the entries */
762 Entry
= Catalog
->ProtocolList
.Flink
;
763 while (GoOn
&& (Entry
!= &Catalog
->ProtocolList
))
766 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
768 /* Move to the next one and call the callback */
769 Entry
= Entry
->Flink
;
770 GoOn
= Callback(Context
, CatalogEntry
);
779 WsTcFindIfsProviderForSocket(IN PTCATALOG Catalog
,
787 WSAPROTOCOL_INFOW ProtocolInfo
;
790 PTCATALOG_ENTRY CatalogEntry
;
792 /* Get the catalog lock */
795 /* Loop as long as the catalog changes */
798 /* Loop every provider */
799 Entry
= Catalog
->ProtocolList
.Flink
;
800 while (Entry
!= &Catalog
->ProtocolList
)
802 /* Get the catalog entry */
803 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
805 /* Move to the next entry */
806 Entry
= Entry
->Flink
;
808 /* Skip it if it doesn't support IFS */
809 if (!(CatalogEntry
->ProtocolInfo
.dwServiceFlags1
& XP1_IFS_HANDLES
)) continue;
811 /* Check if we need to load it */
812 if (!(Provider
= CatalogEntry
->Provider
))
815 ErrorCode
= WsTcLoadProvider(Catalog
, CatalogEntry
);
817 /* Skip it if we failed to load it */
818 if (ErrorCode
!= ERROR_SUCCESS
) continue;
820 /* Get the provider again */
821 Provider
= CatalogEntry
->Provider
;
824 /* Reference the entry and get our unique id */
825 InterlockedIncrement(&CatalogEntry
->RefCount
);
826 UniqueId
= Catalog
->UniqueId
;
828 /* Release the lock now */
831 /* Get the catalog entry ID */
832 OptionLength
= sizeof(ProtocolInfo
);
833 ErrorCode
= Provider
->Service
.lpWSPGetSockOpt(Handle
,
836 (PCHAR
)&ProtocolInfo
,
837 (LPINT
)&OptionLength
,
840 /* Dereference the entry and check the result */
841 WsTcEntryDereference(CatalogEntry
);
842 if (ErrorCode
!= ERROR_SUCCESS
)
844 /* Lock and make sure this provider is still valid */
846 if (UniqueId
== Catalog
->UniqueId
) continue;
848 /* It changed! We need to start over */
852 /* Now get the IFS handle */
853 NewHandle
= WPUModifyIFSHandle(ProtocolInfo
.dwCatalogEntryId
,
857 /* Check if the socket is invalid */
858 if (NewHandle
== INVALID_SOCKET
) return WSAENOTSOCK
;
860 /* We suceeded, get out of here */
861 return ERROR_SUCCESS
;
864 /* Unrecognized socket if we get here: note, we still have the lock */
871 WsTcRemoveCatalogItem(IN PTCATALOG Catalog
,
872 IN PTCATALOG_ENTRY Entry
)
874 /* Remove the entry from the list */
875 RemoveEntryList(&Entry
->CatalogLink
);
877 /* Decrease our count */
878 Catalog
->ItemCount
--;
883 WsTcDelete(IN PTCATALOG Catalog
)
886 PTCATALOG_ENTRY CatalogEntry
;
888 /* Check if we're initialized */
889 if (!Catalog
->ProtocolList
.Flink
) return;
894 /* Loop every entry */
895 Entry
= Catalog
->ProtocolList
.Flink
;
896 while (Entry
!= &Catalog
->ProtocolList
)
899 CatalogEntry
= CONTAINING_RECORD(Entry
, TCATALOG_ENTRY
, CatalogLink
);
902 WsTcRemoveCatalogItem(Catalog
, CatalogEntry
);
905 WsTcEntryDereference(CatalogEntry
);
907 /* Move to the next entry */
908 Entry
= Catalog
->ProtocolList
.Flink
;
911 /* Check if the catalog key is opened */
912 if (Catalog
->CatalogKey
)
915 RegCloseKey(Catalog
->CatalogKey
);
916 Catalog
->CatalogKey
= NULL
;
919 /* Release and delete the lock */
921 DeleteCriticalSection((LPCRITICAL_SECTION
)&Catalog
->Lock
);
923 /* Delete the object */
924 HeapFree(WsSockHeap
, 0, Catalog
);