DCATALOG.CPP
/*++ 
 
     Copyright (c) 1996 Intel Corporation 
     Copyright 1996 - 1998 Microsoft Corporation 
     All Rights Reserved 
 
     Permission is granted to use, copy and distribute this software and 
     its documentation for any purpose and without fee, provided, that 
     the above copyright notice and this statement appear in all copies. 
     Intel makes no representations about the suitability of this 
     software for any purpose.  This software is provided "AS IS." 
 
     Intel specifically disclaims all warranties, express or implied, 
     and all liability, including consequential and other indirect 
     damages, for the use of this software, including liability for 
     infringement of any proprietary rights, and including the 
     warranties of merchantability and fitness for a particular purpose. 
     Intel does not assume any responsibility for any errors which may 
     appear in this software nor any responsibility to update it. 
 
 
Module Name: 
 
    dcatalog.cpp 
 
Abstract: 
 
    This module contains the implementation of the dcatalog class. This class 
    maintains a catalog of installed WinSock2 service providers. 
 
--*/ 
 
#include "precomp.h" 
#include "install.h" 
 
  
DCATALOG::DCATALOG() 
/*++ 
 
Routine Description: 
 
    Constructor for the DCATALOG object. Set member variables to known 
    state. Initialization of the object is completed in Initialize(). 
 
Arguments: 
 
    NONE. 
 
Return Value: 
 
    NONE. 
 
--*/ 
{ 
 
    m_num_items = 0; 
    m_local_item = NULL; 
 
    // initialize the critical section object 
    InitializeCriticalSection( &m_catalog_lock ); 
    InitializeListHead( &m_protocol_list ); 
} 
 
INT 
DCATALOG::Initialize( 
    ) 
/*++ 
 
Routine Description: 
 
    Initialization routine for the DCATALOG object. Completes the 
    initialization of the DCATALOG object.  This MUST be the first member 
    fuction called after a DCATALOG object is created. 
 
Arguments: 
 
    NONE. 
 
Return Value: 
 
    NO_ERROR if the fuction succeeds else a winsock2 error code. 
 
--*/ 
{ 
    LPWSAPROTOCOL_INFOW   ProtocolInfoBuff = NULL; 
    DWORD                ProtocolInfoBuffSize = 0; 
    PPROTO_CATALOG_ITEM  CatalogItem; 
    INT                  ReturnCode; 
    INT                  ErrorCode; 
    INT                  EnumResult; 
    INT                  Index; 
 
    // Call WSCEnumProtocols with a zero length buffer so we know what size to 
    // send in to get all the installed PROTOCOL_INFO structs. 
    WSCEnumProtocols( 
        NULL,                     // lpiProtocols 
        ProtocolInfoBuff,         // lpProtocolBuffer 
        & ProtocolInfoBuffSize,   // lpdwBufferLength 
        & ErrorCode);             // lpErrno 
 
    ReturnCode = WSA_NOT_ENOUGH_MEMORY; 
    ProtocolInfoBuff = (LPWSAPROTOCOL_INFOW)new char[ProtocolInfoBuffSize]; 
    if (ProtocolInfoBuff){ 
        EnumResult = WSCEnumProtocols( 
            NULL,                     // lpiProtocols 
            ProtocolInfoBuff,         // lpProtocolBuffer 
            & ProtocolInfoBuffSize,   // lpdwBufferLength 
            & ErrorCode); 
 
        ReturnCode = WSASYSNOTREADY; 
        if (EnumResult != SOCKET_ERROR){ 
            for (Index=0; Index < EnumResult ; Index++){ 
 
                //Create a new catalog item for the PROTOCOL_INFO struct. 
                CatalogItem = new PROTO_CATALOG_ITEM; 
                if (CatalogItem){ 
 
                    ReturnCode = CatalogItem->Initialize( 
                        &ProtocolInfoBuff[Index]); 
                    if (NO_ERROR == ReturnCode){ 
 
                        //Add the new catalog item to the catalog 
                        AcquireCatalogLock(); 
                        AppendCatalogItem( 
                            CatalogItem); 
                        if (memcmp (&CatalogItem->GetProtocolInfo()->ProviderId, 
                                &LayeredProviderGuid, 
sizeof (GUID))==0) 
                            m_local_item = CatalogItem; 
                        ReleaseCatalogLock(); 
                    } //if 
                    else{ 
                        break; 
                    } //else 
                } //if 
            } //for 
 
            if ((NO_ERROR==ReturnCode) 
                    && (m_local_item==NULL)) 
                ReturnCode = WSASYSNOTREADY; 
        } //if 
        delete(ProtocolInfoBuff); 
    } //if 
    return(ReturnCode); 
} 
 
 
 
  
DCATALOG::~DCATALOG() 
/*++ 
 
Routine Description: 
 
    This  function  destroys the catalog object.  It takes care of removing and 
    destroying  all  of  the  catalog  entries  in  the catalog.  This includes 
    destroying  all  of the DPROVIDER objects referenced by the catalog.  It is 
    the  caller's responsibility to make sure that the DPROVIDER objects are no 
    longer referenced. 
 
Arguments: 
 
    None 
 
Return Value: 
 
    None 
 
Implementation Notes: 
 
    for each catalog entry 
        remove the entry 
        get its DPROVIDER reference 
        if reference is non-null 
            Set providers for all entries with matching IDs null 
            destroy the DPROVIDER 
        endif 
        destroy the entry 
    end for 
    deallocate the list head 
    close the catalog registry mutex 
--*/ 
{ 
    PLIST_ENTRY  this_linkage; 
    PPROTO_CATALOG_ITEM  this_item; 
    PDPROVIDER  this_provider; 
 
    DEBUGF( 
        DBG_TRACE, 
        ("Catalog destructor\n")); 
 
    AcquireCatalogLock(); 
 
    while ((this_linkage = m_protocol_list.Flink) != & m_protocol_list) { 
        this_item = CONTAINING_RECORD( 
            this_linkage,        // address 
            PROTO_CATALOG_ITEM,  // type 
            m_CatalogLinkage     // field 
            ); 
        RemoveCatalogItem( 
            this_item  // CatalogItem 
            ); 
        this_provider = this_item->GetProvider(); 
        if (this_provider) 
            delete this_provider; 
        delete this_item; 
    }  // while (get entry linkage) 
 
    assert( m_num_items == 0 ); 
 
    ReleaseCatalogLock(); 
    DeleteCriticalSection( &m_catalog_lock ); 
 
}  // ~DCATALOG 
 
 
 
  
VOID 
DCATALOG::EnumerateCatalogItems( 
    IN CATALOGITERATION  Iteration, 
    IN DWORD             PassBack 
    ) 
