⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btclienttoserver.cpp

📁 Symbian OS C++ for Mobile Phones Volume 3 源码
💻 CPP
字号:
// Copyright (c) 2004 - 2007, Symbian Software Ltd. All rights reserved.

#ifndef __SERIES60_3X__
	#include <qbtselectdlg.hrh>
	#include <qbtselectdlg.h>
#endif

#include "bluetoothtransport.h"


// -------- (de)allocation --------

CBtClientToServer* CBtClientToServer::NewL(MTransportObserver& aObserver)
/**
	Factory function allocates new, connected transport.

	@param	aObserver		Observer to notify about transport events.
							This is managed by the CTransport superclass.
	@return					Connected transport that communicates with
							a remote server over Bluetooth.  This is owned
							by the caller.
 */
	{
	CBtClientToServer* self = new(ELeave) CBtClientToServer(aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CBtClientToServer::CBtClientToServer(MTransportObserver& aObserver)
/**
	This constructor is defined to initialize the superclass with the
	supplied observer.

	@param	aObserver		Observer to notify about transport events.
							This is managed by the CTransport superclass.
 */
:	CBluetoothTransport(aObserver)
	{
	// empty.
	}

void CBtClientToServer::ConstructL()
/**
	Initialize this device as a client by selecting a device via the UI;
	searching its SDP records for the OandX service; and connecting
	to the host device.
 */
	{
	TRAN_LOG0(">CBtClientToServer::ConstructL");
	
	ConnectToSocketServerL();
	
	TBTDevAddr devAddr;
	AskUserToSelectHostL(devAddr);

	iProtocolChannel = -1;	// indicate no channel found
	FindProtocolDescriptionL(devAddr);
	
	// dialog will be dismissed by user or FinishedSearching
	TInt r = (! iObserver.StartedLookingForServiceL()) ? KErrCancel : iSdpError;
	User::LeaveIfError(r);
	
	// open the socket and connect it to the remote device
	iBtSocket = CBluetoothSocket::NewL(*this, iSocketServ, *iProtocolName);
	
	TBTSockAddr btSockAddr;
	btSockAddr.SetBTAddr(devAddr);
	btSockAddr.SetPort(iProtocolChannel);

	// channel security settings.  No authentication, authorisation, or encryption.
	TBTServiceSecurity oandxSecurity;
	oandxSecurity.SetUid(KUidServiceSDP);
	oandxSecurity.SetAuthentication(EFalse);	// don't require key (PIN) exchange
	oandxSecurity.SetAuthorisation(ETrue);		// require local user to confirm accept
	oandxSecurity.SetEncryption(EFalse);
	oandxSecurity.SetDenied(EFalse);
	btSockAddr.SetSecurity(oandxSecurity);

	r = iBtSocket->Connect(btSockAddr);
	User::LeaveIfError(r);

	// dialog will be dismissed by user or from HandleConnectCompleteL
	r = (! iObserver.StartedConnectingToServiceL()) ? KErrCancel : iConnectError;
	User::LeaveIfError(r);

	CTransport::ConstructL(/*aInitListen*/ ETrue);
	TRAN_LOG0("<CBtClientToServer::ConstructL");
	}

void CBtClientToServer::AskUserToSelectHostL(TBTDevAddr& aDevAddr)
/**
	Ask the user to select a Bluetooth device with the platform-specific
	notifier dialog.
	
	@param	aDevAddr		On success this is set to the remote device's address.
 */
	{
	TRAN_LOG0(">CBtClientToServer::AskUserToSelectHostL");
	TInt r;

#ifdef __SERIES60_3X__	
	// ask user to select a device via the extended notifier server
	RNotifier ntf;
	r = ntf.Connect();
	User::LeaveIfError(r);
	
	TRequestStatus rs;
	
	// filter displayed devices by those which support the OandX service.
	// (This may not be supported by the UI.)
	TBTDeviceSelectionParamsPckg devFilter;
	devFilter().SetUUID(iServiceUuid);
	
	TBTDeviceResponseParamsPckg response;
	
	ntf.StartNotifierAndGetResponse(rs, KDeviceSelectionNotifierUid, devFilter, response);
	User::WaitForRequest(rs);
	ntf.Close();

	// ensure a valid device was selected
	r = rs.Int();
	if (r == KErrNone && ! response().IsValidDeviceName())
		r = KErrNotFound;
	User::LeaveIfError(r);
	
	aDevAddr = response().BDAddr();
	
#else

	// select a single device with the UIQ dialog
	CBTDeviceArray* btDevArray = new (ELeave)CBTDeviceArray(1);
	BTDeviceArrayCleanupStack::PushL(btDevArray);
	
	CQBTUISelectDialog* btUiSelDlg = CQBTUISelectDialog::NewL(btDevArray);
	TInt dlgRet = btUiSelDlg->RunDlgLD(KQBTUISelectDlgFlagNone);
	
	TRAN_LOG1("-CBtClientToServer::AskUserToSelectHostL,dlgRet=%d", dlgRet);
	if (dlgRet != EBTDeviceSelected)
		r = KErrNotFound;
	else
		{
		const CBTDevice* dev = (*btDevArray)[0];
		if (! dev->IsValidBDAddr())
			r = KErrNotFound;
		else
			{
			aDevAddr = dev->BDAddr();
			r = KErrNone;
			}
		}
	
	User::LeaveIfError(r);
	CleanupStack::PopAndDestroy(btDevArray);
#endif

	TRAN_LOG0("<CBtClientToServer::AskUserToSelectHostL");
	}

void CBtClientToServer::FindProtocolDescriptionL(const TBTDevAddr& aDevAddr)
/**
	Search the supplied device's SDP database for the OandX SDP record.
	If found, the protocol and its channel are put in iProtocolName and
	iProtocolChannel respectively.
	
	iSdpError is set to KErrNone if the search is successful, or another
	error code otherwise.
	
	@param	aDevAddr		Remote device's address.
 */
	{
	TRAN_LOG0(">CBtClientToServer::FindProtocolDescriptionL");
	
	iSdpAgent = CSdpAgent::NewL(/* MSdpAgentNotifier& */ *this, aDevAddr);

	// only process SDP entries which match the OandX service class
	CSdpSearchPattern* searchPattern = CSdpSearchPattern::NewL();
	CleanupStack::PushL(searchPattern);
	searchPattern->AddL(iServiceUuid);
	iSdpAgent->SetRecordFilterL(*searchPattern);
	CleanupStack::PopAndDestroy(searchPattern);
	
	iSdpAgent->NextRecordRequestL();
	// completes in NextRecordRequestComplete

	TRAN_LOG0("<CBtClientToServer::FindProtocolDescriptionL");
	}

void CBtClientToServer::FinishedSearching(TInt aError)
/**
	This function is called when finished parsing remote SDP records.
	It closes the looking-for-service dialog.

	@param	aError			Symbian OS error code.
 */
	{
	// SDP agent no longer required so clean up
	delete iSdpAgent;
	iSdpAgent = 0;
	
	if (aError != KErrEof)		// KErrEof == parsed all matching records
		iSdpError = aError;
	else
		{
		// did we discover the protocol and channel?
		
		if (iProtocolName != 0 && iProtocolChannel != -1)
			iSdpError = KErrNone;
		else
			iSdpError = KErrNotFound;
		}
	
	iObserver.StoppedLookingForService();
	}

CBtClientToServer::~CBtClientToServer()
/**
	Cancel any outstanding operations and free resources used by this object.
 */
	{
	Cancel();
	delete iSdpAgent;
	FreeDataSocket();
	}


// -------- implement MSdpAgentNotifier --------

void CBtClientToServer::NextRecordRequestComplete(TInt aError, TSdpServRecordHandle aHandle, TInt aTotalRecordsCount)
/**
	Implement MSdpAgentNotifier by extracting the protocol descriptor list attribute.
	
	@param	aError			Symbian OS error code.  This is KErrEof if there are
							no more SDP records to parse.
	@param	aHandle			Service record which was retrieved from remote device.
	@param	aTotalRecordsCount Total number of matching records.  Not used.
 */
	{
	(void) aTotalRecordsCount;
	TRAN_LOG3(">CBtClientToServer::NextRecordRequestComplete,err=%d,h=0x%x,c=%d", aError, aHandle, aTotalRecordsCount);
	
	if (aError == KErrNone)
		{
		TRAP(aError, iSdpAgent->AttributeRequestL(aHandle, KSdpAttrIdProtocolDescriptorList));
		}

	if (aError != KErrNone)
		FinishedSearching(aError);

	TRAN_LOG0("<CBtClientToServer::NextRecordRequestComplete");
	}

void CBtClientToServer::AttributeRequestResult(TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID, CSdpAttrValue* aAttrValue)
/**
	Implement MSdpAgentNotifier by processing the supplied attribute.
	The supplied attribute must describe the protocol descriptor list because
	of the attribute selection in NextRecordRequestComplete.
	
	@param	aHandle			The service's record handle, as set by the remote device.  Not used.
	@param	aAttrID			The attribute ID.  See BLUETOOTH SPECIFICATION Version 2.0 + EDR [vol 4]
							Section 5 for a list of attribute IDs.  Not used.
	@param	aAttrValue		The attribute's value.  This function supplies itself as an
							MSdpAttributeValueVisitor to read the protocol descriptor list.
							This function takes ownership of the value object and must delete it.
 */
	{
	(void) aHandle;
	(void) aAttrID;
	TRAN_LOG3(">CBtClientToServer::AttributeRequestResult,h=0x%x,id=0x%x,type=%d", aHandle, aAttrID, aAttrValue->Type());
	
	TRAPD(r, aAttrValue->AcceptVisitorL(/* MSdpAttributeValueVisitor */ *this));
	if (r != KErrNone)
		FinishedSearching(r);

	delete aAttrValue;

	TRAN_LOG0("<CBtClientToServer::NextRecordRequestComplete");
	}

void CBtClientToServer::AttributeRequestComplete(TSdpServRecordHandle aHandle, TInt aError)
/**
	Implement MSdpAgentNotifier by searching the next record for its protocol descriptor list.
	
	@param	aHandle			The service's record handle, as set by the remote device.  Not used.
	@param	aError			Symbian OS error code.
 */
	{
	(void) aHandle;
	TRAN_LOG2(">CBtClientToServer::AttributeRequestComplete,h=0x%x,err=%d", aHandle, aError);
	
	if (aError == KErrNone)
		{
		TRAP(aError, iSdpAgent->NextRecordRequestL());
		}
	
	if (aError != KErrNone)
		FinishedSearching(aError);
	
	TRAN_LOG0("<CBtClientToServer::AttributeRequestComplete");
	}


// -------- implement MSdpAttributeValueVisitor --------

void CBtClientToServer::VisitAttributeValueL(CSdpAttrValue& aValue, TSdpElementType aType)
/**
	Implement MSdpAttributeValueVisitor by extracting protocol type and channel number.
	
	The protocol descriptor list contains ((L2CAP, PSM)) if using an L2CAP channel, and
	((L2CAP, RFCOMM-PSM) (RFCOMM, rfcomm-channel)) if using an RFCOMM channel.
	The attributes in a DES are passed to this function in the order in which they occur
	in the list, so the RFCOMM protocol and value will overwrite the L2CAP protocol and
	channel if it appears.

	(This won't catch the malformed case (L2CAP, RFCOMM-PSM) (RFCOMM) but the subsequent
	connection will fail if RFCOMM-PSM isn't a valid RFCOMM channel.)
	
	@param	aValue			The attribute's value.  This function extracts the value as
							an UUID to identify the protocol, or as an integer to identify
							the channel.
	@param	aType			The value's type.
 */
	{
	TRAN_LOG1(">CBtClientToServer::VisitAttributeValueL,type=%d", aType);
	
	switch (aType)
		{
	case ETypeUUID:
		{
		const TUUID protocolUuid = aValue.UUID();
		if (protocolUuid == TUUID(KL2CAP))
			iProtocolName = &KL2CAPDesC;
		else if (protocolUuid == TUUID(KRFCOMM))
			iProtocolName = &KRFCOMMDesC;
		else
			User::Leave(KErrNotSupported);
		TRAN_LOG1("-CBtClientToServer::VisitAttributeValueL,iProtocolName=%S", iProtocolName);
		}
		break;
	
	case ETypeUint:
		iProtocolChannel = aValue.Uint();
		TRAN_LOG1("-CBtClientToServer::VisitAttributeValueL,iProtocolChannel=%d", iProtocolChannel);
		break;
	
	default:
		// ignore other attribute types.
		break;
		}
	
	TRAN_LOG0("<CBtClientToServer::VisitAttributeValueL");
	}

void CBtClientToServer::StartListL(CSdpAttrValueList& aList)
/**
	Implement MSdpAttributeValueVisitor by doing nothing.
	When this function returns, VisitAttributeValueL will be called
	for every value in the list.
	
	@param	aList			The list which is being visited.
	@see VisitAttributeValueL
	@see EndListL
 */
	{
	(void) aList;
	// empty.
	}

void CBtClientToServer::EndListL()
/**
	Implement MSdpAttributeValueVisitor by doing nothing.

	@see VisitAttributeValueL
	@see StartListL
 */
	{
	// empty.
	}


// -------- partially implement MBluetoothSocketNotifier, override CBluetoothTransport --------

void CBtClientToServer::HandleConnectCompleteL(TInt aErr)
/**
	Implement MBluetoothSocketNotifier by dismissing the
	connecting dialog.  Flow control returns to ConstructL.

	@param	aErr			Symbian OS error code.  This is stored in iConnectError.
 */
	{
	iConnectError = aErr;
	iObserver.StoppedConnectingToService();
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -