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