/*++ 
 
Routine Description: 
 
    This  procedure enumerates all of the DPROTO_CATALOG_ITEM structures in the 
    catalog  by  calling  the indicated iteration procedure once for each item. 
    The called procedure can stop the iteration early by returning FALSE. 
 
    Note  that  the DPROVIDER associated with an enumerated DPROTO_CATALOG_ITEM 
    may  be  NULL.   To retrieve DPROTO_CATALOG_ITEM structure that has had its 
    DPROVIDER      loaded      and      initialized,      you      can      use 
    GetCatalogItemFromCatalogEntryId. 
 
Arguments: 
 
    Iteration - Supplies   a  reference  to  the  catalog  iteration  procedure 
                supplied by the client. 
 
    PassBack  - Supplies  a  value uninterpreted by this procedure.  This value 
                is  passed  unmodified to the catalog iteration procedure.  The 
                client can use this value to carry context between the original 
                call site and the iteration procedure. 
 
Return Value: 
 
    None 
--*/ 
{ 
    PLIST_ENTRY         ListMember; 
    PPROTO_CATALOG_ITEM CatalogEntry; 
    BOOL                enumerate_more; 
 
    assert(Iteration != NULL); 
 
    enumerate_more = TRUE; 
 
    AcquireCatalogLock(); 
 
    ListMember = m_protocol_list.Flink; 
 
    while (enumerate_more && (ListMember != & m_protocol_list)) { 
        CatalogEntry = CONTAINING_RECORD( 
            ListMember, 
            PROTO_CATALOG_ITEM, 
            m_CatalogLinkage); 
        ListMember = ListMember->Flink; 
        enumerate_more = (* Iteration) ( 
            PassBack,     // PassBack 
            CatalogEntry  // CatalogEntry 
            ); 
    } //while 
 
    ReleaseCatalogLock(); 
 
}  // EnumerateCatalogItems 
 
 
  
INT 
DCATALOG::FindNextProviderInChain( 
        IN  LPWSAPROTOCOL_INFOW lpProtocolInfo, 
        OUT PDPROVIDER          *NextProvider, 
OUT PPROTO_CATALOG_ITEM*BaseProviderCatalogEntry 
    ) 
