bluetooth/btstack/linkmgr/hostresolver.h
changeset 0 29b1cd4cb562
child 23 5b153be919d4
--- /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 <bt_sock.h>
+#include <es_prot.h>
+#include <bluetooth/hcicommandqueue.h>
+#include <bluetooth/hcicommandqueueclient.h>
+
+// 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<KHCIRemoteDeviceNameMaxLength>	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<TUint>		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<CBTInqResultRef> TResultRefQue;
+	typedef TDblQueIter<CBTInqResultRef> 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<TInquiryCacheAge> 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<CBTHostResolver>		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