--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetooth/btexample/example/sdap/src/btexchange.cpp Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,344 @@
+// Copyright (c) 2005-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 <e32base.h>
+#include <e32std.h>
+#include "exchange.h"
+#include "btexchange.h"
+
+
+//Dll entry
+EXPORT_C TInt _E32Dll()
+ {
+ return KErrNone;
+ }
+
+//Construction
+/**
+@internalComponent
+Factory function that constructs a CBluetoothExchanger object.
+@param aUUID
+The Universally Unique IDentifier of the service that is provided
+and should be searched for.
+@return The constructed object
+*/
+EXPORT_C CBluetoothExchanger* CBluetoothExchanger::NewL(const TUUID &aUUID)
+ {
+ CBluetoothExchanger* self = CBluetoothExchanger::NewLC(aUUID);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+@internalComponent
+Factory function that constructs a CBluetoothExchanger object.
+@param aUUID
+The Universally Unique IDentifier of the service that is provided
+and should be searched for.
+@return The constructed object
+*/
+EXPORT_C CBluetoothExchanger* CBluetoothExchanger::NewLC(const TUUID &aUUID)
+ {
+ CBluetoothExchanger* self = new(ELeave) CBluetoothExchanger;
+ CleanupStack::PushL(self);
+ self->ConstructL(aUUID);
+ return self;
+ }
+
+/**
+@internalComponent
+Initialises the class, and registers the service with the SDP database service.
+@param aUUID
+The Universally Unique IDentifier of the service that is provided
+and should be searched for.
+@leave If SDP registration fails, the function leaves.
+*/
+void CBluetoothExchanger::ConstructL(const TUUID &aUUID)
+ {
+ TSdpServRecordHandle recordHandle = 0;
+ User::LeaveIfError(iSdpSession.Connect());
+ User::LeaveIfError(iSdpDb.Open(iSdpSession));
+ iSdpDb.CreateServiceRecordL(aUUID, recordHandle);
+ //Service record with mandatory attributes now exists - maybe add others to it
+
+ iSockSession.Connect();
+ iSeeker = CBluetoothSeeker::NewL (iSockSession, aUUID);
+ }
+
+//Destruction
+CBluetoothExchanger::~CBluetoothExchanger()
+ {
+ iSdpDb.Close();
+ iSdpSession.Close();
+ }
+
+//Overrides of pure virtuals from CExchanger
+
+//Inquiry & SDP implementation
+/**
+@internalComponent
+Uses Inquiry and SDP to retrieve a list of peer devices which support
+the UUID that was registered during construction.
+The functionality is implemented by the CBluetoothSeeker active object.
+@param aStatus
+A TRequestStatus object that is signalled when the search is complete.
+@leave Leaves if the bluetooth protocols required can't be loaded.
+*/
+EXPORT_C void CBluetoothExchanger::LookForPeersL(TRequestStatus &aStatus)
+ {
+ //This is handled by the seeker class that we own.
+ iSeeker->BeginUpdateL(aStatus);
+ }
+
+/**
+@internalComponent
+@return
+The count of devices that were found by the search.
+@pre
+A LookForPeersL search must have sucessfully completed
+*/
+EXPORT_C TInt CBluetoothExchanger::Count()
+ {
+ return iSeeker->Names().Count();
+ }
+
+/**
+@internalComponent
+Selects the first device that was found
+*/
+EXPORT_C void CBluetoothExchanger::First()
+ {
+ iDeviceIndex = 0;
+ }
+
+/**
+@internalComponent
+Retrieves the selected device, and selects the next device
+that was found.
+@param aPtr
+A reference to a TNameEntry* pointer. On success, it is filled
+in with a pointer to a device that was found.
+@return KErrNotFound on failure, KErrNone on success.
+*/
+EXPORT_C TInt CBluetoothExchanger::Next(TNameEntry*& aPtr)
+ {
+ if(iDeviceIndex >= Count())
+ return (KErrNotFound);
+ aPtr = &(iSeeker->Names()[iDeviceIndex++]);
+ return KErrNone;
+ }
+
+// CBluetoothSeeker
+_LIT(KBluetoothSeekerClassName, "CBluetoothSeeker");
+
+// construction
+CBluetoothSeeker::CBluetoothSeeker(RSocketServ &aSession) : CActive(CActive::EPriorityStandard), iSession(aSession), iNames(4)
+ {
+ iState = EIdle;
+ }
+
+CBluetoothSeeker::~CBluetoothSeeker()
+ {
+ iResolver.Close();
+ delete iSdpAgent;
+ delete iSdpSearchPattern;
+ }
+
+CBluetoothSeeker* CBluetoothSeeker::NewLC(RSocketServ &aSession, const TUUID &aUUID)
+ {
+ CBluetoothSeeker* self = new(ELeave) CBluetoothSeeker(aSession);
+ CleanupStack::PushL(self);
+ self->ConstructL(aUUID);
+ return self;
+ }
+
+CBluetoothSeeker* CBluetoothSeeker::NewL(RSocketServ &aSession, const TUUID &aUUID)
+ {
+ CBluetoothSeeker* self = CBluetoothSeeker::NewLC(aSession, aUUID);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CBluetoothSeeker::ConstructL(const TUUID &aUUID)
+ {
+ iSdpSearchPattern = CSdpSearchPattern::NewL();
+ iSdpSearchPattern->AddL(aUUID);
+ CActiveScheduler::Add(this);
+ }
+
+void CBluetoothSeeker::RunL()
+ {
+ switch(iState)
+ {
+ case EInquiring:
+ HandleInquiryResultL();
+ break;
+ case EServiceRequest:
+ SDPQueryL();
+ break;
+ default:
+ //RunL in bad state
+ User::Panic(KBluetoothSeekerClassName, KErrGeneral);
+ break;
+ }
+ }
+
+TInt CBluetoothSeeker::RunError(TInt aErr)
+ {
+ //Complete any outstanding request with an error.
+ if(iUpdateStatus)
+ {
+ User::RequestComplete(iUpdateStatus,aErr);
+ }
+ return KErrNone;
+ }
+
+void CBluetoothSeeker::DoCancel()
+ {
+ switch(iState)
+ {
+ case EInquiring:
+ iResolver.Cancel();
+ break;
+ case EServiceRequest:
+ delete iSdpAgent;
+ iSdpAgent = NULL;
+ break;
+ default:
+ break;
+ }
+ User::RequestComplete(iUpdateStatus, KErrCancel);
+ }
+
+void CBluetoothSeeker::BeginUpdateL(TRequestStatus &aStatus)
+ {
+ TProtocolDesc pInfo;
+ _LIT(KLinkMan, "BTLinkManager");
+ TProtocolName name(KLinkMan);
+ User::LeaveIfError(iSession.FindProtocol(name,pInfo));
+ if(IsActive())
+ {
+ User::Leave(KErrInUse);
+ }
+ //First, start an inquiry
+ User::LeaveIfError(iResolver.Open(iSession,pInfo.iAddrFamily,pInfo.iProtocol));
+
+ iInquiryAddress.SetIAC(KGIAC);
+ iInquiryAddress.SetAction(KHostResInquiry);
+ iResolver.GetByAddress(iInquiryAddress, iNameEntry, iStatus);
+ SetActive();
+ iState = EInquiring;
+ iUpdateStatus = &aStatus;
+ *iUpdateStatus = KRequestPending;
+ }
+
+CArrayFixFlat<TNameEntry>& CBluetoothSeeker::Names()
+ {
+ return iNames;
+ }
+
+void CBluetoothSeeker::HandleInquiryResultL()
+ {
+ if(iStatus.Int() == KErrNone)
+ {
+ //We found another device, add it to the list
+ iNames.AppendL(iNameEntry);
+ iResolver.Next(iNameEntry, iStatus);
+ SetActive();
+ }
+ else if(iStatus.Int() == KErrHostResNoMoreResults)
+ {
+ //No more results, so now start SDP checks
+ if(iNames.Count() == 0)
+ {
+ //No devices found by inquiry, so complete request now with a failure
+ User::RequestComplete(iUpdateStatus, KErrNotFound);
+ iState = EIdle;
+ }
+ else
+ {
+ //Some devices found, filter them by whether they support this service
+ iDeviceIndex = 0;
+ iState = EServiceRequest;
+ SDPQueryL();
+ }
+ }
+ else
+ {
+ //Some other error - fail the request
+ User::RequestComplete(iUpdateStatus, iStatus.Int());
+ iState = EIdle;
+ }
+ }
+
+void CBluetoothSeeker::SDPQueryL()
+ {
+ delete iSdpAgent;
+ iSdpAgent = NULL;
+ if(iDeviceIndex < iNames.Count())
+ {
+ TBTSockAddr* addr = (TBTSockAddr *)&((iNames[iDeviceIndex])().iAddr);
+ iSdpAgent = CSdpAgent::NewL(*this, addr->BTAddr());
+ iSdpAgent -> SetRecordFilterL(*iSdpSearchPattern);
+ iSdpAgent -> NextRecordRequestL();
+ // We signal ourselves when the callback completes
+ iStatus = KRequestPending;
+ SetActive();
+ }
+ else
+ {
+ //No more devices, set final status
+ User::RequestComplete(iUpdateStatus, KErrNone);
+ }
+ }
+
+//virtual overrides from MSdpAgentNotifier
+void CBluetoothSeeker::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle /*aHandle*/, TInt aTotalRecordsCount)
+ {
+ if(aError != KErrNone || aTotalRecordsCount == 0)
+ {
+ //This device doesnt support the service we are looking for
+ //or SDP failed and we can't tell that it does.
+ //Either way, remove it from our list of supported peers.
+ iNames.Delete(iDeviceIndex);
+ }
+ else
+ {
+ //This device does support the service we are looking for
+ //(Attribute requests would be done here if implemented)
+
+ //While we are connected anyway (due to SDP), do a name request
+ //- its almost free at this point, so use the synchronous version
+ TInquirySockAddr &addr = TInquirySockAddr::Cast(iNames[iDeviceIndex]().iAddr);
+ addr.SetAction(KHostResName);
+ iResolver.GetByAddress(addr, iNames[iDeviceIndex]);
+ //move on and check the next device.
+ iDeviceIndex++;
+ }
+ //Signal ourself to process the next one
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status,KErrNone);
+ }
+
+void CBluetoothSeeker::AttributeRequestResult(TSdpServRecordHandle , TSdpAttributeID , CSdpAttrValue* )
+ {
+ //should never be called (not currently used)
+ User::Panic(KBluetoothSeekerClassName, KErrNotSupported);
+ }
+void CBluetoothSeeker::AttributeRequestComplete(TSdpServRecordHandle, TInt )
+ {
+ //should never be called (not currently used)
+ User::Panic(KBluetoothSeekerClassName, KErrNotSupported);
+ }