/*++ 
 
Routine Description: 
 
    This procedure finds and loads the provider below this 
    provider in the protocol chain. 
 
Arguments: 
    lpLocalProtocolInfo - A pointer to the WSAPROTOCOL_INFO struct for the 
                          current protocol chain. 
 
    NextProvider        - A pointer to DPROVIDER object pointer for the 
                          next provider in chain 
BaseProviderCatalogEntry - If next provider is a base provider, this 
  pointer will contain the next provider catalog 
  entry 
Return Value: 
 
    NO_ERROR if the next provider is located else a valid winsock2 error 
    code. 
--*/ 
{ 
 
    PLIST_ENTRY         ListMember; 
    PPROTO_CATALOG_ITEM CatalogEntry; 
    PPROTO_CATALOG_ITEM NextProviderCatalogEntry; 
DWORDLocalCatalogEntryId; 
    DWORD               NextProviderCatalogEntryId; 
    INT                 Index; 
    INT                 ReturnCode =WSASYSNOTREADY; 
 
assert (NextProvider!=NULL); 
 
if (m_local_item==NULL) 
return WSASYSNOTREADY; 
 
LocalCatalogEntryId = m_local_item->GetProtocolInfo()->dwCatalogEntryId; 
 
    AcquireCatalogLock(); 
 
// First try to see if we have processed this chain already and 
// thus loaded the provider that follows us in it 
    ListMember = m_protocol_list.Flink; 
 
    while (ListMember != & m_protocol_list) { 
 
        CatalogEntry = CONTAINING_RECORD( 
            ListMember, 
            PROTO_CATALOG_ITEM, 
            m_CatalogLinkage); 
        ListMember = ListMember->Flink; 
        if (CatalogEntry->GetProtocolInfo()->dwCatalogEntryId == 
lpProtocolInfo->dwCatalogEntryId) { 
*NextProvider = CatalogEntry->GetProvider (); 
if (*NextProvider!=NULL) { 
 ReturnCode = NO_ERROR; 
} 
else { 
// 
// Get the next providers CatalogEntryId from the protocol chain 
// 
for (Index=0; 
 Index < lpProtocolInfo->ProtocolChain.ChainLen; 
 Index++){ 
if ((LocalCatalogEntryId== 
lpProtocolInfo->ProtocolChain.ChainEntries[Index]) 
&& (lpProtocolInfo->ProtocolChain.ChainLen>Index+1)) { 
NextProviderCatalogEntryId = 
lpProtocolInfo->ProtocolChain.ChainEntries[Index+1]; 
break; 
} //if 
} // for 
// 
// If we found ourselves before reaching the end of the chain, 
// go load the next guy in the chain 
// 
if (Index<lpProtocolInfo->ProtocolChain.ChainLen) { 
ReturnCode = GetCatalogItemFromCatalogEntryId ( 
NextProviderCatalogEntryId, 
&NextProviderCatalogEntry); 
if (NO_ERROR==ReturnCode) { 
// Pass the chain protocol info if 
// the provider we are loading is not 
// the last in the chain (base provider) 
if (Index==lpProtocolInfo->ProtocolChain.ChainLen-1) 
ReturnCode = LoadProvider ( 
NextProviderCatalogEntry, 
NextProviderCatalogEntry->GetProtocolInfo(), 
NextProvider); 
else 
ReturnCode = LoadProvider ( 
NextProviderCatalogEntry, 
lpProtocolInfo, 
NextProvider); 
 
// Cache provider if we succeded 
if (NO_ERROR==ReturnCode) { 
CatalogEntry->SetProvider (*NextProvider); 
CatalogEntry->SetProviderCatalogEntry (NextProviderCatalogEntry); 
} 
} //if 
} 
} 
if ((NO_ERROR==ReturnCode) 
&& (CatalogEntry->GetProviderCatalogEntry()->GetProtocolInfo()->ProtocolChain.ChainLen==BASE_PROTOCOL)) 
*BaseProviderCatalogEntry = CatalogEntry->GetProviderCatalogEntry(); 
 
break; 
} 
} 
 
    ReleaseCatalogLock(); 
    return(ReturnCode); 
} 
 
 
  
INT 
DCATALOG::GetCatalogItemFromCatalogEntryId( 
    IN  DWORD                     CatalogEntryId, 
    OUT PPROTO_CATALOG_ITEM FAR * CatalogItem 
    ) 
