bluetooth/btstack/sdp/sdpclient.cpp
changeset 0 29b1cd4cb562
child 48 22de2e391156
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <bluetooth/logger.h>
       
    17 #include <bt_sock.h>
       
    18 #include <btsdp.h>
       
    19 #include "sdp.h"
       
    20 #include "sdpnetdb.h"
       
    21 #include "sdppdu.h"
       
    22 #include "sdpstackutil.h"
       
    23 #include "sdpclient.h"
       
    24 
       
    25 #ifdef __FLOG_ACTIVE
       
    26 _LIT8(KLogComponent, LOG_COMPONENT_SDP);
       
    27 #endif
       
    28 
       
    29 CSdpClient::CSdpClient(CSdpProtocol& aProtocol, CProtocolBase& aL2CAP)
       
    30 	: iNetDbProviders(_FOFF(CSdpNetDbProvider, iLink)),
       
    31 	iOutboundQ(_FOFF(CSdpPdu, iLink)),
       
    32 	iProtocol(aProtocol),
       
    33 	iL2CAP(aL2CAP)
       
    34 	{
       
    35 	TCallBack cb(IdleTimerExpired, this);
       
    36 	iIdleTimerEntry.Set(cb);
       
    37 	}
       
    38 
       
    39 void CSdpClient::ConstructL()
       
    40 	{
       
    41 	iBoundSAP=iL2CAP.NewSAPL(KSockSeqPacket);
       
    42 	iBoundSAP->SetNotify(this);
       
    43 	CheckForIdle(KSDPIdleTimeout*4);// No point hanging about if no one connects
       
    44 	}
       
    45 
       
    46 CSdpClient* CSdpClient::NewL(CSdpProtocol& aProt, CProtocolBase& aL2CAP)
       
    47 	{
       
    48 	CSdpClient* self = new(ELeave) CSdpClient(aProt, aL2CAP);
       
    49 	CleanupStack::PushL(self);
       
    50 	self->ConstructL();
       
    51 	CleanupStack::Pop();
       
    52 	return self;
       
    53 	}
       
    54 
       
    55 CSdpClient::~CSdpClient()
       
    56 	{
       
    57 	delete iNextPacket;
       
    58 	delete iBoundSAP;
       
    59 	while (!iOutboundQ.IsEmpty())
       
    60 		{
       
    61 		delete iOutboundQ.First();
       
    62 		}
       
    63 	while (!iNetDbProviders.IsEmpty())
       
    64 		{// Tell any lingering netdb's that we're gone.
       
    65 		iNetDbProviders.First()->ClientDown();
       
    66 		// Note -- this will cause idle timer to be re-queued, 
       
    67 		// so we must cancel it *after* taking netdbs down.
       
    68 		}
       
    69 	CancelIdleTimer();
       
    70 	}
       
    71 
       
    72 /****************************************************************************/
       
    73 /* 
       
    74    Commands from protocol
       
    75 */
       
    76 
       
    77 void CSdpClient::Open(TBTDevAddr& aAddr)
       
    78 /**
       
    79     Create lower-layer link to the remote device.
       
    80    
       
    81 	The bound sap will be used to
       
    82     create an L2CAP link to the remote end over which the SDP
       
    83     PDUs will flow.  The client will then run this channel.
       
    84 **/
       
    85 	{
       
    86 	__ASSERT_DEBUG(!ChannelUp(), Panic(ESdpClientAlreadyConnected));
       
    87 	iRemoteAddr=aAddr;
       
    88 	iBoundSAP->AutoBind();
       
    89 	TL2CAPSockAddr remote;
       
    90 	remote.SetBTAddr(aAddr);
       
    91 	remote.SetPort(KSDPPSM);  // Always 0x01
       
    92 	if(iBoundSAP->SetRemName(remote)!=KErrNone)
       
    93 		{
       
    94 		Panic(ESdpErrorSettingAddress);
       
    95 		}
       
    96 	iBoundSAP->ActiveOpen();  // Signals ConnectComplete eventually!
       
    97 	}
       
    98 
       
    99 void CSdpClient::AddNetDbProvider(CSdpNetDbProvider& aNetDbProvider)
       
   100 	{
       
   101 	CancelIdleTimer();
       
   102 	iNetDbProviders.AddFirst(aNetDbProvider);
       
   103 	if (ChannelUp())
       
   104 		aNetDbProvider.ClientUp();
       
   105 	}
       
   106 
       
   107 void CSdpClient::RemoveNetDbProvider(CSdpNetDbProvider& aNetDbProvider)
       
   108 	{
       
   109 	
       
   110    	if(!iOutboundQ.IsEmpty())
       
   111 		{
       
   112 
       
   113 		CSdpPdu* request = iOutboundQ.First();
       
   114 		CSdpNetDbProvider* netdb = request->NetDbProvider();
       
   115 		if(netdb == &aNetDbProvider)
       
   116 			request->iNetDbProvider = 0;
       
   117 
       
   118 		TDblQueIter<CSdpPdu> iter(iOutboundQ);
       
   119 		while(iter)
       
   120 			{
       
   121 			request = iter++;
       
   122 			if(request->NetDbProvider()==&aNetDbProvider)
       
   123 				//NB 1st one is NULL so won't be deleted
       
   124 				delete request;
       
   125 			}
       
   126 		}
       
   127 
       
   128 	aNetDbProvider.iLink.Deque();
       
   129 	if (iNetDbProviders.IsEmpty())
       
   130 		{
       
   131 		CheckForIdle(KSDPIdleTimeout);
       
   132 		}
       
   133 	}
       
   134 
       
   135 /****************************************************************************/
       
   136 /* 
       
   137    Commands for netdb provider
       
   138 */
       
   139 
       
   140 inline TUint8 DEHeader(TUint8 aType, TUint8 aSizeIndex)
       
   141 /**
       
   142 	Make a data element header from aType and aSizeIndex.
       
   143 	aType occupies top 5 bits, aSizeIndex the bottom 3 bits.
       
   144 **/
       
   145 	{// Move aType 3 bits across.
       
   146 	return (TUint8)((aType << 3) | (aSizeIndex & 0x7));
       
   147 	}
       
   148 
       
   149 void CSdpClient::ServiceSearchRequest(CSdpNetDbProvider& aNetDbProvider,
       
   150 		TUint16 aMaxCount, const TUUID &aUUID, const TDesC8& aContState)
       
   151 	{
       
   152 	if (!ChannelUp())
       
   153 		{
       
   154 		aNetDbProvider.Error(KErrSdpClientNotConnected);
       
   155 		return;
       
   156 		}
       
   157 	CSdpPdu* pdu = new CSdpPdu(&aNetDbProvider);
       
   158 	if (!pdu)
       
   159 		{
       
   160 		aNetDbProvider.Error(KErrNoMemory);
       
   161 		return;
       
   162 		}
       
   163 
       
   164 	TPtrC8 uuid(aUUID.ShortestForm());
       
   165 	TInt len = uuid.Length();
       
   166 	TUint8 szIndex = 0;
       
   167 	while (len >>= 1)
       
   168 		++szIndex;
       
   169 	__ASSERT_DEBUG(uuid.Length() == (1<<szIndex), Panic(ESdpBadUUID));
       
   170 
       
   171 	pdu->SetPduId(EServiceSearchRequest);
       
   172 	pdu->SetTransid(NextTransId());
       
   173 	pdu->PutByte(DEHeader(6,5));  // Header: DES, 1 byte length
       
   174 	pdu->PutByte(TUint8(1+uuid.Length()));// Size: Length of one UUID element
       
   175 	pdu->PutByte(DEHeader(3,szIndex)); //	 Header: 'len' byte UUID
       
   176 	pdu->PutData(uuid);			  //   Data: The UUID
       
   177 	pdu->PutBigEndian16(aMaxCount);	// Maximum Service record count
       
   178 	pdu->PutByte((TUint8)aContState.Length());	// Cont state length
       
   179 	pdu->PutData(aContState);
       
   180 	pdu->SetLength();
       
   181 	EnqueOutboundPdu(*pdu);
       
   182 	}
       
   183 
       
   184 void CSdpClient::ServiceAttributeRequest(CSdpNetDbProvider& aNetDbProvider,
       
   185 		TUint aRecordHandle, TUint16 aMaxLength, TBool aRange,
       
   186 		TUint aAttribute, const TDesC8& aContState)
       
   187 	{
       
   188 	if (!ChannelUp())
       
   189 		{
       
   190 		aNetDbProvider.Error(KErrSdpClientNotConnected);
       
   191 		return;
       
   192 		}
       
   193 	CSdpPdu* pdu = new CSdpPdu(&aNetDbProvider);
       
   194 	if (!pdu)
       
   195 		{
       
   196 		aNetDbProvider.Error(KErrNoMemory);
       
   197 		return;
       
   198 		}
       
   199 
       
   200 	pdu->SetPduId(EServiceAttributeRequest);
       
   201 	pdu->SetTransid(NextTransId());
       
   202 	pdu->PutBigEndian32(aRecordHandle);
       
   203 	pdu->PutBigEndian16(aMaxLength);
       
   204 	pdu->PutByte(DEHeader(6,5));        // Header: DES, 1 byte length
       
   205 	if (aRange)
       
   206 		{// Range of attribute IDs. Send 1 4-byte uint.
       
   207 		pdu->PutByte(5);			    // Size: Length of 16 uint element
       
   208 		pdu->PutByte(DEHeader(1,2));    //	 Header: 4 byte integer
       
   209 		pdu->PutBigEndian32(aAttribute);//   Attribute ID range
       
   210 		}
       
   211 	else
       
   212 		{// Single attribute ID. Send 1 2-byte uint.
       
   213 		pdu->PutByte(3);			    // Size: Length of 32 uint element
       
   214 		pdu->PutByte(DEHeader(1,1));    //	 Header: 2 byte integer
       
   215 		pdu->PutBigEndian16(static_cast<TUint16>(aAttribute));//   Single attribute ID
       
   216 		}
       
   217 	pdu->PutByte(static_cast<TUint8>(aContState.Length()));	// Cont state length
       
   218 	pdu->PutData(aContState);
       
   219 	pdu->SetLength();
       
   220 	EnqueOutboundPdu(*pdu);
       
   221 	}
       
   222 
       
   223 void CSdpClient::EncodedRequest(CSdpNetDbProvider& aNetDbProvider,
       
   224 								TUint8 aPduRequestId,
       
   225 								const TDesC8& aEncodedData)
       
   226 	{
       
   227 	if (!ChannelUp())
       
   228 		{
       
   229 		aNetDbProvider.Error(KErrSdpClientNotConnected);
       
   230 		return;
       
   231 		}
       
   232 	CSdpPdu* pdu = new CSdpPdu(&aNetDbProvider);
       
   233 	if (!pdu)
       
   234 		{
       
   235 		aNetDbProvider.Error(KErrNoMemory);
       
   236 		return;
       
   237 		}
       
   238 
       
   239 	pdu->SetPduId(aPduRequestId);
       
   240 	pdu->SetTransid(NextTransId());
       
   241 	pdu->PutData(aEncodedData);
       
   242 	pdu->SetLength();
       
   243 	EnqueOutboundPdu(*pdu);
       
   244 	}
       
   245 
       
   246 
       
   247 /****************************************************************************/
       
   248 /* 
       
   249    Protocol MSocketNotify functions
       
   250    Upcalls from L2CAP
       
   251 */
       
   252 void CSdpClient::NewData(TUint aCount)
       
   253 /**
       
   254 	New data arrived on lower SAP.
       
   255 	Read out the data straight away.
       
   256 	@param	aCount Number of packets that have arrived.
       
   257 **/
       
   258 	{
       
   259 	LOG1(_L("SDP: New data, count %d"), aCount);
       
   260 
       
   261 	TPckgBuf<TInt> mru;
       
   262 	TInt err = iBoundSAP->GetOption(KSolBtL2CAP, KL2CAPInboundMTU, mru);
       
   263 	if (err == KErrNone && (!iNextPacket || mru() > iNextPacket->Size()))
       
   264 		{
       
   265 		delete iNextPacket;
       
   266 		iNextPacket = HBufC8::New(mru());
       
   267 		if (iNextPacket == 0)
       
   268 			{
       
   269 			err = KErrNoMemory;
       
   270 			}
       
   271 		}
       
   272 	if(err)
       
   273 		{
       
   274 		Error(err, EErrorFatal);
       
   275 		return;
       
   276 		}
       
   277 
       
   278 	TPtr8 data = iNextPacket->Des();
       
   279 	while (aCount)
       
   280 		{
       
   281 		data.SetMax();
       
   282 		iBoundSAP->GetData(data, 0);
       
   283 		LOGHEXDESC(data)
       
   284 		ParseNextPacket();
       
   285 		--aCount;
       
   286 		}
       
   287 	}
       
   288 
       
   289 void CSdpClient::CanSend()
       
   290 	{
       
   291 	L2CAPBlocked(EFalse);
       
   292 	TryToSend();
       
   293 	}
       
   294 
       
   295 void CSdpClient::ConnectComplete()
       
   296 /**
       
   297 	Right, we're connected.
       
   298 	Let all the netdbs waiting on us know.
       
   299 	Should check L2CAP MTU's now, but for now we're just
       
   300 	trusting that they'll be large enough to hold our very
       
   301 	small requests and responses, as we can't fragment anyway.
       
   302 **/
       
   303 	{
       
   304 	ChannelUp(ETrue);
       
   305 	TDblQueIter<CSdpNetDbProvider> iter(iNetDbProviders);
       
   306 	
       
   307 	while(iter)
       
   308 		{
       
   309 		(iter++)->ClientUp();
       
   310 		}
       
   311 	}
       
   312 
       
   313 void CSdpClient::ConnectComplete(const TDesC8&)
       
   314 	{
       
   315 	Panic(ESdpConnectWithData);
       
   316 	}
       
   317 
       
   318 void CSdpClient::ConnectComplete(CServProviderBase&)
       
   319 	{
       
   320 	Panic(ESdpClientPassiveConnect);
       
   321 	}
       
   322 
       
   323 void CSdpClient::ConnectComplete(CServProviderBase&,const TDesC8& )
       
   324 	{
       
   325 	Panic(ESdpClientPassiveConnect);
       
   326 	}
       
   327 
       
   328 void CSdpClient::CanClose(TDelete /*aDelete*/)
       
   329 /**
       
   330 	Line ourselves up ready for deletion.
       
   331 	The bound SAP calling this upcall will be tided up when we are,
       
   332 	so there's no point getting carried away in doing it here.
       
   333 **/
       
   334 	{
       
   335 	iRemoteAddr.Reset();
       
   336 	ChannelUp(EFalse);
       
   337 	TDblQueIter<CSdpNetDbProvider> iter(iNetDbProviders);
       
   338 	while(iter)
       
   339 		{//Tell the netdb's we're down.
       
   340 		(iter++)->ClientDown();
       
   341 		}
       
   342 	CheckForIdle(0);	// Async call back to delete ourselves!
       
   343 	}
       
   344 
       
   345 void CSdpClient::CanClose(const TDesC8&, TDelete)
       
   346 	{
       
   347 	Panic(ESdpDisconnectWithData);
       
   348 	}
       
   349 
       
   350 void CSdpClient::Error(TInt aError,TUint anOperationMask)
       
   351 /**
       
   352    Something's gone wrong.
       
   353 
       
   354    We get told whether it's just this operation or all that are
       
   355    affected, but we'll just assume that all of them are bust for
       
   356    now.
       
   357 **/
       
   358 	{
       
   359 	LOG2(_L("SDP: L2CAP socket error: %d, mask: 0x%x"), aError, anOperationMask);
       
   360 	if (!(anOperationMask & ~EErrorIoctl))
       
   361 		return;//Ignore Ioctl errors.
       
   362 	if (anOperationMask & EErrorFatal)
       
   363 		ChannelUp(EFalse);
       
   364 	TDblQueIter<CSdpNetDbProvider> iter(iNetDbProviders);
       
   365 	CSdpNetDbProvider* netdb;
       
   366 	
       
   367 	while(iter)
       
   368 		{
       
   369 		netdb=iter++;
       
   370 		netdb->Error(aError);
       
   371 		}
       
   372 
       
   373 	iRemoteAddr.Reset();
       
   374 	CheckForIdle(0);
       
   375 	}
       
   376 
       
   377 void CSdpClient::Disconnect()
       
   378 /**
       
   379 	We're no longer connected
       
   380 **/
       
   381 	{
       
   382 	LOG(_L("SDP bearer disconnected. Closing..."))
       
   383 	CanClose();
       
   384 	}
       
   385 
       
   386 void CSdpClient::Disconnect(TDesC8& /*aDisconnectData*/)
       
   387 	{
       
   388 	Panic(ESdpDisconnectWithData);
       
   389 	}
       
   390 
       
   391 void CSdpClient::IoctlComplete(TDesC8* /*aBuf*/)
       
   392 	{
       
   393 	// This must be an internally generated ioctl
       
   394 	LOG(_L("SDP: Unexpected IoctlComplete upcall!"));
       
   395 	}
       
   396 
       
   397 /****************************************************************************/
       
   398 /* 
       
   399    Internal functions
       
   400 */
       
   401 
       
   402 void CSdpClient::ParseNextPacket()
       
   403 /**
       
   404 	Parse PDUs out of the L2CAP packet received.
       
   405 	This is actually a bit general, as we can have at most
       
   406 	one PDU per packet (SDP v1.1).
       
   407 **/
       
   408 	{
       
   409 	TPtr8 packet(iNextPacket->Des());
       
   410 	TInt rem = packet.Length();
       
   411 	TUint8* ptr = rem ? &packet[0] : 0;
       
   412 	while (rem >= KSdpPduHeaderSize)
       
   413 		{
       
   414 		TUint8  pduid   = ptr[KSdpPduIdOffset];
       
   415 		TUint16 transid = BigEndian::Get16(ptr+KSdpPduTransIdOffset);
       
   416 		TUint16 paramlen= BigEndian::Get16(ptr+KSdpPduParamLengthOffset);
       
   417 		if (rem < KSdpPduHeaderSize + paramlen)
       
   418 			break;
       
   419 		ptr += KSdpPduHeaderSize;
       
   420 		TPtrC8 params(ptr, paramlen);
       
   421 		HandlePDU(pduid, transid, params);
       
   422 		ptr += paramlen;
       
   423 		rem -= (KSdpPduHeaderSize+paramlen);
       
   424 		}
       
   425 	if (rem)
       
   426 		{//Partial pdu received. Bin it
       
   427 		LOG1(_L("SDP: Frame error: %d extra bytes received\n"), rem);
       
   428 		}
       
   429 	}
       
   430 
       
   431 void CSdpClient::HandlePDU(TUint8 aPduId, TUint16 aTransId, const TDesC8& aParams)
       
   432 	{
       
   433  	if(!RequestOutstanding())
       
   434  		{// The server is spontaneously sending us data. DROP it
       
   435  		return;
       
   436  		}
       
   437 
       
   438 	// There can only be one oustanding pdu,
       
   439 	// So the first pdu on the list must be the one.
       
   440 	__ASSERT_DEBUG(!iOutboundQ.IsEmpty(),Panic(ESdpNoRequestPdu));
       
   441    	CSdpPdu* request = iOutboundQ.First();
       
   442 	CSdpNetDbProvider* netdb = request->NetDbProvider();
       
   443 	TUint16 reqTransId = request->TransId();
       
   444 
       
   445 	RequestOutstanding(EFalse);
       
   446 	// Request complete. So delete. (Removes from Q, so we can carry on sending).
       
   447 	delete request;
       
   448 	TryToSend();
       
   449 
       
   450 	if(!netdb)
       
   451 		return;
       
   452 
       
   453 	if (reqTransId != aTransId)
       
   454    		{//DROP
       
   455 		LOG2(_L("SDP: Unexpected PDU; pdu id %d, transaction id: %d\n"), aPduId, aTransId);
       
   456 		netdb->Error(KErrSdpBadResultData);
       
   457 		return;
       
   458 		}
       
   459 
       
   460 	switch (aPduId)
       
   461 		{
       
   462 	case EErrorResponse:
       
   463 		HandleErrorResponse(netdb, aParams);
       
   464 		break;
       
   465 
       
   466 	case EServiceSearchResponse:
       
   467 		HandleServiceSearchResponse(netdb, aParams);
       
   468 		break;
       
   469 
       
   470 	case EServiceAttributeResponse:
       
   471 		HandleServiceAttributeResponse(netdb, aParams);
       
   472 		break;
       
   473 
       
   474 	default:
       
   475 		LOG1(_L("SDP: Unexpected PDU type; pdu id: %d\n"), aPduId);
       
   476 		netdb->Error(KErrSdpBadResultData);
       
   477 		};
       
   478 
       
   479 	}
       
   480 
       
   481 void CSdpClient::HandleErrorResponse(CSdpNetDbProvider* aNetDbProv, const TDesC8& aParams)
       
   482 /**
       
   483 	We've got an error response.
       
   484 
       
   485 	Parameter format is...
       
   486 	<pre>
       
   487 	  Byte  |  0   |  1  |  2   |  3  ....
       
   488 	        | Error Code | Error info (dependent on code)
       
   489 	</pre>
       
   490 **/
       
   491 	{
       
   492 	const TInt KMinLength = 2;
       
   493 	const TInt KErrorCodeOffset = 0;
       
   494 
       
   495 	TInt err = KErrGeneral; // The code to send up...
       
   496 
       
   497 	if (aParams.Length() < KMinLength)
       
   498 		{// Way! Bad error response! drop it..
       
   499 		err = KErrSdpPeerError;
       
   500 		}
       
   501 	else
       
   502 		{
       
   503 		TSdpErrorCodes code = (TSdpErrorCodes)BigEndian::Get16(&aParams[KErrorCodeOffset]);
       
   504 		switch (code)
       
   505 			{
       
   506 		case EInvalidSdpVersion:
       
   507 			err=KErrSdpUnsupportedVersion;
       
   508 			break;
       
   509 		case EInvalidServiceRecordHandle:
       
   510 			err=KErrSdpBadRecordHandle;
       
   511 			break;
       
   512 		case EInvalidContinuationState:
       
   513 			err=KErrSdpBadContinuationState;
       
   514 			break;
       
   515 		case EInvalidRequestSyntax:
       
   516 		case EInvalidPduSize:
       
   517 		default:
       
   518 			err=KErrSdpServerRejectedRequest;
       
   519 			}
       
   520 		}
       
   521 
       
   522 	if (!aNetDbProv)
       
   523 		{
       
   524 		LOG1(_L("SDP: Error response with no owning aNetDbPr %d\nWill error them all!\n"), err);
       
   525 		Error(err, EErrorAllOperations);
       
   526 		return;
       
   527 		}
       
   528 	aNetDbProv->Error(err);
       
   529 	}
       
   530 
       
   531 void CSdpClient::HandleServiceSearchResponse(CSdpNetDbProvider* aNetDbProv, const TDesC8& aParams)
       
   532 /**
       
   533 	Got service search response.
       
   534 	Pass it right on up to the net db.
       
   535 **/
       
   536 	{
       
   537 	if (!aNetDbProv)
       
   538 		{
       
   539 		LOG(_L("SDP: Service search response with no owning aNetDbPr\n"));
       
   540 		return;
       
   541 		}
       
   542 	aNetDbProv->QueryComplete(aParams);
       
   543 	}
       
   544 
       
   545 void CSdpClient::HandleServiceAttributeResponse(CSdpNetDbProvider* aNetDbProv, const TDesC8& aParams)
       
   546 /**
       
   547 	We've got an attribute request response.
       
   548 	Pass the params up to the net db. It'll be dealt with client side!
       
   549 
       
   550 **/
       
   551 	{
       
   552 	if (!aNetDbProv)
       
   553 		{
       
   554 		LOG(_L("SDP: Attribute response with no owning aNetDbPr\n"));
       
   555 		return;
       
   556 		}
       
   557 	aNetDbProv->QueryComplete(aParams);
       
   558 	}
       
   559 
       
   560 CSdpPdu* CSdpClient::NewPdu(CSdpNetDbProvider* aNetDb)
       
   561 	{
       
   562 	return new CSdpPdu(aNetDb);
       
   563 	}
       
   564 
       
   565 TUint16 CSdpClient::NextTransId()
       
   566 	{
       
   567 	return ++iTransId ? iTransId : ++iTransId;
       
   568 	}
       
   569 
       
   570 void CSdpClient::EnqueOutboundPdu(CSdpPdu& aPdu)
       
   571 	{
       
   572 	iOutboundQ.AddLast(aPdu);
       
   573 	TryToSend();
       
   574 	}
       
   575 
       
   576 void CSdpClient::TryToSend()
       
   577 /**
       
   578 	Try to send out a pdu.
       
   579 	Can do this if we have something to send, L2CAP is not blocked,
       
   580 	and there is no outstanding request.
       
   581 	There are 3 different places TryToSend can be called,
       
   582 	corresponding to invalidation of these three guards.
       
   583 
       
   584 	Pdu tries to emit for is one. It can make this if we will have something to emit, L2CAP is
       
   585 	not obstructed, and it does not have no prominent order. It has 3 different places that
       
   586 	TryToSend can be called, corresponding to invalidation of these three holds. 
       
   587 **/
       
   588 	{
       
   589 	if (RequestOutstanding())
       
   590 		return;
       
   591 	if (iOutboundQ.IsEmpty())
       
   592 		return;
       
   593 	if (L2CAPBlocked())
       
   594 		return;
       
   595 
       
   596 	// To pipeline, we should iterate here, until no more can fit in the packet,
       
   597 	// then send packet. Should really mark the pdus as sent too.
       
   598 	CSdpPdu& pdu = *iOutboundQ.First();
       
   599 	// We just try to write, regardless of MTU! If it doesn't fit, we'll
       
   600 	// get back an error from remtoe. But our requests generally should fit.
       
   601 	if (!iBoundSAP->Write(pdu.Data(), 0))
       
   602 		{
       
   603 		L2CAPBlocked(ETrue);
       
   604 		return;
       
   605 		}
       
   606 	// PDU will be dequed when it's response returns.
       
   607 	// This is easy to do, as we're not pipelining requests in L2CAP packets,
       
   608 	// so at most only one pdu can be outstanding at once.
       
   609 	RequestOutstanding(ETrue);
       
   610 	}
       
   611 
       
   612 void CSdpClient::CheckForIdle(TInt aTimeoutInSeconds)
       
   613 	{
       
   614 	CancelIdleTimer();
       
   615 	iIdleQueued = ETrue;
       
   616 	// Add 10 to allow aTimeInSeconds to be 0.
       
   617     BTSocketTimer::Queue((aTimeoutInSeconds*1000000)+10, iIdleTimerEntry);
       
   618 	}
       
   619 
       
   620 void CSdpClient::CancelIdleTimer()
       
   621 	{
       
   622 	if (iIdleQueued)
       
   623 		{
       
   624 	    BTSocketTimer::Remove(iIdleTimerEntry);
       
   625 		iIdleQueued = EFalse;
       
   626 		}
       
   627 	}
       
   628 
       
   629 TInt CSdpClient::IdleTimerExpired(TAny* aPtr)
       
   630 /**
       
   631 	Static function called whenever idle timer expires.
       
   632 	Take us down. Gracefully, mind!
       
   633 **/
       
   634 	{
       
   635 	CSdpClient* self = static_cast<CSdpClient*>(aPtr);
       
   636 	__ASSERT_DEBUG(self->iIdleQueued, Panic(ESdpClientBadIdleState));
       
   637 	self->iIdleQueued = EFalse;
       
   638 	if (self->ChannelUp())
       
   639 		{// Take it down, first.
       
   640 		// Clear remote address, so we don't accept further netdbs.
       
   641 		self->iRemoteAddr.Reset();
       
   642 		self->ChannelUp(EFalse);
       
   643 		self->iBoundSAP->Shutdown(CServProviderBase::ENormal);
       
   644 		self->CheckForIdle(KSDPIdleTimeout*2);
       
   645 		}
       
   646 	else
       
   647 		{// Channels down. Say good bye!
       
   648 		self->iProtocol.ClientDown(*self);	// Who'll promtly delete 'self'
       
   649 		}
       
   650 	return FALSE;
       
   651 	}
       
   652