00001 /* 00002 Copyright (c) 2002-2011 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 00003 00004 Redistribution and use in source and binary forms, with or without 00005 modification, are permitted provided that the following conditions are met: 00006 00007 * Redistributions of source code must retain the above copyright notice, this 00008 list of conditions and the following disclaimer. 00009 * Redistributions in binary form must reproduce the above copyright notice, 00010 this list of conditions and the following disclaimer in the documentation 00011 and/or other materials provided with the distribution. 00012 * Neither the name of Nokia Corporation nor the names of its contributors 00013 may be used to endorse or promote products derived from this software 00014 without specific prior written permission. 00015 00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 00020 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00021 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00022 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00023 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 00024 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00025 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 00027 Description: 00028 */ 00029 00030 00031 // INCLUDE FILES 00032 00033 #include "BluetoothServiceSearcher.h" 00034 #include "common.hrh" 00035 /* 00036 ============================================================================ 00037 CBluetoothServiceSearcher's constructor 00038 ============================================================================ 00039 */ 00040 CBluetoothServiceSearcher::CBluetoothServiceSearcher(MBluetoothServiceSearcherObserver& aObs) 00041 : iObserver(aObs), iPort(KPort), iFoundRfcommProtocol(EFalse) 00042 { 00043 } 00044 00045 /* 00046 ============================================================================ 00047 CBluetoothServiceSearcher's destructor 00048 ============================================================================ 00049 */ 00050 CBluetoothServiceSearcher::~CBluetoothServiceSearcher() 00051 { 00052 delete iSdpSearchPattern; 00053 00054 if (iAgent) 00055 { 00056 iAgent->Cancel(); 00057 delete iAgent; 00058 } 00059 } 00060 00061 /* 00062 ============================================================================ 00063 Retrives from a remote device a SDP's service record. 00064 On completion calls NextRecordRequestComplete. 00065 ============================================================================ 00066 */ 00067 void CBluetoothServiceSearcher::FindServiceByUUIDL(const TBTDevAddr& aTarget, const TUUID& aUUID) 00068 { 00069 /* 00070 ============================================================================ 00071 Deletes any previous existing SDP agent and search pattern 00072 ============================================================================ 00073 */ 00074 delete iSdpSearchPattern; 00075 iSdpSearchPattern = NULL; 00076 delete iAgent; 00077 iAgent = NULL; 00078 /* 00079 ============================================================================ 00080 Bluetooth's service class records are stored into the SDP database. 00081 In order to access/get SDP's records you need to use CSdpAgent. 00082 CSdpAgent can only been used if the address of a remote Bluetooth device has been identified. 00083 Also the class using CSdpAgent must implement the MSdpAgentNotifier interface in order 00084 to handle SDP's responses. See SDK for more details about CSdpAgent and MSdpAgentNotifier 00085 ============================================================================ 00086 */ 00087 iAgent=CSdpAgent::NewL(*this,aTarget); 00088 /* 00089 ============================================================================ 00090 In order to retrive only the SDP record you are interested in, SDP provides the filter 00091 CSdpSearchPattern. CSdpSearchPattern is an array of TUUID (Bluetooth Universally Unique Identifier) 00092 that uniquelly identifies a service class. 00093 Adding a service class to the filter is done by calling subsequentially CSdpSearchPattern::AddL(). 00094 In our example we are interested only in seeing if the remote device provides the RPS service, but you could 00095 for example ask the SDP server to return all Bluetooth services that support the RFCOMM protocol. 00096 After adding all the TUUID you are interested in into CSdpSearchPattern you need to move it into 00097 CSdpAgent by calling CSdpAgent::SetRecordFilterL(). 00098 ============================================================================ 00099 */ 00100 iSdpSearchPattern=CSdpSearchPattern::NewL(); 00101 iSdpSearchPattern->AddL(aUUID); 00102 iAgent->SetRecordFilterL(*iSdpSearchPattern); 00103 /* 00104 ============================================================================ 00105 We now need to get the handle of the record on the remote device that matches the service class we set previously in 00106 CSdpSearchPattern. You need to use CSdpAgent::NextRecordRequestL(). NextRecordRequestL() is an asynchronous function 00107 and when completed it will call the callback NextRecordRequestComplete() from the MSdpAgentNotifier interface 00108 passed in the NewL. Note that as mention above CSdpSearchPattern could contain more then one service class TUUID and you can get 00109 the next (if available) service record by calling subsequently NextRecordRequestL(). 00110 ============================================================================ 00111 */ 00112 iAgent->NextRecordRequestL(); 00113 } 00114 00115 /* 00116 ============================================================================ 00117 Called when a service record request (CSdpAgent::NextRecordRequestComplete()) operation is completed 00118 ============================================================================ 00119 */ 00120 void CBluetoothServiceSearcher::NextRecordRequestComplete(TInt aError,TSdpServRecordHandle aHandle,TInt aTotalRecordsCount) 00121 /* 00122 ================================================================================= 00123 NextRecordRequestComplete is invoked each time a complete full SDP service record is retrieved from the remote Bluetooth target. 00124 NextRecordRequestComplete is the CSdpAgent::NextRecordRequestL's callback 00125 If there is no error, we then invoke CSdpAgent::AttributeRequestL to browse the attributes of the SDP record. 00126 If there are no more records to browse then the error will be KErrEof. 00127 ================================================================================= 00128 */ 00129 { 00130 TBool terminated=EFalse; 00131 00132 if(aError == KErrNone) 00133 { 00134 if(aTotalRecordsCount==0) 00135 { 00136 /* 00137 ================================================================================= 00138 This covers the case where CSdpAgent::NextRecordRequestL didn't find any SDP's records matching our RPS's service class 00139 ================================================================================= 00140 */ 00141 iObserver.OnServiceSearchComplete(iPort, KErrNotFound); 00142 } 00143 else 00144 { 00145 iPort=KPort; 00146 /* 00147 ================================================================================= 00148 If there are SDP's records containing our class service, we need to browse the SDP record to retrive 00149 the port of the service. The port is then used with the remote BT's address by the Master in order to connect to the slave. 00150 CSdpAgent::AttributeRequestL is an asynchronous call. When the attributes have been retrived from the remote device then it 00151 calls AttributeRequestResult from the MSdpAgentNotifier interface. AttributeRequestL takes two parameters: the first one 00152 is the handle of the SDP's record that is a TUint32 (TSdpServRecordHandle) and the second parameter is one of the "Universal Attributes" 00153 defined in btsdp.h; in our example we use KSdpAttrIdProtocolDescriptorList because we are only interested in SDP's record that 00154 contains the RFCOMM protocol. Note that there is another overload AttributeRequestL where the search is done 00155 with a range of attibutes instead of only one. You need to use AttributeRequestL(TSdpServRecordHandle aHandle, const CSdpAttrIdMatchList& aMatchList), 00156 where CSdpAttrIdMatchList is the list of attributes you want to filter. Also you can use your own builder class in order 00157 to browse the SDP's record attributes. In this case you need to use 00158 AttributeRequestL(MSdpElementBuilder* aBuilder, TSdpServRecordHandle aHandle, TSdpAttributeID aAttrID) for a single attribute or 00159 AttributeRequestL(MSdpElementBuilder* aBuilder,TSdpServRecordHandle aHandle,const CSdpAttrIdMatchList& aMatchList) 00160 for a range of attributes. If you don't want to provide your own MSdpElementBuilder then you can use directly 00161 CSdpAttrValue returned from AttributeRequestResult. See below. 00162 ================================================================================= 00163 */ 00164 TRAPD(err, iAgent->AttributeRequestL(aHandle,KSdpAttrIdProtocolDescriptorList)); 00165 if(err != KErrNone) 00166 { 00167 iObserver.OnServiceSearchComplete(iPort, err); 00168 } 00169 } 00170 } 00171 else 00172 { 00173 /* 00174 ================================================================================= 00175 This covers the case where there are no more SDP's records left to be read (KErrEof) or an SDP's error occurs. 00176 ================================================================================= 00177 */ 00178 iObserver.OnServiceSearchComplete(iPort, aError); 00179 terminated=ETrue; 00180 } 00181 } 00182 00183 /* 00184 ============================================================================ 00185 Called when an attribute request (CSdpAgent::AttributeRequestL()) wants to pass up a result 00186 ============================================================================ 00187 */ 00188 void CBluetoothServiceSearcher::AttributeRequestResult(TSdpServRecordHandle /*aHandle*/, TSdpAttributeID /*aAttrID*/, CSdpAttrValue* aAttrValue) 00189 { 00190 /* 00191 ================================================================================= 00192 AttributeRequestResult is invoked each time an attribute-value is retrieved from the SDP record. AttributeRequestResult is the CSdpAgent::AttributeRequestL's callback. 00193 We need to browse the attribute-value to decide whether we have a match with our initial requirements 00194 CSdpAttrValue::AcceptVisitorL passes the attribute value to the VisitAttributeValueL callback 00195 from MSdpAttributeValueVisitor 00196 ================================================================================= 00197 */ 00198 TRAPD(err,aAttrValue->AcceptVisitorL(*this)); 00199 if(err != KErrNone) 00200 { 00201 iObserver.OnServiceSearchComplete(iPort, err); 00202 } 00203 } 00204 00205 /* 00206 ============================================================================ 00207 Called to pass an attribute value 00208 ============================================================================ 00209 */ 00210 void CBluetoothServiceSearcher::VisitAttributeValueL(CSdpAttrValue &aValue, TSdpElementType aType) 00211 { 00212 /* 00213 ================================================================================= 00214 Here we browse the attributes to see if we have a match with our initial requirements. 00215 In our case we are interested only in RPS's services that used only the KRFCOMM protocol. If there is a match 00216 then we need to get the port of the RPS's service. VisitAttributeValueL is called for each 00217 attribute. When all the attributes have been browsed then AttributeRequestComplete callback below is called. 00218 ================================================================================= 00219 */ 00220 switch(aType) 00221 { 00222 case ETypeUUID: 00223 if(aValue.UUID() == TUUID(KRFCOMM)) 00224 { 00225 iFoundRfcommProtocol = ETrue; 00226 } 00227 break; 00228 case ETypeUint: 00229 if(iFoundRfcommProtocol) 00230 { 00231 //get the RFCOMM's service port number 00232 iPort=aValue.Uint(); 00233 iFoundRfcommProtocol = EFalse; 00234 } 00235 break; 00236 default: 00237 break; 00238 } 00239 } 00240 00241 /* 00242 ================================================================================= 00243 Called when an attribute request (CSdpAgent::AttributeRequestL()) wants to signal the completion of 00244 an attribute request. 00245 ================================================================================= 00246 */ 00247 void CBluetoothServiceSearcher::AttributeRequestComplete(TSdpServRecordHandle /*aHandle*/, TInt aError) 00248 { 00249 /* 00250 ================================================================================= 00251 In our example we finish on the first match but you can use iAgent->NextRecordRequestL() to search for 00252 another record (if any). 00253 ================================================================================= 00254 */ 00255 iObserver.OnServiceSearchComplete(iPort, aError); 00256 } 00257 00258 /* 00259 ================================================================================= 00260 Indicates that subsequent elements added belong to a DES or DEA 00261 ================================================================================= 00262 */ 00263 void CBluetoothServiceSearcher::StartListL(CSdpAttrValueList& /*aList*/) 00264 { 00265 //From MSdpAttributeValueVisitor. 00266 //Not used 00267 } 00268 00269 /* 00270 ================================================================================= 00271 Indicates the end of a list started by StartListL(). 00272 ================================================================================= 00273 */ 00274 void CBluetoothServiceSearcher::EndListL() 00275 { 00276 //From MSdpAttributeValueVisitor. 00277 //Not used 00278 }