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

📄 btservertoclient.cpp

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

#include "bluetoothtransport.h"


CBtServerToClient* CBtServerToClient::NewL(MTransportObserver& aObserver, const TDesC& aProtocolName)
/**
	@param	aObserver		Observer to notify about transport events.
							This is managed by the CTransport superclass.
	@param	aProtocolName	Whether this function should connect over
							L2CAP ("L2CAP") or RFCOMM ("RFCOMM").
	@return					Connected transport that communicates with
							a remote device over Bluetooth.  This is owned
							by the caller.
 */
	{
	CBtServerToClient* self = new(ELeave) CBtServerToClient(aObserver);
	CleanupStack::PushL(self);
	self->ConstructL(aProtocolName);
	CleanupStack::Pop(self);
	return self;
	}

CBtServerToClient::CBtServerToClient(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 CBtServerToClient::ConstructL(const TDesC& aProtocolName)
/**
	Implement CBluetoothTransport by creating an accept socket,
	advertising the OandX service via SDP, and waiting for a remote
	device to connect.
	
	This function returns when it has accepted an incoming connection,
	or leaves when an error has occurred.

	This function is called from CBluetoothTransport::ConstructL which
	has already connected to the socket server.
	
	@param	aProtocolName	Protocol over which this server should provide
							the OandX service.  This can be "L2CAP" (KL2CAPDesC)
							"RFCOMM" (KRFCOMMDesC).
 */
	{
	TRAN_LOG1(">CBtServerToClient::ConstructL,\"%S\"", &aProtocolName);
	__BTT_ASSERT((aProtocolName == KL2CAPDesC || aProtocolName == KRFCOMMDesC), ESvToClCtlUnrecProto);

	ConnectToSocketServerL();
	
	TInt channel = CreateListenChannelL(aProtocolName);

	TUint protocolValue = (aProtocolName == KL2CAPDesC) ? KL2CAP : KRFCOMM;
	
	// open a blank socket which which exchange data with remote device
	iBtSocket = CBluetoothSocket::NewL(*this, iSocketServ);
	iListenSocket->Accept(*iBtSocket);
	
	BuildSdpRecordL(protocolValue, channel);
	
	// dialog will be dismissed by user selecting cancel, or by HandleAcceptCompleteL
	TInt r = (! iObserver.StartedWaitingForClientL()) ? KErrCancel : iAcceptError;
	User::LeaveIfError(r);

	CTransport::ConstructL(/*aInitListen*/ EFalse);
	TRAN_LOG0("<CBtServerToClient::ConstructL");
	}

TInt CBtServerToClient::CreateListenChannelL(const TDesC& aProtocolName)
/**
	Create a listen socket which waits for incoming connections.

	@param	aProtocolName	Protocol over which this server should provide
							the OandX service.  This can be "L2CAP" (KL2CAPDesC)
							"RFCOMM" (KRFCOMMDesC).
	@return					L2CAP or RFCOMM channel which has been reserved
							for the connection.
 */
	{
	TRAN_LOG1(">CBtServerToClient::CreateListenChannelL,\"%S\"", &aProtocolName);
	
	iListenSocket = CBluetoothSocket::NewL(*this, iSocketServ, aProtocolName);

	// 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);

	TInt r;
	if (aProtocolName == KL2CAPDesC)
		{
		TL2CAPSockAddr l2SockAddr;				// find an available L2CAP channel
		l2SockAddr.SetPort(KL2CAPPassiveAutoBind);
		l2SockAddr.SetSecurity(oandxSecurity);
		r = iListenSocket->Bind(l2SockAddr);
		}
	else	// if (aProtocolName == KRFCOMMDesC)
		{
		TRfcommSockAddr rfSockAddr;				// find an available RFCOMM channel
		rfSockAddr.SetPort(KRfcommPassiveAutoBind);
		rfSockAddr.SetSecurity(oandxSecurity);
		r = iListenSocket->Bind(rfSockAddr);
		}
	
	// accept one incoming connection on this socket
	if (r == KErrNone)
		r = iListenSocket->Listen(/*qSize*/ 1);
	User::LeaveIfError(r);

	// get automatically bound channel (port) number
	TInt channel = iListenSocket->LocalPort();
	
	TRAN_LOG1("<CBtServerToClient::CreateListenChannelL,ch=%d", channel);
	return channel;
	}

void CBtServerToClient::BuildSdpRecordL(TUint aProtocol, TInt aChannel)
/**
	Publish an SDP record with a service name, service description, and
	protocol descriptor list to advertise this service.
	
	@param	aProtocol		Which protocol is used, i.e. KL2CAP or KRFCOMM.
	@param	aChannel		Which channel is used by the protocol.  This is a PSM
							for L2CAP and an RFCOMM channel for RFCOMM.
 */
	{
	TInt r = iSdp.Connect();
	if (r == KErrNone)
		r = iSdpDb.Open(iSdp);
	User::LeaveIfError(r);
	
	// create service record and get record handle, KSdpAttrIdServiceRecordHandle == 0x0
	iSdpDb.CreateServiceRecordL(iServiceUuid, iServRecHandle);
	
	// describe connection as protocol descriptor list, KSdpAttrIdProtocolDescriptorList == 0x4
	CSdpAttrValueDES* protoDesc =
			(aProtocol == KL2CAP)
		?	BuildL2CapProtocolDescriptorListLC(aChannel)
		:	BuildRfcommProtocolDescriptorListLC(aChannel);
	iSdpDb.UpdateAttributeL(iServRecHandle, KSdpAttrIdProtocolDescriptorList, *protoDesc);
	CleanupStack::PopAndDestroy(protoDesc);
	
	// set service name in primary language
	// (KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceName) == (0x100 + 0) == 0x100
	iSdpDb.UpdateAttributeL(
		iServRecHandle,
		KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceName,
		KOandXServiceName);

	// set up service description in primary language
	// (KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceDescription) == (0x100 + 1) == 0x101
	iSdpDb.UpdateAttributeL(
		iServRecHandle,
		KSdpAttrIdBasePrimaryLanguage + KSdpAttrIdOffsetServiceDescription,
		KOandXServiceDesc);
	}

CSdpAttrValueDES* CBtServerToClient::BuildL2CapProtocolDescriptorListLC(TInt aChannel)
/**
	Construct an ((L2CAP, channel)) protocol descriptor list.

	@param	aChannel		The L2CAP channel, i.e. PSM, on which the service is run.
	@return					An initialized protocol descriptor list attribute value, suitable
							for adding to an SDP record.  The caller owns this object.
 */
	{
	CSdpAttrValueDES* protoDesc = CSdpAttrValueDES::NewDESL(NULL);
	CleanupStack::PushL(protoDesc);
	
	TSdpIntBuf<TUint16> channelBuf(static_cast<TUint16>(aChannel));
	protoDesc
		->StartListL()
		->BuildDESL()
			->StartListL()
			->BuildUUIDL(KL2CAP)		// 0x0100
			->BuildUintL(channelBuf)	// 0x0003
			->EndListL()
		->EndListL();
	return protoDesc;
	}

CSdpAttrValueDES* CBtServerToClient::BuildRfcommProtocolDescriptorListLC(TInt aChannel)
/**
	Construct an ((L2CAP, RFCOMM-PSM) (RFCOMM, channel)) protocol descriptor list.

	@param	aChannel		The RFCOMM channel,on which the service is run.
	@return					An initialized protocol descriptor list attribute value, suitable
							for adding to an SDP record.  The caller owns this object.
 */
	{
	// rfcommconsts.h is not available in the SDK, so define RFCOMM PSM value here.
	// (This value is assigned in S4.2 of BLUETOOTH SPECIFICATION Version 2.0 + EDR [vol 4].
	const TInt KRFCOMMPSM = 0x03;  /// The PSM on which RFCOMM resides

	CSdpAttrValueDES* protoDesc = CSdpAttrValueDES::NewDESL(NULL);

	TSdpIntBuf<TUint16> l2capChannelBuf(static_cast<TUint16>(KRFCOMMPSM));
	TSdpIntBuf<TUint8> channelBuf(static_cast<TUint16>(aChannel));
	CleanupStack::PushL(protoDesc);
	protoDesc
		->StartListL()
		->BuildDESL()
			->StartListL()
			->BuildUUIDL(KL2CAP)			// 0x0100
			->BuildUintL(l2capChannelBuf)	// 0x0003
			->EndListL()
		->BuildDESL()
			->StartListL()
			->BuildUUIDL(KRFCOMM)			// 0x0003
			->BuildUintL(channelBuf)
			->EndListL()
		->EndListL();
	return protoDesc;
	}

CBtServerToClient::~CBtServerToClient()
/**
	Cancel any outstanding request and free resources used by this layer.
 */
	{
	TRAN_LOG0(">CBtServerToClient::~CBtServerToClient");
	Cancel();
	
	// remove SDP record
	TRAN_LOG0("-CBtServerToClient::~CBtServerToClient,sdp");
	if (iSdpDb.SubSessionHandle() != KNullHandle && iServRecHandle != 0)
		{
		TRAP_IGNORE(iSdpDb.DeleteRecordL(iServRecHandle));
		}
	iSdpDb.Close();
	iSdp.Close();
	
	FreeDataSocket();
	delete iListenSocket;
	
	TRAN_LOG0("<CBtServerToClient::~CBtServerToClient");
	}


// -------- implement MBluetoothSocketNotifier  --------

void CBtServerToClient::HandleAcceptCompleteL(TInt aErr)
/**
	Implement MBluetoothSocketNotifier by dismissing the waiting-for-client
	dialog and recording any error code.

	@param	aErr			Symbian OS error code.
 */
	{
	TRAN_LOG1(">CBtServerToClient::HandleAcceptCompleteL,aErr=%d", aErr);
	iAcceptError = aErr;
	iObserver.StoppedWaitingForClient();
	TRAN_LOG0("<CBtServerToClient::HandleAcceptCompleteL");
	}

⌨️ 快捷键说明

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