/*++ 
 
Routine Description: 
 
    This  procedure  retrieves  a  reference  to a catalog item given a catalog 
    entry ID to search for. 
 
 
Arguments: 
 
    CatalogEntryId  - Supplies The ID of a catalog entry to be searched for. 
 
    CatalogItem     - Returns a reference to the catalog item with the matching 
                      catalog entry ID if it is found, otherwise returns NULL. 
 
Return Value: 
 
  The  function  returns  NO_ERROR  if  successful, otherwise it returns an 
  appropriate WinSock error code. 
--*/ 
{ 
    PLIST_ENTRY         ListMember; 
    INT                 ReturnCode=WSASYSNOTREADY; 
    PPROTO_CATALOG_ITEM CatalogEntry; 
 
    assert(CatalogItem != NULL); 
 
    // Prepare for early error return 
    * CatalogItem = NULL; 
 
    AcquireCatalogLock(); 
 
    ListMember = m_protocol_list.Flink; 
 
    while (ListMember != & m_protocol_list) { 
 
        CatalogEntry = CONTAINING_RECORD( 
            ListMember, 
            PROTO_CATALOG_ITEM, 
            m_CatalogLinkage); 
        ListMember = ListMember->Flink; 
        if (CatalogEntry->GetProtocolInfo()->dwCatalogEntryId == 
CatalogEntryId) { 
            * CatalogItem = CatalogEntry; 
            ReturnCode = NO_ERROR; 
break; 
        } //if 
    } //while 
 
    ReleaseCatalogLock(); 
    return(ReturnCode); 
}  // GetCatalogItemFromCatalogEntryId 
 
 
  
INT 
DCATALOG::LoadProvider( 
    IN PPROTO_CATALOG_ITEM CatalogEntry, 
    IN LPWSAPROTOCOL_INFOW lpProtocolInfo, 
    OUT PDPROVIDER         *Provider 
    ) 
/*++ 
 
Routine Description: 
 
    Load   the   provider  described  by  CatalogEntry. 
 
Arguments: 
 
    CatalogEntry - Supplies  a reference to a protocol catalog entry describing 
                   the provider to load. 
 
    lpProtocolInfo - Protocol info structure to pass to provider when 
loading it 
 
    Provider     - Returns a reference to the newly loaded provider object. 
 
Return Value: 
 
    The  function  returns NO_ERROR if successful, otherwise it returns an 
    appropriate WinSock error code. 
--*/ 
{ 
    INT ReturnCode = WSA_NOT_ENOUGH_MEMORY; 
    PDPROVIDER LocalProvider; 
 
    assert(CatalogEntry != NULL); 
    assert(Provider != NULL); 
 
    *Provider = NULL; 
 
    LocalProvider = new(DPROVIDER); 
    if (LocalProvider) { 
 
        ReturnCode = LocalProvider->Initialize( 
            CatalogEntry->GetLibraryPath(), 
            lpProtocolInfo 
            ); 
        if (NO_ERROR == ReturnCode) { 
            *Provider = LocalProvider; 
        } //if 
        else { 
            delete(LocalProvider); 
        } //else 
    } //if 
    return(ReturnCode); 
}  // LoadProvider 
 
 
  
VOID 
DCATALOG::AppendCatalogItem( 
    IN  PPROTO_CATALOG_ITEM  CatalogItem 
    ) 
/*++ 
 
Routine Description: 
 
    This procedure appends a catalog item to the end of the (in-memory) catalog 
    object.   It becomes the last item in the catalog. 
 
Arguments: 
 
    CatalogItem - Supplies a reference to the catalog item to be added. 
 
Return Value: 
 
    None 
--*/ 
{ 
    assert(CatalogItem != NULL); 
 
    InsertTailList( 
        & m_protocol_list,               // ListHead 
        & CatalogItem->m_CatalogLinkage  // Entry 
       ); 
    m_num_items++; 
}  // AppendCatalogItem 
 
 
  
VOID 
DCATALOG::RemoveCatalogItem( 
    IN  PPROTO_CATALOG_ITEM  CatalogItem 
    ) 
/*++ 
 
Routine Description: 
 
    This  procedure removes a catalog item from the (in-memory) catalog object. 
    The catalog information in the registry is NOT updated. 
 
Arguments: 
 
    CatalogItem - Supplies a reference to the catalog item to be removed. 
 
Return Value: 
 
    None 
--*/ 
{ 
    assert(CatalogItem != NULL); 
 
    RemoveEntryList( 
        & CatalogItem->m_CatalogLinkage  // Entry 
        ); 
    assert(m_num_items > 0); 
    m_num_items--; 
}  // RemoveCatalogItem