diff -r 000000000000 -r dfb7c4ff071f datacommsserver/esockserver/ssock/SS_MAN.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/datacommsserver/esockserver/ssock/SS_MAN.CPP Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,1411 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +//#include +#include +#include +#include +#include +#include "SS_rslv.H" +#include "SS_conn.H" +#include "ss_eintsockimpl.h" + + +#ifdef _DEBUG +// Panic category for "absolutely impossible!" vanilla ASSERT()-type panics from this module +// (if it could happen through user error then you should give it an explicit, documented, category + code) +_LIT(KSpecAssert_ESockSSockS_MAN, "ESockSSockS_MAN."); +#endif + +using namespace ESock; + +#if defined (_DEBUG) + +/** @file +Check that the protocol has filled in the protocol structure +As much as we can anyway. +Note that this function needs to be maintained in parallel with the contents of es_sock.h and es_prot.h + +A panic in this function means that the protocol has returned an invalid TServerProtocolDesc + +@internalComponent +*/ +void CheckProtocolList(TServerProtocolDesc* aProtocolList,TInt aCount) + { + for (TInt i=0;iiServiceTypeInfo&0xFFFFFF00) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iNumSockets==(TInt)0xa5a5a5a5) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iName.Length()==0) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iAddrFamily==0 || (aProtocolList+i)->iAddrFamily==0xa5a5a5a5) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iSockType==0xa5a5a5a5) + { + Panic(EBadProtocolDescription); + } + //If the socket has no support for sockets (NumSockets is 0) + //then it should be of SockType 0. + if ((aProtocolList+i)->iSockType==0) + { + if ((aProtocolList+i)->iNumSockets!=0) + { + Panic(EBadProtocolDescription); + } + } + if ((aProtocolList+i)->iProtocol==0 || (aProtocolList+i)->iProtocol==0xa5a5a5a5) + { + Panic(EBadProtocolDescription); + } + if ((((aProtocolList+i)->iVersion.iMajor==0)&&((aProtocolList+i)->iVersion.iMinor==0)&&((aProtocolList+i)->iVersion.iBuild==0))) + { + Panic(EBadProtocolDescription); + } + if (((aProtocolList+i)->iByteOrder!=EBigEndian && (aProtocolList+i)->iByteOrder!=ELittleEndian && (aProtocolList+i)->iByteOrder!=EOtherByteOrder)) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iServiceInfo&0xfffc0000) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iNamingServices&0xfffffe00) + { + Panic(EBadProtocolDescription); + } + if ((aProtocolList+i)->iSecurity&0xfffffffe) + { + Panic(EBadProtocolDescription); + } + if (((aProtocolList+i)->iMessageSize<0 && (aProtocolList+i)->iMessageSize!=KSocketMessageSizeNoLimit)) + { + Panic(EBadProtocolDescription); + } + } + } +#endif + +// +// Protocol manager assumes that there will be an ini file setion called +// [protocols] which will contain a single entry: protocols= the data for +// which is a comma seperated list of further section names. +// Each of these section names should contina a file name of a .PRT +// and index number of the protocol inside this family and an optional +// bindto= entry specifying which lower protocols this should be bound to. +// +// The protocol manager late loads (and binds) all protocols - keeping only CProtocolRef etc. +// classes which contain enough data to reload the protocol when the first socket is +// created. Protocols will the stay loaded unti lthe last client (who made a socket of +// the specified type) closes. I.e. protocols are created for sockets but referenced by +// sessions. +// + +/** +@internalComponent +*/ + +_LIT(KSockManMainSectionName,"sockman"); +_LIT(KProtocolListItemName,"protocols"); +_LIT(KFilenameItemName,"filename"); +_LIT(KIndexTagName,"index"); +_LIT(KBindToItemName,"bindto"); +_LIT(KBindFromItemName,"bindfrom"); +_LIT(KFlowFactoryUid, "flow_factory_uid"); +_LIT(KFlowProtocol, "flow_protocol_id"); +_LIT(KOpenAngle, "<"); +_LIT(KCloseAngle, ">"); +_LIT(KComma, ","); + +const TInt KDependSize = 32; + + +void ProtocolManager::AddDependencyL(const TDesC& aDependentsList, const TDesC& aModuleToLoad) +/** +Adds a module to the dependency list. Dependency list is of form b,ce,f +meaning that module "a" is dependant on "b" and "c" and requires module b and c to be loaded. + +@param aDependentsList list of dependant components to be loaded +@param aModuleToLoad The module for which the dependency is added +*/ + { + CSockManData *globals=SockManGlobals::Get(); + + if (globals->iDeps == NULL) + { + globals->iDeps = HBufC::NewL(KDependSize); + } + + TLex lex(aDependentsList); + TChar ch=0; + do + { + lex.Mark(); + + do + { + ch=lex.Get(); + } + while (ch!=',' && ch!=0); + + if (ch==',') + { + lex.UnGet(); + } + + TPtrC dependent=lex.MarkedToken(); + lex.Get(); + + TBuf<50> searchBuf; + searchBuf.Append(KOpenAngle); + searchBuf.Append(dependent); + searchBuf.Append(KCloseAngle); + + TPtr list = globals->iDeps->Des(); + TInt reqLength = list.Length() + searchBuf.Length() + aModuleToLoad.Length(); + if (reqLength >= list.MaxLength()) + { + globals->iDeps = globals->iDeps->ReAllocL(reqLength); + list.Set(globals->iDeps->Des()); + } + + TInt pos = list.Find(searchBuf); + if (pos == KErrNotFound) + { + list.Append(searchBuf); + list.Append(aModuleToLoad); + } + else + { + pos++; + TInt endPos = list.Mid(pos).Find(KOpenAngle); + if (endPos != KErrNotFound) + { + endPos += pos; + list.Insert(endPos, KComma); + list.Insert(endPos + 1, aModuleToLoad); + } + else + { + list.Append(KComma); + list.Append(aModuleToLoad); + } + } + } while (ch != 0); + } + +TBool ProtocolManager::GetDependency(const TDesC& aTag,TPtrC &aList) +/** +Goes through the dependency list and gets the dependant modules for aTag + +@param aTag The protocol tag based on which the dependancy list is searched +@param aList A list of components dependant on aTag protocol which are returned +@return ETrue if a dependency for the component aTag is found else EFalse +*/ + { + CSockManData *globals=SockManGlobals::Get(); + + if(globals->iDeps) + { + + TPtrC list = *globals->iDeps; + + TBuf<50> tag(KOpenAngle); + tag.Append(aTag); + tag.Append(KCloseAngle); + + TInt offset= list.Find(tag); + + if(offset!=KErrNotFound) + { + aList.Set(list.Mid(offset+tag.Length())); + offset= aList.Find(KOpenAngle); + if(offset!=KErrNotFound) + { + aList.Set(aList.Mid(0,offset)); + } + return ETrue; + } + } + return EFalse; + } + +void ProtocolManager::InitL() +/** +Init data structures and hunt for protocols. +*/ + { + LOG( ESockLog::Printf(_L("ProtocolManager: Initialising.")) ); + + // Allocate global storage to be held in tls. + CSockManData *globals=SockManGlobals::Get(); + + globals->iProtocols=new(ELeave) TSglQue(_FOFF(CProtocolRef,iLink)); + CleanupStack::PushL(globals->iProtocols); + globals->iProtocolFamilies=new(ELeave) TSglQue(_FOFF(CProtocolFamilyRef,iLink)); + CleanupStack::Pop(globals->iProtocols); + } + +void ProtocolManager::ShutDown() +/** +free data structures +*/ + { + CSockManData* globals=SockManGlobals::Get(); + + TSglQueIter i(*globals->iProtocols); + CProtocolRef* p=NULL; + while(p=i++,p!=NULL) + { + globals->iProtocols->Remove(*p); + delete p; + } + + TSglQueIter j(*globals->iProtocolFamilies); + CProtocolFamilyRef* f=NULL; + while(f=j++,f!=NULL) + { + globals->iProtocolFamilies->Remove(*f); + delete f; + } + + // delete all the containers and lists of protocols etc. + delete globals->iProtocols; + delete globals->iProtocolFamilies; + delete globals->iDeps; + + } + +void ProtocolManager::ProcessIniDataL() + { + LOG( ESockLog::Printf(_L("ProtocolManager: Retrieve ESock inidata.")) ); + + CSockManData *globals=SockManGlobals::Get(); + const CESockIniData* ini=globals->IniData(); + + TPtrC protocols; + if (ini->FindVar(KSockManMainSectionName,KProtocolListItemName,protocols)==EFalse) + User::Leave(KErrBadName); + + LOG( ESockLog::Printf(_L("ProtocolManager: Protocol list is %S"), &protocols) ); + LOG( ESockLog::Printf(_L("ProtocolManager: Loading PRTs and setting up protocols.")) ); + + TLex lex(protocols); + TChar ch=0; + do + { + lex.Mark(); + + do + { + ch=lex.Get(); + } + while (ch!=',' && ch!=0); + + if (ch==',') + { + lex.UnGet(); + } + TPtrC protTag=lex.MarkedToken(); + lex.Get(); + TPtrC fileName(NULL,0); + + // If there is no filename present (legacy PRT based protocols) then we expect instead the uid of a + // three plane comms based flow factory that can can return a protocol description + if(ini->FindVar(protTag, KFilenameItemName, fileName) == EFalse) + { + // Deal with the flow case + // Fetch the UID of the flow factory + TInt flowFactoryUid; + if(ini->FindVar(protTag, KFlowFactoryUid, flowFactoryUid) == EFalse) + { +#if defined(_DEBUG) + LOG(ESockLog::Printf(_L("ProtocolManager: error while parsing 3PC based protocol - no flow factory UID found"))); + Panic(EBadProtocolDescription); +#else + User::Leave(KErrNotFound); +#endif + } + + // We need the flow factory container in order to instantiate a flow factory with ECOM + // Misconfiguration should not kill off c32 in a release build so we simply leave rather than panic +#if defined(_DEBUG) + if(globals->iSubConnectionFlowFactories == NULL) + { + LOG(ESockLog::Printf(_L("ProtocolManager: error while parsing esk files - flow factories not yet initialised"))); + Panic(EBadProtocolDescription); + } +#else + User::LeaveIfNull(globals->iSubConnectionFlowFactories); +#endif + + // Fetch the given factory and fetch the protocol description from it + CSubConnectionFlowFactoryBase* flowFactory = + static_cast(globals->iSubConnectionFlowFactories->FindOrCreateFactoryL(TUid::Uid(flowFactoryUid))); + CleanupStack::PushL(flowFactory); + + // Fetch the id of the protocol itself (as one factory can create flows of more than one type) + TInt protocol; + if(ini->FindVar(protTag, KFlowProtocol, protocol) == EFalse) + { + LOG(ESockLog::Printf(_L("ProtocolManager: error while parsing esk file - no 3PC protocol found"))); + __ASSERT_DEBUG(0, Panic(EBadProtocolDescription)); + User::Leave(KErrNotFound); + } + + // Ask for a protocol description from the flow factory and add that description to our globals +#if defined(_DEBUG) + TServerProtocolDesc* protocolDescription = NULL; + TRAPD(descriptionError, protocolDescription = flowFactory->CreateFlowDescriptionL(protocol);); + if(descriptionError != KErrNone) + { + LOG(ESockLog::Printf(_L("ProtocolManager: error while parsing esk file - no protocol description provided by factory for 3PC based flow type"))); + Panic(EBadProtocolDescription); + } +#else + TServerProtocolDesc* protocolDescription = flowFactory->CreateFlowDescriptionL(protocol); +#endif + + CleanupStack::PushL(protocolDescription); + CProtocolRef::MakeRefL(protTag, protocolDescription); + globals->iNumProtocols++; + delete protocolDescription; + + CleanupStack::Pop(2, flowFactory); + } + else + { + // Deal with the legacy case + TPtrC bindfrom(NULL, 0); + if (ini->FindVar(protTag,KBindFromItemName,bindfrom)) + { + AddDependencyL(bindfrom, protTag); + } + + CProtocolFamilyRef* protFamily = NULL; + TInt err; + TRAP(err, protFamily = CProtocolFamilyRef::GetProtocolFamilyL(fileName)); + if (err != KErrNone) + { + continue; + } + CleanupStack::PushL(protFamily); + + // Query the protocol family about all the socket types it can produce + // We'll remember them because we unload the libraries until we actually need them. + TServerProtocolDesc *protocolList = NULL; + + + // Note: some protocols will leave in their ProtocolList() method. This + // is handled correctly here, although the naming convention is incorrect. + TInt numProtocols = 0; + TRAP(err, numProtocols = protFamily->ProtocolFamilyL(EFalse).ProtocolList(protocolList)); + + if (numProtocols == 0 || err != KErrNone) + { + LOG( ESockLog::Printf(_L("ProtocolManager: Protocol %S failed to load (error = %d, number of protocols = %d)"), + &protTag, err, numProtocols) ); + CleanupStack::Pop(protFamily); + continue; + } + +#if defined (_DEBUG) + CheckProtocolList(protocolList,numProtocols); +#endif + CleanupArrayDeletePushL(protocolList); + TInt num=0; + if (numProtocols>1) + { + if (ini->FindVar(protTag,KIndexTagName,num) == EFalse) + { + LOG(ESockLog::Printf(_L("ProtocolManager: error while parsing esk file - Protocol index missing"))); + User::Leave(KErrNotFound); + } + num--; + } + + if (num>numProtocols) + { + CleanupStack::Pop(protocolList); + CleanupStack::Pop(protFamily); + continue; + } + + + CProtocolRef *pp=CProtocolRef::MakeRefL(protTag,protFamily,protocolList+num); + if (pp==NULL) + { + User::Leave(KErrNoMemory); + } + CleanupStack::Pop(protocolList); + LOG(ESockLog::Printf(KESockSessDetailTag, _L("ProtocolManager: prot '%S' ref=%08x, famRef=%08x, num=%d"), &protTag, pp, protFamily, num)); + + globals->iNumProtocols++; + + delete []protocolList; + CleanupStack::Pop(protFamily); + } + } + while (ch!=0); // ch==0 when last token removed from TLex + + // Leave if there's no point in carrying on. - i.e. no protocols. + if (globals->iNumProtocols==0) + { + LOG(ESockLog::Printf(_L("ProtocolManager: No protocols - leaving."))); + User::Leave(KErrBadDriver); + } + + // Delete all protocolfamilybase objects, causing DLLs to unload + LOG(ESockLog::Printf(_L("ProtocolManager: Finished initialising. Unloading all PRTs."))); + TSglQueIter familyIter(*globals->iProtocolFamilies); + CProtocolFamilyRef* family; + while(family=familyIter++,family!=NULL) + { + delete &(family->ProtocolFamilyL(EFalse)); + } + + LOG(ESockLog::Printf(_L("ProtocolManager: Done."))); + + if(globals->iDeps) + { + LOG(ESockLog::Printf(_L("Dependencies: %S"), &*(globals->iDeps))); + } + } + +void ProtocolManager::SafeCleanupProtocol(TAny* aProtocolRef) +/** +Try to clean up a protocol instance + +This routine is pushed onto the cleanup stack in order to clean up a protocol instance. +The check against the protocol pointer being non-NULL is a safety check. This routine was +created because ProtocolManager::CleanupProtocol(protocol) was being called in circumstances +where the protocol had already gone and the pointer to it had become invalid. This routine +takes as argument a pointer to the CProtocolRef instance of the protocol, so that the protocol +pointer can be checked against NULL. + +@param aProtocolRef pointer to the CProtocolRef instance whose protocol needs to be deleted +*/ + { + CProtocolRef *pRef = reinterpret_cast(aProtocolRef); + if (pRef->Protocol()) + { + pRef->Protocol()->TryDelete(); + } + } + +void ProtocolManager::CleanupProtocol(TAny* aProtocol) + { + ((CProtocolBase *)aProtocol)->TryDelete(); + } + +void ProtocolManager::TransferSocketL(CSocket* aSocket, CPlayer* aPlayer) +/** +Transfer socket from one session to another +*/ + { + + //-- check the flag that enables socket transfer and the capabilities of the process that owns aSession, + //-- where the socket is supposed to be transferred. + if(aSocket->iSecTransferEnabled && aSocket->iTransferSecPolicy.CheckPolicy(aPlayer->SafeMessage())) + {//-- everything is OK, reset socket transfer flag. + aSocket->iSecTransferEnabled = EFalse; + } + else + {//-- security check failed. + User::Leave(KErrPermissionDenied); + } + + if (aSocket->iSSP) + { + // For non-null sockets, ask the socket provider to perform security + // policy checking on new session + User::LeaveIfError(aSocket->iSSP->SecurityCheck(aPlayer->CurrentSession())); + } + + // Add the protocol of the socket being transferred to the receipient session's list of protocols + // The socket doesn't know about legacy protocols directly anymore so we need to find the protocol + TProtocolDesc* info = aSocket->iProtocolInfo; + __ASSERT_DEBUG(info, User::Panic(KSpecAssert_ESockSSockS_MAN, 1)); + CProtocolRef* protocolReference = FindProtocolL(info->iAddrFamily, info->iSockType, info->iProtocol); + CProtocolBase* protocol = protocolReference->Protocol(); + + // The protocol reference will not have a protocol member if it refers to a new 3PC based flow + // Add the protocol to the sessionproxy for the session receiving the socket + if(protocol) + { + aPlayer->CurrentSessionProxyL()->AddProtocolL(protocol); + } + } + +CProtocolBase* ProtocolManager::FindAndLoadProtocolL(const TDesC& aName, TProtocolType aType) +/** +Find a protocol by name and load it. +Caller is responsible for ultimately deleting the protocol + +This is for use by extension DLLs as it does not attach the protocol +to a session. + +*/ + { + TServerProtocolDesc pinfo; + User::LeaveIfError(ProtocolInfo(aName,pinfo)); + switch (aType) + { + case ENormalProtocol: + // Dont care what extra interfaces it supports + break; + case EInterfaceProtocol: + // Need a protocol that support Interface extensions + if (!(pinfo.iServiceTypeInfo & EInterface)) + { + User::Leave(KErrBadName); + } + break; + } + return (FindAndLoadProtocolL(pinfo.iAddrFamily, pinfo.iSockType, pinfo.iProtocol)); + } + +CProtocolBase* ProtocolManager::FindAndLoadProtocolL(TUint aAddrFamily,TUint aSockType,TUint aProtocol) +/** +Find a protocol by address family, socket type, and protocol ID and load it. +Caller is responsible for ultimately deleting the protocol + +This is for use by extension DLLs as it does not attach the protocol +to a session. +*/ + { + CProtocolRef* pref = FindProtocolL(aAddrFamily,aSockType,aProtocol); + pref->LoadAndBindL(); + return pref->Protocol(); + } + +void ProtocolManager::LoadProtocolL(TUint anAddrFamily, TUint aSocketType, TUint aProtocol, CPlayer* aPlayer) +/** +Manually load the specified protocol +This is used by clients who need to ensure that an open call will not take a +significant amount of time (e.g. IrCOMM) It effectively makes all the lengthy parts of Open asynchronous. + +*/ + { + CProtocolRef* prot = FindProtocolL(anAddrFamily, aSocketType, aProtocol); + + // If the protocol reference is for a "three plane comms" based flow then we silently return + // without loading anything as their lifetime is managed by ECOM and therefore explicit loading is not supported + if(prot->GetFlag() & CProtocolRef::EThreePlaneCommsBased) + { + return; + } + + // Got one, make sure the library is loaded and we have an instance of the protocol object. + prot->LoadAndBindL(); + CleanupStack::PushL(TCleanupItem(ProtocolManager::CleanupProtocol,prot->Protocol())); + + // register the protocol with the Session + aPlayer->CurrentSessionProxyL()->AddProtocolL(prot->Protocol()); + CleanupStack::Pop(); + } + +void ProtocolManager::UnLoadProtocolL(TUint anAddrFamily, TUint aSocketType, TUint aProtocol, CPlayer* aPlayer) +/** +Do the opposite of the above function + +*/ + { + CProtocolRef* prot = FindProtocolL(anAddrFamily, aSocketType, aProtocol); + + // If the protocol reference is for a "three plane comms" based flow then we silently return + // without attempting to unload anything as their lifetime is managed by ECOM only + if(prot->GetFlag() & CProtocolRef::EThreePlaneCommsBased) + { + return; + } + + aPlayer->CurrentSessionProxyL()->RemoveProtocolL(prot->Protocol()); + } + +CHostResolver* ProtocolManager::NewHostResolverL(TUint anAddrFamily, TUint aProtocolId, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId) +/** +Create a new host resolver object + +*/ + { + CProtocolRef * prot=FindProtocolL(anAddrFamily,KUndefinedSockType,aProtocolId); + if (!(prot->Info().iNamingServices & KNSNameResolution)) + { + User::Leave(KErrNotSupported); + } + + // Got one, make sure protocol & library are loaded + prot->LoadAndBindL(); + + CleanupStack::PushL(TCleanupItem(ProtocolManager::CleanupProtocol,prot->Protocol())); + + CHostResolvProvdBase* hr=prot->Protocol()->NewHostResolverL(); + + // Give the host resolver the info to clean up after itself. + hr->iProtocol=prot->Protocol(); + + CleanupStack::Pop(); + CleanupStack::PushL(hr); + + + // ask the resolver provider to perform security policy checking + User::LeaveIfError(hr->SecurityCheck(aPlayer->CurrentSession())); + CHostResolver* r=CHostResolver::NewLC(prot, aPlayer->CurrentSession(), aPlayer, aSubSessionUniqueId); + +// CleanupStack::PushL(r); + + +// CleanupStack::Pop(r); +// CleanupStack::PushL(TCleanupItem(CloseSubSession,r)); + + // register the protocol with the Session +// aPlayer->CurrentSessionProxyL()->AddProtocolL(prot->Protocol()); + + aPlayer->SubSessions().AppendL(r); + hr->SetNotify(r); + r->SetResolver(hr); + CleanupStack::Pop(r); + CleanupStack::Pop(hr); +// CleanupStack::Pop(1); + + return r; + } + +CServiceResolver* ProtocolManager::NewServiceResolverL(TUint anAddrFamily, TUint aSocketType, TUint aProtocolId, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId) +/** +Create a new service resolver provider + +*/ + { + CProtocolRef * prot=FindProtocolL(anAddrFamily,aSocketType,aProtocolId); + if (!(prot->Info().iNamingServices & KNSServiceResolution)) + { + User::Leave(KErrNotSupported); + } + + // Got one, make sure protocol & library are loaded + prot->LoadAndBindL(); + CleanupStack::PushL(TCleanupItem(ProtocolManager::CleanupProtocol,prot->Protocol())); + + CServiceResolvProvdBase *sr=NULL; + + sr=prot->Protocol()->NewServiceResolverL(); + CleanupStack::PushL(sr); + + // Give the host resolver the info to clean up after itself. + sr->iProtocol=prot->Protocol(); + + // ask the resolver provider to perform security policy checking + User::LeaveIfError(sr->SecurityCheck(aPlayer->CurrentSession())); + CServiceResolver* s=CServiceResolver::NewLC(prot, aPlayer->CurrentSession(), aPlayer, aSubSessionUniqueId); + sr->SetNotify(s); + +// CleanupStack::PushL(TCleanupItem(CloseSubSession,s)); + + // register the protocol with the Session +// aPlayer->CurrentSessionProxyL()->AddProtocolL(prot->Protocol()); + + aPlayer->SubSessions().AppendL(s); + s->SetResolver(sr); + + CleanupStack::Pop(3); + return s; + } + +CNetDatabase* ProtocolManager::NewNetDatabaseL(TUint anAddrFamily, TUint aProtocolId, CPlayer* aPlayer, const TSubSessionUniqueId aSubSessionUniqueId) +/** +Create a new database type thang + +*/ + { + CProtocolRef * prot=FindProtocolL(anAddrFamily,KUndefinedSockType,aProtocolId); + if (!(prot->Info().iNamingServices & KNSInfoDatabase)) + { + User::Leave(KErrNotSupported); + } + + // Got one, make sure protocol & library are loaded + prot->LoadAndBindL(); + CleanupStack::PushL(TCleanupItem(ProtocolManager::CleanupProtocol,prot->Protocol())); + + CNetDBProvdBase *db=NULL; + db=prot->Protocol()->NewNetDatabaseL(); + + CleanupStack::PushL(db); + + // Give the host resolver the info to clean up after itself. + db->iProtocol=prot->Protocol(); + + // ask the net database provider to perform security policy checking + User::LeaveIfError(db->SecurityCheck(aPlayer->CurrentSession())); + + CNetDatabase* n=CNetDatabase::NewLC(prot, aPlayer->CurrentSession(), aPlayer, aSubSessionUniqueId); + db->SetNotify(n); +// CleanupStack::Pop(); + +// CleanupStack::PushL(TCleanupItem(CloseSubSession,n)); + + // register the protocol with the Session +// aPlayer->CurrentSessionProxyL()->AddProtocolL(prot->Protocol()); + + aPlayer->SubSessions().AppendL(n); + n->SetProvd(db); + + CleanupStack::Pop(3); + return n; + } + +CInternalSocketImpl* ProtocolManager::NewInternalSocketL ( TAny* aParams, const TDesC& aName ) + { + TServerProtocolDesc pinfo; + User::LeaveIfError(ProtocolInfo(aName,pinfo)); + return ProtocolManager::NewInternalSocketL ( aParams, pinfo.iAddrFamily, pinfo.iSockType, pinfo.iProtocol ); + } + +CInternalSocketImpl* ProtocolManager::NewInternalSocketL ( TAny* aParams, TUint aAddrFamily, TUint aSockType, TUint aProtocol ) + { + CInternalSockSubSession::TParameters* params = reinterpret_cast < CInternalSockSubSession::TParameters* > ( aParams ); + CProtocolRef* prot = FindProtocolL ( aAddrFamily, aSockType, aProtocol ); + if (!(prot->Info().iServiceTypeInfo&ESocketSupport)) + { + User::Leave(KErrNotSupported); + } + prot->LoadAndBindL (); + // Please check @NewSocketL to see why we need to push this item. + CleanupStack::PushL ( TCleanupItem ( ProtocolManager::CleanupProtocol,prot->Protocol () ) ); + CInternalSocketImpl* intSock = CInternalSocketImpl::NewL ( *params, &( prot->Info() ), prot->Protocol() ); + CleanupStack::Pop (); // prot + return intSock; + } + +TUint ProtocolManager::NumProtocols(void) + { + + return SockManGlobals::Get()->iNumProtocols; + } + +TInt ProtocolManager::ProtocolInfo(const TDesC &aName,TProtocolDesc &aProtocol) + { + TInt ret; + TServerProtocolDesc info; + + ret = ProtocolInfo(aName, info); + if (ret==KErrNone) + { + aProtocol = info; + } + return ret; + } + + +TInt ProtocolManager::ProtocolInfo(const TDesC &aName,TServerProtocolDesc &aProtocol) +/** +Find a protocol by name - no wildcard support. + +*/ + { + TSglQueIter i(*SockManGlobals::Get()->iProtocols); + + // Run the queue looking for a match. + do + { + if(((CProtocolRef *)i)->Info().iName.Compare(aName)==0) + { + aProtocol=((CProtocolRef*)i)->Info(); + return KErrNone; + } + i++; + } + while((CProtocolRef *)i); + + return KErrNotFound; + } + + +CProtocolRef* ProtocolManager::FindProtocolL(TInt anAddrFamily,TUint aSocketType,TInt aProtocol) +/** + Find a protocol from the lists. +*/ + { + + TSglQueIter i(*SockManGlobals::Get()->iProtocols); + + CProtocolRef *pP; + // Run the protocol queue looking for a match on requested socket type. + while ((pP=i++)!=NULL) + { + if (pP->Matches(anAddrFamily,aSocketType,aProtocol)) + { + return pP; + } + } + + User::Leave(KErrBadName); + return NULL; //lint !e527 // LINT knows we can't get here + } + + +CProtocolFamilyRef::CProtocolFamilyRef() + :CBase() + { + } + +CProtocolFamilyRef::~CProtocolFamilyRef() + { + if (iLibFileName) + { + delete iLibFileName; + } + } + +CProtocolFamilyRef* CProtocolFamilyRef::GetProtocolFamilyL(TDesC& aName) +/** +Either return a pointer to an existing protocol ref or create a new one. + +*/ + { + + TSglQue* families=SockManGlobals::Get()->iProtocolFamilies; + TSglQueIter i(*families); + + // Run through the list of existing protocols looking for a match. + CProtocolFamilyRef* protRef; + while(protRef=(CProtocolFamilyRef *)i,protRef) + { + if(protRef->iLibFileName->Compare(aName)==0) + { + if (protRef->iProtocolFamily) + { + return protRef; + } + else + { + break; + } + } + i++; + } + + // Not found one yet - we must create one. + if (!protRef) + { + protRef=new(ELeave) CProtocolFamilyRef; + CleanupStack::PushL(protRef); + protRef->iLibFileName=aName.AllocL(); + + // Ensure that this protocol we're about to return is loaded + protRef->LoadL(); + + // If it didn't leave, then add it to the list + families->AddLast(*protRef); + } + else + { + CleanupStack::PushL(protRef); + // Ensure that this protocol we're about to return is loaded + protRef->LoadL(); + } + + CleanupStack::Pop(); + + return protRef; + } + +void CProtocolFamilyRef::LoadL() +/** +Load the protocol. Leave it un-initted until the last minute - i.e. init it in the accessor. + +*/ + { + if (iProtocolFamily) + { + return; + } + + TAutoClose lib; + const TInt ret = lib.iObj.Load(*iLibFileName); + LOG(TBuf8<64> buf8); + LOG(buf8.Copy(iLibFileName->Des())); + LOG(ESockLog::Printf(KESockProvChoresTag, _L8("CProtocolFamilyRef(%08x)::LoadL '%S' [ret=%d]"), this, &buf8, ret)); + if(ret!=KErrNone) + { + delete iLibFileName; // cleanup after aName.AllocL + iLibFileName = NULL; + User::Leave(ret); + } + lib.PushL(); + + // The Uid check +#ifdef _UNICODE + if(lib.iObj.Type()[1]!=TUid::Uid(KUidUnicodeProtocolModule)) + { + LOG(ESockLog::Printf(_L8("FAILED uid check! (type=%08X)"), lib.iObj.Type()[1].iUid)); + User::Leave(KErrBadLibraryEntryPoint); + } +#else + if(lib.iObj.Type()[1]!=TUid::Uid(KUidProtocolModule)) + { + User::Leave(KErrBadLibraryEntryPoint); + } +#endif + + TProtocolNew libEntry=(TProtocolNew)lib.iObj.Lookup(1); + if (libEntry==NULL) + { + LOG(ESockLog::Printf(_L8("FAILED retrieving factory entrypoint (ord 1)"))); + User::Leave(KErrNoMemory); + } + + iProtocolFamily=(*libEntry)(); + if (!iProtocolFamily) + { + LOG(ESockLog::Printf(_L8("FAILED running factory entrypoint"))); + User::Leave(KErrNoMemory); + } + + // Make sure the protocol family has all the info needed to clean up after itself. + iProtocolFamily->iManagerRef=this; + TRAPD(res, iProtocolFamily->SetLibraryL(lib.iObj)); + if(res != KErrNone) + { + LOG(ESockLog::Printf(_L8("FAILED creating lib unloader (err %d)"), res)); + delete iProtocolFamily; + iProtocolFamily=0; + User::Leave(res); + } + + lib.Pop(); + lib.iObj.SetHandle(0); // Dont let ~TAutoClose() close library + } + +CProtocolFamilyBase& CProtocolFamilyRef::ProtocolFamilyL(TBool aInstall) +/** +Accessor to ProtocolFamily from manager ref - this must leave because we perform late loading and +hence must allocate memory and other nasty grubby things. + +*/ + { + if (!iProtocolFamily) + { + LoadL(); + } + __ASSERT_DEBUG(iProtocolFamily, User::Panic(KSpecAssert_ESockSSockS_MAN, 2)); + + if (aInstall && !(iFlags&EInstalled)) + { + TInt r=iProtocolFamily->Install(); + if (r!=KErrNone) + { + delete iProtocolFamily; + iProtocolFamily=0; + User::Leave(r); + } + iFlags|=EInstalled; + } + + return *iProtocolFamily; + } + +CProtocolRef::~CProtocolRef() + { + delete iTag; + } + +CProtocolRef::CProtocolRef() + :CBase() + { + } + +TBool CProtocolRef::Matches(TUint anAddrFamily,TUint aSockType,TUint aProtocol) +/** +Return ETrue if a protocol desc matches the specified family type and protocol +We allow clients to be a little hazy about their exact requirements + +*/ + { + if(iInfo.iAddrFamily==anAddrFamily && + (iInfo.iSockType==KUndefinedSockType || aSockType==KUndefinedSockType || iInfo.iSockType==aSockType) && + (iInfo.iProtocol==KUndefinedProtocol || aProtocol==KUndefinedProtocol || iInfo.iProtocol==aProtocol)) + { + return ETrue; + } + else + { + return EFalse; + } + } + + +CProtocolRef* CProtocolRef::GetProtocolNoCreate(TProtocolRefList *iProtocolList, const TDesC& aTag) +/** +Find a protocol from the lists by name +Return null if not found; +*/ + { + TSglQueIter i(*iProtocolList); + + CProtocolRef *pP = NULL; + // Run the protocol queue looking for a match on requested name + while ((pP=i++)!=NULL) + { + if (pP->iTag->Compare(aTag)==0) + { + return pP; + } + } + return NULL; + } + +CProtocolRef* CProtocolRef::GetProtocolL(const TDesC& aTag) +/** +Find a protocol from the lists by name +Will make a new ref and families if required. + +*/ + { + TSglQue* protocols=SockManGlobals::Get()->iProtocols; + + + CProtocolRef *pP = GetProtocolNoCreate(protocols,aTag); + + if (!pP) + { + pP=MakeRefL(aTag); + } + + return pP; + } + +void CProtocolRef::Cleanup(TAny* aFamily) +/** +Close a protocol family from the cleanup stack. + +*/ + { + ((CProtocolFamilyRef *)aFamily)->Close(); + } + +void CloseProtocol(TAny* aProtocol) + { + ((CProtocolBase*)aProtocol)->Close(); + } +void BindingLeave(TAny* aProtRef) + { + TUint flag=((CProtocolRef*)aProtRef)->GetFlag(); + ((CProtocolRef*)aProtRef)->SetFlag(~(CProtocolRef::EBound) & flag); + } + +void CProtocolRef::LoadL(TBool aLoadForBinding) +/** +Fill in a protocol ref - loading any libs or families +Loads and binds the requested protocol loading any libraries required. +May go recursive if a bindee needs loading and the aloadForBinding argument is set. + +*/ + { + if (iProtocol) + { + if (!aLoadForBinding) + { + CleanupStack::PushL(TCleanupItem(BindingLeave, this)); + ResolveBindingL(); + CleanupStack::Pop(); + } + return; + } + + // Three plane comms protos shouldn't be loading like this + __ASSERT_DEBUG(! (GetFlag() & CProtocolRef::EThreePlaneCommsBased), User::Panic(KSpecAssert_ESockSSockS_MAN, 3)); + + __ASSERT_DEBUG(iFamily, User::Panic(KSpecAssert_ESockSSockS_MAN, 4)); + iFamily->ProtocolFamilyL().Open(); + + CleanupStack::PushL(TCleanupItem(CProtocolRef::Cleanup,iFamily)); + + // Get the Protocol from the family + iProtocol=iFamily->ProtocolFamilyL().NewProtocolL(iInfo.iSockType,iInfo.iProtocol); + + // At this stage the iProtocol member effectively takes over control of closing + // the family reference + // Note there is a work around in TCPIP 047 which fixes the problem + // by pushing a NULL reference + CleanupStack::Pop(); + + // Make sure the protocol has the info needed to clean up after itself. + iProtocol->iManagerRef=this; + + CleanupStack::PushL(iProtocol); + if (!(iFlags & EInited)) + { + iProtocol->InitL(*iTag); + iFlags|=EInited; + } + + if (!aLoadForBinding) + { + ResolveBindingL(); + } + + CleanupStack::Pop(1); // Was pop(2) see comment above + } + +void CProtocolRef::ResolveBindingL() +/** +Resolve binding requirements for a top level (i.e service provider) protocol + +*/ + { + if (iFlags&EBound) + { + return; + } + + LoadL(ETrue); +// CESockIniData* ini=CESockIniData::NewL(); +// CleanupStack::PushL(ini); + + const CESockIniData* ini=SockManGlobals::Get()->IniData(); + DoBindingL(*ini); +// CleanupStack::PopAndDestroy(ini); + + iFlags|=EBound; + } + + +void CProtocolRef::DoBindingL(const CESockIniData& aIniFile) +/** + Actually perform the binding for a given protocol. Recursive +*/ + { + if (iFlags&EBound) + { + return; + } + + iFlags|=EBound; // Set "is bound" flag here to preempt any recursive binding. + + TPtrC bindList; + if (aIniFile.FindVar(*iTag,KBindToItemName,bindList)) + { + // BindTo scenario. Proceed with the node current node is binding to + ProcessBindListL(bindList, aIniFile); + } + + TPtrC depList; + TBool foundDep = ProtocolManager::GetDependency(*iTag,depList); + if(foundDep) + { + // BindFrom scenario. Proceed with the node that is binding from to current one + ProcessBindListL(depList, aIniFile); + } + + StartL(); + } + +void CProtocolRef::ProcessBindListL(TPtrC aBindList, const CESockIniData& aIniFile) + { + LOG( ESockLog::Printf(_L("ProcessBindListL(aBindList = %S)"), &aBindList) ); + TLex lex(aBindList); + TChar ch=0; + do + { + lex.Mark(); + do + { + ch=lex.Get(); + } + while (ch!=',' && ch!=0); + + if (ch==',') + { + lex.UnGet(); + } + + CProtocolRef* prot=GetProtocolL(lex.MarkedToken()); + lex.Get(); + prot->LoadL(ETrue); + prot->iProtocol->Open(); + + CleanupStack::PushL(TCleanupItem(CloseProtocol, prot->iProtocol)); + CleanupStack::PushL(TCleanupItem(BindingLeave, prot)); + + prot->DoBindingL(aIniFile); + prot->StartL(); + + LOG_STMT(TPtrC bindFrom = iProtocol->Tag();) + LOG_STMT(TPtrC bindTo = prot->iProtocol->Tag();) + LOG( ESockLog::Printf(_L("ProcessBindListL(Binding: %S -> %S)"), &bindFrom, &bindTo) ); + + iProtocol->BindToL(prot->iProtocol); + + CleanupStack::Pop(); + CleanupStack::PopAndDestroy(); + } + while (ch!=0); // ch == 0 when last token extracted from TLex + } + + +CProtocolRef* CProtocolRef::MakeRefL(const TDesC& aTag,CProtocolFamilyRef* aFamily,TServerProtocolDesc* anInfo) +/** +Protocol reference 'constructor'. +CProtocolRef really is a refernece and hence it runs the list of currently loaded protocols +before really and truly loading + +*/ + { + CProtocolRef* pP=new(ELeave) CProtocolRef; + CleanupStack::PushL(pP); + pP->iTag=aTag.AllocL(); + + if (aFamily==NULL && anInfo==NULL) + { + TPtrC familyName(NULL,0); + + const CESockIniData* ini=SockManGlobals::Get()->IniData(); + if (!ini->FindVar(aTag,KFilenameItemName,familyName)) + { + User::Leave(KErrBadName); + } + pP->iFamily=CProtocolFamilyRef::GetProtocolFamilyL(familyName); + + TServerProtocolDesc* protocolList; + TInt numProtocols=pP->iFamily->ProtocolFamilyL().ProtocolList(protocolList); + TInt index=0; + + if (numProtocols>1 && !ini->FindVar(aTag,KIndexTagName,index)) + { + User::Leave(KErrBadName); + } + + pP->iInfo=protocolList[index-1]; + delete[] protocolList; + } + else + { + pP->iInfo=*anInfo; + pP->iFamily=aFamily; + } + + TSglQue* protList = SockManGlobals::Get()->iProtocols; +#ifdef _DEBUG + CProtocolRef* ref = GetProtocolNoCreate(protList,aTag); + if (ref) // uhoh we have a duplicate protocol better panic in debug mode + { + LOG( ESockLog::Printf(_L("ERROR in config - duplicate protocol loaded: %S loaded more than once"),&aTag)); + Panic(EBadProtocolDescription); + } +#endif + protList->AddLast(*pP); + CleanupStack::Pop(pP); + return pP; + } + +CProtocolRef* CProtocolRef::MakeRefL(const TDesC& aName, TServerProtocolDesc* aInfo) +/** +Protocol reference 'constructor'. +This overload of is for "three plane comms" based flows only. It creates a protocol reference +that is then not subject to particular requirements of legacy protocols such as explicit +loading with `RSocketServ::StartProtocol()` +*/ + { + __ASSERT_DEBUG(aInfo, Panic(EBadProtocolDescription)); + User::LeaveIfNull(aInfo); + + // Create our protocol reference and designate it as being 3PC based + CProtocolRef* pP = new(ELeave) CProtocolRef; + pP->SetFlag(EThreePlaneCommsBased); + + CleanupStack::PushL(pP); + pP->iTag = aName.AllocL(); + pP->iInfo = *aInfo; + pP->iFamily = NULL; + + // Now add it to our global list of protocols + TSglQue* protList = SockManGlobals::Get()->iProtocols; + +#ifdef _DEBUG + CProtocolRef* ref = GetProtocolNoCreate(protList, aName); + if (ref) // uhoh we have a duplicate protocol better panic in debug mode + { + LOG( ESockLog::Printf(_L("ERROR in config - duplicate protocol loaded: %S loaded more than once"), &aName)); + Panic(EBadProtocolDescription); + } +#endif + + protList->AddLast(*pP); + CleanupStack::Pop(pP); + return pP; + } + + +void CProtocolRef::StartL() +/** +Start the protocol - only once mind lad. + +*/ + { + if (!(iFlags&EStarted)) + { + iProtocol->StartL(); + iFlags|=EStarted; + } + } + +#ifdef __FLOG_ACTIVE + +void TProtocolManagerLogger::LogLoadedInfo() + { + CSockManData* globals=SockManGlobals::Get(); + TBuf<256> descList; + TLogIgnoreOverflow16 overflow; + + TSglQueIter j(*globals->iProtocolFamilies); + CProtocolFamilyRef* f=NULL; + while(f=j++,f!=NULL) + { + if(f->iProtocolFamily) + { + descList.AppendFormat(_L(" %08x,"), &overflow, f->iProtocolFamily); + } + } + LOG( ESockLog::Printf(_L("Families (addr):%S"), &descList) ); + + descList.SetLength(0); + TSglQueIter i(*globals->iProtocols); + CProtocolRef* p=NULL; + while(p=i++,p!=NULL) + { + if(p->Protocol()) + { + const TDesC& tag(p->Tag()); + descList.AppendFormat(_L(" %S[%08x],"), &overflow, &tag, p->Family()); + } + } + LOG( ESockLog::Printf(_L("Protocols + fam addr:%S"), &descList) ); + } + +#endif