diff -r 000000000000 -r 29b1cd4cb562 bluetooth/btstack/linkmgr/hostresolver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bluetooth/btstack/linkmgr/hostresolver.h Fri Jan 15 08:13:17 2010 +0200 @@ -0,0 +1,511 @@ +// Copyright (c) 1999-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: +// L2CAP Host resolver. +// Implements Inquiry and Name lookup +// +// + +#ifndef L2HOSTRESOLVER_H +#define L2HOSTRESOLVER_H + + +#include +#include +#include +#include + +// BT1.1: Could make these runtime configurable. + +// HCI Inquiry length time, in 1.28 seconds. +static const TInt KInquiryLength = 10; +// Upper limit to number of results we can handle +static const TInt KInquiryMaxResults = 00; + +// Seconds between flushes +static const TInt KFlushTimeoutSecs = 5; +// Number of flushes required to actually clear a record +static const TInt KRecordDeathAge = 120; // 10 mins + + +// Maximum flushes before the a device disappears to inquires +static const TInt KRecordStaleAge = 10; // 50 secs +// Maximum flushes before the cache is set to stale (needing refresh) +static const TInt KCacheStaleAge = -1; // -1 == always needs refresh + +// While doing inquiry, set of watchdog every second +static const TInt KInquiryWatchdogPeriod = 1; +// Immidiately fetch the first 3 names +static const TInt KImmediateNameFetch = 3; + +// Page Timeout for name request, we'll initially use this for each one +static const TUint16 KMinNamePageTimeout = 0x1200; // 0x1200 = 3 secs +// Amount to increase pagetimeout, everytime a lookup fails +static const TUint16 KNamePageTimeoutIncrement = 0x140; // 0x140 = .2 sec +/** Max Page Timeout for name request, we'll consider using (ACL connects +are blocked while doing name lookup, so mustn't be too high!) **/ +static const TUint16 KMaxNamePageTimeout = 0x2500; // 0x2500 = 6 secs + +// Max times we'll try to get a single name while an inquiry pending +static const TInt KMaxNameLookupAttemptsDuringInquiry = 1; +// Max number of times to try to get a name +static const TInt KMaxNameLookupAttempts = 4; + + + +class CBTInquiryMgr; +class CBTInqResultRef; +class CLinkMgrProtocol; + + +enum TBTInqResultValid + { + EBluetoothAddr = 0x001, //000000000001 + EBluetoothCoD = 0x008, //000000001000 + EBluetoothPageScanRepMode = 0x080, //000010000000 + EBluetoothPageScanMode = 0x100, //000100000000 + EBluetoothClockOffSet = 0x200, //001000000000 + EBluetoothRssi = 0x400, //010000000000 + EBluetoothEir = 0x800, //100000000000 + EBluetoothJuice = EBluetoothCoD | + EBluetoothPageScanRepMode | + EBluetoothPageScanMode | + EBluetoothClockOffSet + }; + + +/** + BT Inquiry Result record. + Ref counted object, deletes itself when no more CBTInqResultRef objects + point to it. Aggregates the TInquiryLogEntry type. +**/ + +NONSHARABLE_CLASS(CBTInqResultRecord) : public CBase + { +friend class CBTInquiryMgr; +friend class CBTInqResultRef; + +public: + TInquiryLogEntry& LogEntry(); + void SetName(const TDesC8& aName); + const TDesC8& Name() const; + TBool IsNameRequestPending() const; + void SetNamePending(TBool aBool); + TBool IsNameRefreshRequested() const; + void SetNameRefreshRequested(TBool aBool); + TBool IsNameComplete() const; + void SetNameComplete(TBool aBool); + TBool IsExplicitNameRequest() const; + void SetExplicitNameRequest(TBool aBool); + TBool IsNameValid() const; + void SetNameValid(TBool aBool); + void SetNameLookupResultCode(TInt aResultCode); + TBool HaveNameLookupResult() const; + TInt NameLookupResultCode() const; + TInt NameLookupAttempts() const; + TInt IncFlushes(); + void GetInquirySockAddr(TInquirySockAddr& aAddr); + TInt GetEir(TNameRecord& aNameRec, TBool aIgnoreCachedName); + TInt GetName(TNameRecord& aNameRec); + TInt AddIAC(TUint aIAC); + TBool HasRespondedToIAC(TUint aIAC); + TInt NumberOfIACsRespondedTo(); + void ClearIACs(); + inline TBool IsJuiceFromHCI() { return (EBluetoothJuice == (iJuiceFromHCIMask & EBluetoothJuice)); };//for the moment demand all + inline TBool IsPageScanModeFromHCI() { return iJuiceFromHCIMask & EBluetoothPageScanMode; }; + inline TBool IsPageScanRepModeFromHCI() { return iJuiceFromHCIMask & EBluetoothPageScanRepMode; }; + inline TBool IsCoDFromHCI() { return iJuiceFromHCIMask & EBluetoothCoD; }; + inline TBool IsClockOffsetFromHCI() { return iJuiceFromHCIMask & EBluetoothClockOffSet; } + inline TBool IsEirPresent() { return iJuiceFromHCIMask & EBluetoothEir; } + inline TExtendedInquiryResponseDataCodec& Codec() { return iCodec; } + +private: + enum TNameStatus + { + ENamePending = 1, + ENameRefreshRequested = 2, + ENameComplete = 4, + ENameExplicitRequest = 8, // An explicit name lookup has been requested, so don't put this to the back of the queue + }; + + ~CBTInqResultRecord(); + // Interface for CBTInquiryMgr + CBTInqResultRecord(const TBTDevAddr& aAddr); + // Interface for CBTInqResultRef + void Open(); + void Close(); + + // Number of CBTInqResultRef objects pointing to this result + TInt iRefCount; + // The actual inquiry log entry. It contains EIR data, RSSI value and old style TInquiryLogEntry. + TInquiryLogEntryWithEir iEntry; + // The device name's state + TInt iNameStatus; //Bit flag + // The result of name lookup, of >0 if one hasn't been done + TInt iNameLookupResultCode; + // The device's name (if known), it can be from EIR or a Remote Name Request + TBuf8 iName; + // Number of attempts made at getting name. + TInt iNameLookupAttempts; + // Flush cycles since last seen (lower == newer). + TInt iFlushes; + // IACs this device has responded to + RArray iIACs; + // Has inquiry log entry been populated by inquiry? + TUint16 iJuiceFromHCIMask; + // Has this entry been found during the current, ongoing inquiry? + TBool iFoundDuringCurrentInquiry; + + TExtendedInquiryResponseDataCodec iCodec; + }; + +/** + Inquiry result reference. + References a CBTInqResultRecord. +**/ +NONSHARABLE_CLASS(CBTInqResultRef) : public CBase + { +public: + CBTInqResultRef(CBTInqResultRef& aRef); + CBTInqResultRef(CBTInqResultRecord& aRec); + ~CBTInqResultRef(); + CBTInqResultRecord& Result() const; + +private: + // The pointer to actual CBTInqResultRecord + CBTInqResultRecord& iRecord; +public: + // List to go on a view, in CBTInqResultSet + TDblQueLink iLink; + }; + +/** + BT Inquiry Result Set. + A view onto a set of the current inquiry results. +**/ +NONSHARABLE_CLASS(CBTInqResultSet) : public CBase + { +public: + CBTInqResultSet(); + ~CBTInqResultSet(); + void Reset(); + CBTInqResultRef* Add(CBTInqResultRecord& aRec); + CBTInqResultRef* FindEntry(const TBTDevAddr& aAddr); + CBTInqResultRef* NextResult(); + CBTInqResultRef* CurrentResult(); + void ReturnToFirstResult(); + TBool IsEmpty(); + void MoveToback(CBTInqResultRef& aRef); +private: + typedef TDblQue TResultRefQue; + typedef TDblQueIter TResultQueIter; + TResultRefQue iResultRefs; + TResultQueIter iNextRefIter; + CBTInqResultRef* iCurrentResult; + }; + +NONSHARABLE_STRUCT(TInquiryCacheAge) + { +public: + TUint iIAC; + TInt iCacheAge; + }; + +/** + BT Host resolver. + Represents one client host resolver session. + Only implements GetByAddress, as this is all the + BT API supports. +**/ +NONSHARABLE_CLASS(CBTHostResolver) : public CHostResolvProvdBase + { +public: + enum TInquiryStatus + { + EInquiryReady, + EInquiring, + EInquiryComplete + }; + enum TNameLookupMode + { + EDontGetNames, + EDoGetNames + }; + + enum TRequestState + { + EIdle, + EInquiry, + ENameLookup, + ESetLocalName, + EGetLocalName, + EError // LC added + }; + + CBTHostResolver(CBTInquiryMgr& aInquiryMgr); + ~CBTHostResolver(); + // From CHostResolvProvdBase + void GetByName(TNameRecord& aName); + void GetByAddress(TNameRecord& aName); + void SetHostName(TDes& aNameBuf); + void GetHostName(TDes& aNameBuf); +// Need this to allow instantiation. Doesn't seem to be callable though! +// Simply stub it, as we don't actually care... + virtual TInt SetOption(TUint aLevel, TUint aName, const TDesC8& aOption); + + // From CResolverProvdBase + void CancelCurrentOperation(); + + // IquiryMgr interface + void InquiryResult(CBTInqResultRecord& aResult); + void NameLookupResult(TInt aErr, const TBTDevAddr& aAddr, const TDesC8& aName); + void InquiryComplete(TInt aErr); + void SetLocalNameComplete(TInt aErr); + void GetLocalNameComplete(TInt aErr, const TDesC8& aName); + + TUint GetIAC() const; + inline static TInt LinkOffset() {return _FOFF(CBTHostResolver, iLink);} + + //From CResolverProvdBase + TInt SecurityCheck(MProvdSecurityChecker *aSecurityChecker); +private: + void TryToCompleteRequest(); + void CompleteRequest(TInt aErr); + void CompleteCurrentOperation(); + + CBTInquiryMgr& iInquiryMgr; + // The record we're currently retreiving + TNameRecord* iNameRecord; + // the buffer we get host name into + TDes* iHostNameBuf; + + // Current user request. + TRequestState iRequestState; + // Status of the on-going inquiry process + TInquiryStatus iInquiryStatus; + // Get names or not? + TNameLookupMode iNameLookupMode; + // Error code... Only valid when iInquiryStatus == EInquiryComplete + TInt iInqCompletionCode; + // Set of devices found, to be returned to client + CBTInqResultSet iResults; + // Member of Q in InquiryMgr. + TDblQueLink iLink; + //Mixin providing security checking, This is not an owned variable. + MProvdSecurityChecker* iSecurityChecker; + }; + +#ifdef CONNECTION_PREEMPTS_INQUIRY +class CConnectingStatusSubscriber; +#endif + +/** + BT Inquiry Manager. + Singleton object that manages host resolvers, inquiries, and + name lookups. +**/ +NONSHARABLE_CLASS(CBTInquiryMgr) : public CBase, public MHCICommandQueueClient + { +public: + // Interface for CL2CAPProtocol + ~CBTInquiryMgr(); + static CBTInquiryMgr* NewL(CLinkMgrProtocol& aProtocol); + CBTHostResolver* NewHostResolverL(); + + void SetHCICommandQueue(MHCICommandQueue& aCommandQueue); + void ClearHCICommandQueue(); + + void ClockOffsetResult(const TBTDevAddr& aAddr, TBasebandTime aClockOffset); + void CoDResult(const TBTDevAddr& aConn, TUint aCoD); + + void SetLocalNameComplete(TInt aErr); + void GetLocalNameComplete(TInt aErr, const TDesC8& aName); + void Suspend(); + void Resume(); + void SetInquiryMode(); + + +#ifdef _DEBUG + void IncrementHRCount() {++iNumHRs;}; + void DecrementHRCount() {--iNumHRs;}; +#endif + + // Interface for CBTHostResolver + void StartInquiry(CBTHostResolver& aResolver, TUint aIAC, TBool aIgnoreCache); + void LookupName(CBTHostResolver& aResolver, const TBTDevAddr& aAddr, TBool aIgnoreCache, TBool aExplicitNameRequest); + void ClearCache(); + TInt SetLocalName(const TDesC8& aName); + TInt GetLocalName(); + CBTInqResultRef* FindExistingCacheEntry(const TBTDevAddr& aAddr); + CBTInqResultRef* AddEntryToCache(const TBTDevAddr& aAddr); + CBTInqResultRef* AddEntryWithJuiceToCache(const TInquiryLogEntry& aEntry); + CBTInqResultRef* AddEntryWithCoDToCache(const TBTDevAddr& aAddr, const TUint aCoD); + CBTInqResultRef* AddEntryWithClockOffsetToCache(const TBTDevAddr& aAddr, const TBasebandTime aClockOffset); + const TDesC8* DeviceNameFromCache(const TBTDevAddr& aAddr); + CBTInqResultRecord* BasebandParametersFromCache(const TBTDevAddr& aAddr); + void DeletingHostResolver(); + + enum THWState + { + EIdle = 0, + EInquiry, + ENameLookup, + EConnecting, // can't do anything really! +// EConnected // can't do anything ? + EOff, + ECancellingForNewIAC, + }; + + THWState HWState(){ return iHWState; } + void SetHWState(THWState aState); + void PublishStatus(); + + void CompleteCommands(TInt aErr); + TBool IsExtendedInquiryResponseSupported(); + + // commands sent to the controller -- called from external classes + void ReadRemoteNameL(const TBTDevAddr& aAddr); + +private: // Handling logical inquiry events + void WriteInquiryModeComplete(TBool aSucceeded); + void InquiryResult(TInt aErr,const TInquiryLogEntry& aEntry); + void InquiryComplete(TInt aErr, TUint8 aNumResponses); + void RemoteNameResult(TInt aErr, const TBTDevAddr& aAddr, const TBTDeviceName8& aBuf); + void RemoteHostSupportedFeatures(TInt aErr, const TBTDevAddr& aAddr, const TUint64& aHostSupportedFeatures); + +private: // from MHCICommandQueueClient + virtual void MhcqcCommandEventReceived(const THCIEventBase& aEvent, const CHCICommandBase* aRelatedCommand); + virtual void MhcqcCommandErrored(TInt aErrorCode, const CHCICommandBase* aCommand); + +private: // HCI event handling functions + // basic types + void CommandCompleteEvent(const THCIEventBase& aEvent); + void CommandStatusEvent(const THCIEventBase& aEvent, const CHCICommandBase& aCommand); + + // first class events + void InquiryResultEvent(const THCIEventBase& aEvent); + void InquiryResultWithRSSIEvent(const THCIEventBase& aEvent); + void ExtendedInquiryResultEvent(const THCIEventBase& aEvent); + void InquiryCompleteEvent(const THCIEventBase& aEvent); + void RemoteNameReqCompleteEvent(const THCIEventBase& aEvent); + void RemoteHostSupportedFeaturesNotificationEvent(const THCIEventBase& aEvent); + + // command complete events + void WriteInquiryModeOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent); + void ReadLocalNameOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent); + void InquiryCancelOpcode(THCIErrorCode aHciErr, const THCIEventBase& aEvent); + +private: + CBTInquiryMgr(CLinkMgrProtocol& aProtocol); + void ConstructL(); + + MHCICommandQueue& CommandQueue() const; + + // commands sent to the controller + void CancelInquiryL(); + void CancelRemoteNameL(const TBTDevAddr& aAddr); + void StartInquiryL(TUint aIAC, TUint8 aLength, TUint8 aNumResponses); + void WriteInquiryModeL(TUint8 aInquiryMode); + void LookupNameL(const TInquiryLogEntry& aEntry); + void ReadLocalNameL(); + + void DoInquiry(); + void DoNameLookup(TBool aInquiryComplete); + void HandleRemoteNameResult(TInt aErr, CBTInqResultRef& aRef, const TBTDeviceName8& aBuf); + void TryToInterruptInquiryForNameLookup(); + void UpdateNotifiers(const TBTDevAddr& aAddr, const TDesC8& aName); + void ClearCurrentInquiryResults(); + TInt CancelHardwareInquiry(); + TInt StartHardwareInquiry(); + + static TInt InquiryWatchdog(TAny* aPtr); + static TInt Flush(TAny* aPtr); + void DoFlush(); + void EnableFlusher(); + + TInt CacheAge(TUint aIAC) const; + void SetCacheAge(TUint aIAC, TInt aAge); + +private: + MHCICommandQueue* iCommandQueue; + + // Singleton owner of us + CLinkMgrProtocol& iLinkMgrProtocol; + + // What the hardware is currently up to (as far as we know) + THWState iHWState; + // IAC of the current inquiry + TUint iCurrentInquiryIAC; + // IAC of the inquiry that is currently requested by a host resolver, either in progress or about to start + TUint iRequestedInquiryIAC; + // IAC of the inquiry that has been put on hold while a higher priority IAC is in progress + TUint iQueuedInquiryIAC; + // Number of times we've interrupted the current inquiry + TInt iInquiryInteruptions; + // Time since the last inquiry, per IAC + RArray iCacheAge; + // Timer to age records and the cache itself + CPeriodic* iFlusher; + // Results since watchdog last went off + TInt iResultCount; + // Number of watchdogs seeing 0 devices + TInt iInquirySilenceCount; + // Number of name requests pending + TInt iPendingNameRequests; + // True is there are new page requests pending + TInt iNewPageRequestsPending; + // Current name request pagetimeout + TUint16 iNamePageTimeout; + // Current Inquiry Mode + TUint8 iInquiryMode; + // Pending Inquiry Mode + TUint8 iPendingInquiryMode; + + CBTInqResultSet iCurrentResults; + TDblQue iHRs; + + TBool iReportedInquiryState; // what did we last tell the Inquiry state P&S key +#ifdef CONNECTION_PREEMPTS_INQUIRY + // Monitors if a ACL connection is currently being established. + CConnectingStatusSubscriber* iConnectingStatus; +#endif + +#ifdef _DEBUG + TInt iNumHRs; // no Count() in que's - handy to have +#endif + }; + +#ifdef CONNECTION_PREEMPTS_INQUIRY +// ******************************************************************* +// ACL Connecting status subscriber +// ******************************************************************* +NONSHARABLE_CLASS(CConnectingStatusSubscriber) : public CActive + { +public: + static CConnectingStatusSubscriber* NewL(CBTInquiryMgr& aInquiryMgr); + ~CConnectingStatusSubscriber(); + +private: + CConnectingStatusSubscriber(CBTInquiryMgr& aInquiryMgr); + void ConstructL(); + void Subscribe(); + + void RunL(); + void DoCancel(); + + CBTInquiryMgr& iParent; + RProperty iProperty; + }; +#endif // CONNECTION_PREEMPTS_INQUIRY + +#endif