?? btservertoclient.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 + -