bluetooth/btsdp/server/epocsvr.cpp
changeset 0 29b1cd4cb562
child 22 786b94c6f0a4
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 <e32svr.h>
       
    18 #include <e32uid.h>
       
    19 #include <btsdp.h>
       
    20 #include "DataEncoder.h"
       
    21 #include "EncoderVisitor.h"
       
    22 #include "sdputil.h"
       
    23 #include "reqhandler.h"
       
    24 #include "listener.h"
       
    25 #include "epocsvr.h"
       
    26 #include "ipcinternals.h"
       
    27 #include "attrvalueencoded.h"
       
    28 
       
    29 #include "epocsvr.inl"
       
    30 #include <f32file.h>	//	For RFs
       
    31 
       
    32 #ifdef __EPOC32__
       
    33 #include <c32comm.h>
       
    34 #endif
       
    35 
       
    36 #include "SdpServerSecurityPolicy.h"
       
    37 
       
    38 #ifdef __FLOG_ACTIVE
       
    39 _LIT8(KLogComponent, LOG_COMPONENT_SDP_SERVER);
       
    40 #endif
       
    41 
       
    42 #ifdef _DEBUG
       
    43 PANICCATEGORY("epocsvr");
       
    44 #endif
       
    45 
       
    46 GLDEF_D TInt sdp_debug_level = 5;
       
    47 
       
    48 void Panic(TSdpServerPanics aCode)
       
    49 	{
       
    50 	User::Panic(KSdpServerPanicName, aCode);
       
    51 	}
       
    52 
       
    53 /**
       
    54  The SDP database subsession class has been removed from the SDP server but to 
       
    55  maintain BC we still have to deal with subsession requests from the client.
       
    56  The constant below is used as the subsession handle for any new subsession
       
    57  requests from a client as we no longer maintain a real handle to a subsession.
       
    58 **/
       
    59 static const TInt KSdpDatabaseSubSessionHandle = 0x1A2B3C4D;
       
    60 
       
    61 inline CSdpServerShutdown::CSdpServerShutdown()
       
    62 	:CTimer(-1)
       
    63 	{CActiveScheduler::Add(this);}
       
    64 inline void CSdpServerShutdown::ConstructL()
       
    65 	{CTimer::ConstructL();}
       
    66 inline void CSdpServerShutdown::Start()
       
    67 	{After(KSdpServerShutdownDelay);}
       
    68 
       
    69 //
       
    70 
       
    71 
       
    72 void CSdpServerShutdown::RunL()
       
    73 /**
       
    74  Initiate server exit when the timer expires
       
    75 **/
       
    76 	{
       
    77 	LOG_FUNC
       
    78 	CActiveScheduler::Stop();
       
    79 	}
       
    80 
       
    81 CSdpServer::CSdpServer()
       
    82 	: CPolicyServer(0, KSdpServerPolicy)
       
    83 	{
       
    84 	CONNECT_LOGGER
       
    85 	LOG_FUNC
       
    86 	}
       
    87 
       
    88 CSdpServer* CSdpServer::NewLC()
       
    89 /**
       
    90  Create the server object and leave on cleanup stack.
       
    91 **/
       
    92 	{
       
    93 	LOG_STATIC_FUNC
       
    94 	CSdpServer* self=new(ELeave) CSdpServer();
       
    95 	CleanupStack::PushL(self);
       
    96 	self->ConstructL();
       
    97 	return self;
       
    98 	}
       
    99 
       
   100 void CSdpServer::ConstructL()
       
   101 	{
       
   102 	LOG_FUNC
       
   103 	StartL(KSdpServerName);
       
   104 	
       
   105 	iSdpDatabase = CSdpDatabase::NewL();
       
   106 	iUuidManager = CSdpUuidManager::NewL(*iSdpDatabase);
       
   107 
       
   108 	TPckg<TUint> intBuf(0);
       
   109 	iDbState = CSdpAttrValueUint::NewUintL(intBuf);
       
   110 
       
   111 	// Create the buffer the correct size for storing a Uint
       
   112 	TInt encodedSize = TElementEncoder::EncodedSize(iDbState->Type(), iDbState->DataSize());
       
   113 	iEncodeBuf.CreateL(encodedSize);
       
   114 	TElementEncoder encoder(iEncodeBuf);
       
   115 
       
   116 	iEncoderVisitor = CAttrEncoderVisitor::NewL(encoder);
       
   117 	BuildRecordZeroL(); //Unencoded
       
   118 	Database()->EncodeDbL(); /*If we get to here, database exists*/
       
   119 
       
   120 	User::LeaveIfError(iSocketServ.Connect());
       
   121 	iSdpListener = CSdpListener::NewL(iSocketServ, 4, *(Database()));
       
   122 
       
   123 	//Ensure that the server will exit even if the 1st client fails to connect
       
   124 	//Start shutdown timer only after all the heavy duty initialisation has been done. 
       
   125 	//Otherwise it could fire before any client had a chance to connect to the server
       
   126 	iShutdown.ConstructL();
       
   127 	iShutdown.Start();
       
   128 	}
       
   129 
       
   130 CSdpServer::~CSdpServer()
       
   131 	{
       
   132 	LOG_FUNC
       
   133 	delete iSdpListener;
       
   134 	iSocketServ.Close();
       
   135 	
       
   136 	delete iRecZero;
       
   137 	delete iDbState;
       
   138 	delete iEncoderVisitor;
       
   139 	iEncodeBuf.Close();
       
   140 
       
   141 	delete iUuidManager;
       
   142 	delete iSdpDatabase;
       
   143 	CLOSE_LOGGER
       
   144 	}
       
   145 
       
   146 CSdpDatabase* CSdpServer::Database()
       
   147 	{
       
   148 	LOG_FUNC
       
   149 	return iSdpDatabase;
       
   150 	}
       
   151 
       
   152 void CSdpServer::BuildRecordZeroL()
       
   153 /**
       
   154  Record 0 should be used when a server instance is created.
       
   155  note that attributes 2, 5 and 0x201 should be updated.
       
   156  also note only English, pas de Francais, keine Deutsch, non Espanol
       
   157 **/
       
   158 	{
       
   159 	LOG_FUNC
       
   160 	ASSERT_DEBUG(iSdpDatabase);
       
   161 	
       
   162 	TBuf8<2> attrId;
       
   163 	TBuf8<4> val;
       
   164 	
       
   165 	iRecZero = CSdpServRecord::NewServerSideL(User::Identity());
       
   166 
       
   167 	// Set Attr 0 (Record handle) to 0
       
   168 	attrId.FillZ(2);
       
   169 	val.FillZ(4);
       
   170 	iRecZero->BuildUintL(attrId)->BuildUintL(val);
       
   171 
       
   172 	// Set Attr 1 (service class list) to list with UUID = 0x1000
       
   173 	attrId[0] = 0x00;
       
   174 	attrId[1] = 0x01;
       
   175 	iRecZero->BuildUintL(attrId)->BuildDESL()
       
   176 			->StartListL()
       
   177 				->BuildUUIDL(TUUID(TUint16(KServiceDiscoveryServerServiceClassUUID)))
       
   178 			->EndListL();
       
   179 
       
   180 	// Set Attr 2 (service record state) to 0
       
   181 	attrId[0] = 0x00;
       
   182 	attrId[1] = 0x02;
       
   183 	val.FillZ(4);
       
   184 	iRecZero->BuildUintL(attrId)->BuildUintL(val);
       
   185 
       
   186 	// Set attr 4 (protocol list) to L2CAP, no RFCOMM, no OBEX
       
   187 	attrId[0] = 0x00;
       
   188 	attrId[1] = 0x04;
       
   189 	val.FillZ(4);
       
   190 	val[3] = 1;
       
   191 	iRecZero->BuildUintL(attrId)->BuildDESL()
       
   192 			->StartListL()
       
   193 				->BuildDESL()
       
   194 				->StartListL()
       
   195 					->BuildUUIDL(TUUID(TUint16(0x0100))) // L2CAP
       
   196 					->EndListL()
       
   197 					->EndListL();
       
   198 
       
   199 	// Set Attr 5 (browse group list) to list with one UUID
       
   200 	// 0x1000 (SDP server class)
       
   201 	// this should be updated with other service classes when other services are added.
       
   202 	attrId[0] = 0x00;
       
   203 	attrId[1] = 5;
       
   204 	iRecZero->BuildUintL(attrId)->BuildDESL()
       
   205 			->StartListL()
       
   206 				->BuildUUIDL(TUUID(TUint32(0x1000)))
       
   207 			->EndListL();
       
   208 
       
   209 	// Set Attr 0x006 (language base)
       
   210 	attrId[0] = 0x00;
       
   211 	attrId[1] = 0x06;
       
   212 	TUint16 lang = 0x656e;
       
   213 	TUint16 coding = 0x006a;
       
   214 	TUint16 base = 0x0100;
       
   215 
       
   216 	iRecZero->BuildUintL(attrId)->BuildDESL()
       
   217 			->StartListL()
       
   218 				->BuildUintL(TSdpIntBuf<TUint16>(lang)) // english
       
   219 				->BuildUintL(TSdpIntBuf<TUint16>(coding)) // UTF-8
       
   220 				->BuildUintL(TSdpIntBuf<TUint16>(base)) // language base
       
   221 			->EndListL();
       
   222 
       
   223 	// Set Attr 0x007 (time to live) to 1200 (0x4B0) seconds (20 minutes)
       
   224 	attrId[0] = 0x00;
       
   225 	attrId[1] = 0x07;
       
   226 	val.FillZ(4);
       
   227 	val[2]=4;
       
   228 	val[3]=0xb0;
       
   229 	iRecZero->BuildUintL(attrId)->BuildUintL(val);
       
   230 
       
   231 	// Set Attr 0x008 (availability) to 0xff - fully available - not in use
       
   232 	attrId[0] = 0x00;
       
   233 	attrId[1] = 0x08;
       
   234 	TBuf8<1> val4;
       
   235 	val4.FillZ(1);
       
   236 	val4[0]=0xff;
       
   237 	iRecZero->BuildUintL(attrId)->BuildUintL(val4);
       
   238 
       
   239 	// Set Attr 0x100 (default Name) to string
       
   240 	attrId[0] = 0x01;
       
   241 	attrId[1] = 0;
       
   242 	iRecZero->BuildUintL(attrId)->BuildStringL(_L8("SDP Server"));
       
   243 
       
   244 	// Set Attr 0x101 (def. description) to string
       
   245 	attrId[0] = 0x01;
       
   246 	attrId[1] = 1;
       
   247 	iRecZero->BuildUintL(attrId)->BuildStringL(_L8("Provides local service information for remote devices."));
       
   248 
       
   249 	// Set Attr 0x102 (def. provider) to Symbian
       
   250 	attrId[0] = 0x01;
       
   251 	attrId[1] = 2;
       
   252 	iRecZero->BuildUintL(attrId)->BuildStringL(_L8("Symbian OS"));
       
   253 
       
   254 	// Set Attr 0x200 (version number support) to list with 1.0 and 1.1
       
   255 	iRecZero->BuildUintL(TSdpIntBuf<TSdpAttributeID>(0x200))
       
   256 			->BuildDESL()
       
   257 			->StartListL()
       
   258 				->BuildUintL(TSdpIntBuf<TUint16>(0x0100)) // 1.0
       
   259 				->BuildUintL(TSdpIntBuf<TUint16>(0x0101)) // 1.1
       
   260 			->EndListL();
       
   261 
       
   262 	// Set Attr 0x201 (service database state) to 0
       
   263 	attrId[0] = 0x02;
       
   264 	attrId[1] = 0x01;
       
   265 	val.FillZ(4);
       
   266 	iRecZero->BuildUintL(attrId)->BuildUintL(val);
       
   267 
       
   268 	// Add the record into the database
       
   269 	Database()->AddRecord(iRecZero);
       
   270 	}
       
   271 
       
   272 CSession2* CSdpServer::NewSessionL(const TVersion& /*aVersion*/) const
       
   273 	{
       
   274 	LOG_FUNC
       
   275 	User::Leave(KErrNotSupported);
       
   276 	return 0;
       
   277 	}
       
   278 
       
   279 CSession2* CSdpServer::NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const
       
   280 	{
       
   281 	LOG_FUNC
       
   282 	TVersion v(KSdpServerMajorVersionNumber,KSdpServerMinorVersionNumber,KSdpServerBuildVersionNumber);
       
   283 	if (!User::QueryVersionSupported(v,aVersion))
       
   284 		{
       
   285 		User::Leave(KErrNotSupported);
       
   286 		}
       
   287 	// make new session
       
   288 	return new(ELeave) CSdpServSession(aMessage);
       
   289 	}
       
   290 
       
   291 void CSdpServer::AddSession()
       
   292 /**
       
   293 A new session is being created
       
   294 Cancel the shutdown timer if it was running
       
   295 **/
       
   296 	{
       
   297 	LOG_FUNC
       
   298 	++iSessionCount;
       
   299 	if (iSessionCount > iMaxSessionCount)
       
   300 		{
       
   301 		iMaxSessionCount = iSessionCount;
       
   302 		}
       
   303 	iShutdown.Cancel();
       
   304 	}
       
   305 
       
   306 void CSdpServer::DropSession()
       
   307 /**
       
   308 A session is being destroyed
       
   309 Start the shutdown timer if it is the last session.
       
   310 **/
       
   311 	{
       
   312 	__ASSERT_DEBUG(iSessionCount > 0, PanicServer(ESdpBadState));
       
   313 	
       
   314 	if (--iSessionCount==0)
       
   315 		{
       
   316 		iShutdown.Start();
       
   317 		}
       
   318 	}
       
   319 
       
   320 void CSdpServer::CheckAllowedL(const RMessage2& aMessage, const CSdpServRecord& aRecord)
       
   321 	{
       
   322 	LOG_FUNC
       
   323 	if (!Allowed(aMessage, aRecord))
       
   324 		{
       
   325 		User::Leave(KErrPermissionDenied);
       
   326 		}
       
   327 	}
       
   328 
       
   329 TBool CSdpServer::Allowed(const RMessage2& aMessage, const CSdpServRecord& aRecord)
       
   330 	{
       
   331 	LOG_FUNC
       
   332 	_LIT_SECURITY_POLICY_S0(KSidPolicy, aRecord.ClientUid().iUid);
       
   333 	
       
   334 	//if the secure id of the record matches the secure id of the message sender
       
   335 	if (KSidPolicy().CheckPolicy(aMessage))
       
   336 		{
       
   337 		//allowed
       
   338 		return ETrue;
       
   339 		}
       
   340 	
       
   341 	//not allowed
       
   342 	return EFalse;
       
   343 	}
       
   344 
       
   345 CSdpServRecord* CSdpServer::FindRecordByHandle(const TSdpServRecordHandle aHandle)
       
   346 /**
       
   347 Returns a pointer to the first record object found with its 
       
   348 attribute '0' set to the specified handle.
       
   349 If no such record object is found, this function return 0 (Null).
       
   350 **/
       
   351 	{
       
   352 	LOG_FUNC
       
   353 	for(TServRecordIter recIter(Database()->RecordIter()); recIter; recIter++)
       
   354 		{// Iterate thru records in iDatabase
       
   355 		if((*recIter).Handle()==aHandle)
       
   356 			{
       
   357 			//Destructor of a record removes/destroys all its 
       
   358 			//attributes and deques it from database list.
       
   359 			return &(*recIter);
       
   360 			}
       
   361 		}
       
   362 	return 0;
       
   363 	}
       
   364 
       
   365 CSdpAttr* CSdpServer::FindAttributeByID(CSdpServRecord& aRecord, const TSdpAttributeID aAttrID)
       
   366 /**
       
   367 Returns a pointer to the attribute object found in the 
       
   368 specified record that has the specified ID.
       
   369 If no such attribute object is found, this function return 0 (Null).
       
   370 **/
       
   371 	{
       
   372 	LOG_FUNC
       
   373 	for(TServAttrIter attrIter(aRecord.AttributeIter()); attrIter; attrIter++)
       
   374 		{// Iterate thru attributes in record
       
   375 		if((*attrIter).AttributeID()==aAttrID)
       
   376 			{
       
   377 			return &(*attrIter);
       
   378 			}
       
   379 		}
       
   380 	return 0;
       
   381 	}
       
   382 
       
   383 /**
       
   384 This function must be called whenever a service record is added or removed.
       
   385 
       
   386 The SDP server 0 service record has a ServerServiceDatabaseState attribute
       
   387 which, if present, must be updated when a service record is added or removed.
       
   388 */
       
   389 void CSdpServer::DatabaseStateChange()
       
   390 	{
       
   391 	LOG_FUNC
       
   392 	//increment database state attribute in record zero
       
   393 	if(iRecZero)
       
   394 		{
       
   395 		TUint state = iDbState->Uint();
       
   396 
       
   397 		TPckg<TUint> stateBuf(0);
       
   398 		SdpUtil::PutUint(&stateBuf[0], ++state, sizeof(TUint));
       
   399 
       
   400 		iDbState->SetUintValue(stateBuf);
       
   401 
       
   402 		// This encodes iDbState into the buffer provided at construction
       
   403 		iEncodeBuf.SetLength(0);
       
   404 		TRAPD(err, iEncoderVisitor->EncodeAttributeL(*iDbState));
       
   405 		// Attribute encoding can only fail if the attribute is of an unknown type 
       
   406 		// or the supplied buffer is too small.  We have set the length of the
       
   407 		// buffer to the correct length on creation so that will not fail.
       
   408 		// We know iDbState is a CSdpAttrValueUint so cannot fail.
       
   409 		__ASSERT_ALWAYS(!err, PanicServer(ESdpAttributeEncodingFailed));
       
   410 
       
   411 		CSdpAttr* attr = FindAttributeByID(*iRecZero, KSdpAttrIdSdpServerServiceDatabaseState);
       
   412 		__ASSERT_ALWAYS(attr->Value().Type() == ETypeEncoded, PanicServer(ESdpStoredAttrValNotEncoded));
       
   413 		reinterpret_cast<CSdpAttrValueEncoded&>(attr->Value()).SetEncodedValue(iEncodeBuf);
       
   414 
       
   415 		iRecZero->RecordStateChange();
       
   416 		iUuidManager->NotifySdpRecordChange();
       
   417 		}
       
   418 	}
       
   419 
       
   420 CSdpServRecord* CSdpServer::CreateServiceRecordL(const RMessage2& aMessage)
       
   421 /**
       
   422 Creates a record on the global database. Returns a pointer to the new record.
       
   423 **/
       
   424 	{
       
   425 	LOG_FUNC
       
   426 
       
   427 	CSdpServRecord* record = CSdpServRecord::NewServerSideL(aMessage.Identity());
       
   428 	
       
   429 	CleanupStack::PushL(record);
       
   430 	
       
   431 	//Build record handle attribute...
       
   432 	//..NB if we had created the record using iDatabase.NewRecordL we would not
       
   433 	//     have to add the handle attribute manually..BUT then to encode the 
       
   434 	//	   the handle attribute would have required us to dig it out of the
       
   435 	//	   record first which seems less robust than what is below.
       
   436 	//	   For 1.1 we might create an EncodeRecordL function for a single record
       
   437 	//	   in the same way we now have an EncodeDbL function for the whole database.
       
   438 	//	   This would then allow us to call iDatabase>NewRecordL, followed by 
       
   439 	//	   record.EncodeRecordL.	
       
   440 	CSdpAttr* handleAttr = CSdpAttr::NewL(0x00, record);
       
   441 	record->AddAttribute(handleAttr);
       
   442 	handleAttr->BuildUintL(TSdpIntBuf<TSdpServRecordHandle>(Database()->NextFreeHandle()));
       
   443 	CSdpAttrValue* handleAttrValue = &(handleAttr->Value());
       
   444 
       
   445 	TUint size = TElementEncoder::EncodedSize(handleAttrValue->Type(), 
       
   446 											  handleAttrValue->DataSize());
       
   447 	HBufC8* bufEncodedHandle = HBufC8::NewL(size);
       
   448 	CleanupStack::PushL(bufEncodedHandle);
       
   449 	TPtr8 ptrEncodedHandle = bufEncodedHandle->Des();
       
   450 
       
   451 	TElementEncoder ee(ptrEncodedHandle);
       
   452 	CAttrEncoderVisitor::EncodeAttributeL(ee, *handleAttrValue);
       
   453 	handleAttr->BuildEncodedL(ptrEncodedHandle); 
       
   454 
       
   455 	CleanupStack::PopAndDestroy(); //bufEncodedHandle
       
   456 
       
   457 	//Write record handle back to EPOC client (i.e. user)
       
   458 	TSdpServRecordHandlePckgBuf pckg(record->Handle());
       
   459 	pckg() = record->Handle();
       
   460 	aMessage.WriteL(1, pckg); //ss//
       
   461 
       
   462 	//Build service class attribute...
       
   463  	TInt bufServiceClassLen = aMessage.GetDesLengthL(0); //ss//
       
   464  	HBufC8* bufServiceClass = HBufC8::NewLC(bufServiceClassLen);
       
   465  	TPtr8 ptrServiceClass = bufServiceClass->Des();
       
   466  	aMessage.ReadL(0, ptrServiceClass); //get message data into buf (via ptr) //ss//
       
   467 
       
   468 	TBuf8<2> attrId;
       
   469 	attrId.FillZ(2); // Order of following lines important to value in attrId!!!
       
   470 	attrId[0] = 0x00;
       
   471 	attrId[1] = 0x01;
       
   472 
       
   473 	CSdpAttr* attr = CSdpAttr::NewL(0x0001, record);
       
   474 	record->AddAttribute(attr);
       
   475 	attr->BuildEncodedL(ptrServiceClass);
       
   476 
       
   477 	//Add record, now with handle and service class attributes, to database
       
   478 	Database()->AddRecord(record);
       
   479 	CleanupStack::PopAndDestroy(); //bufServiceClass
       
   480  	CleanupStack::Pop(); //record,
       
   481 	
       
   482 	DatabaseStateChange();
       
   483 
       
   484 	//Return a pointer to the new record
       
   485 	return record;
       
   486 	}
       
   487 
       
   488 CSdpServRecord* CSdpServer::FindAndCheckServiceRecordForDeletion(const RMessage2& aMessage)
       
   489 /**
       
   490 Checks it's ok to delete a record on the global database using handle sent in message slot 0.
       
   491 Returns the pointer of the record that is to be deleted. 
       
   492 **/
       
   493 	{
       
   494 	LOG_FUNC
       
   495 	
       
   496 	TSdpServRecordHandlePckgBuf pckg;
       
   497  	TRAPD(err, aMessage.ReadL(0, pckg)); //get message data into buf (via ptr)
       
   498 	if(err)
       
   499 		{
       
   500 		// Client has sent us a dodgy descriptor, punish them!
       
   501 		PanicClient(aMessage, ESdpBadDescriptor);
       
   502 		return NULL;
       
   503 		}
       
   504 	
       
   505 	//the service record handle should be non-zero
       
   506 	__ASSERT_DEBUG(pckg() != 0, Panic(ESdpServerDeleteServiceRecordHandleZero));
       
   507 	
       
   508 	CSdpServRecord* record = FindRecordByHandle(pckg());
       
   509 	if(!record)
       
   510 		{
       
   511 		PanicClient(aMessage, ESdpNonExistantRecordHandle);
       
   512 		return NULL;
       
   513 		}
       
   514 
       
   515 	TRAP(err, CheckAllowedL(aMessage, *record));
       
   516 	if(err)
       
   517 		{
       
   518 		// Client has been naughty, trying to delete things they shouldn't!
       
   519 		PanicClient(aMessage, ESdpBadRequest);
       
   520 		return NULL;
       
   521 		}
       
   522 
       
   523 	//Return a pointer to the record to be deleted
       
   524 	return record;
       
   525 	}
       
   526 
       
   527 void CSdpServer::UpdateAttributeL(const RMessage2& aMessage)
       
   528 /**
       
   529 Updates/Creates an attribute in a record on the global database using the packaged 
       
   530 record handle, the packaged attribute id, and the encoded attribute value 
       
   531 sent in message slots 0, 1, and 2. 
       
   532 **/
       
   533 	{
       
   534 	LOG_FUNC
       
   535 	
       
   536 	TSdpAttributeIDPckgBuf idPckg;
       
   537 	TSdpServRecordHandlePckgBuf handlePckg;
       
   538 	
       
   539  	aMessage.ReadL(0, handlePckg); //get handle into handle package
       
   540  	
       
   541 	//the service record handle should be non-zero
       
   542 	__ASSERT_DEBUG(handlePckg() != 0, Panic(ESdpServerUpdateAttributeRecordHandleZero));
       
   543 	
       
   544  	aMessage.ReadL(1, idPckg); //get id into id package
       
   545  	TInt bufLen = aMessage.GetDesLengthL(2);
       
   546  	HBufC8* buf = HBufC8::NewLC(bufLen);
       
   547  	TPtr8 ptr = buf->Des();
       
   548  	aMessage.ReadL(2, ptr); //get message data into buf (via ptr)
       
   549  	
       
   550 	CSdpServRecord* record = FindRecordByHandle(handlePckg());
       
   551 	if(!record)
       
   552 		{
       
   553 		PanicClient(aMessage, ESdpNonExistantRecordHandle);
       
   554 		return;
       
   555 		}
       
   556 	
       
   557 	CheckAllowedL(aMessage, *record);
       
   558 	
       
   559 	UpdateOrCreateAtributeL(*record, idPckg(), ptr);
       
   560 	
       
   561 	iUuidManager->NotifySdpRecordChange();
       
   562 	
       
   563 	CleanupStack::PopAndDestroy(); //buf
       
   564 	}
       
   565 
       
   566 void CSdpServer::UpdateOrCreateAtributeL(CSdpServRecord& aRecord, TSdpAttributeID aAttrId, const TDesC8& aBuf)
       
   567 	{
       
   568 	LOG_FUNC
       
   569 	CSdpAttr* attr = FindAttributeByID(aRecord, aAttrId);
       
   570 	if(attr)
       
   571 		{
       
   572 		//Deletes old attr value, and replaces with encoded value found in 'ptr'.
       
   573 		attr->BuildEncodedL(aBuf);	
       
   574 		}
       
   575 	else
       
   576 		{
       
   577 		TPckg<TUint16> idBuf(0);
       
   578 		BigEndian::Put16(&idBuf[0], aAttrId);
       
   579 		static_cast<CSdpAttr*>(aRecord.BuildUintL(idBuf))->BuildEncodedL(aBuf);
       
   580 		}
       
   581 
       
   582 	aRecord.RecordStateChange();
       
   583 	}
       
   584 
       
   585 void CSdpServer::DeleteAttribute(const RMessage2& aMessage)
       
   586 /**
       
   587 Deletes an attribute on the global database using the packaged record and the packaged 
       
   588 attribute id found in record handle and attribute id sent in message slots 0 and 1. 
       
   589 **/
       
   590 	{
       
   591 	LOG_FUNC
       
   592 	
       
   593 	TSdpAttributeIDPckgBuf idPckg;
       
   594 	TSdpServRecordHandlePckgBuf handlePckg;
       
   595 	
       
   596  	TRAPD(err, aMessage.ReadL(0, handlePckg)); //get handle into handle package
       
   597 	if(err)
       
   598 		{
       
   599 		// Client has sent us a dodgy descriptor, punish them!
       
   600 		PanicClient(aMessage, ESdpBadDescriptor);
       
   601 		return;
       
   602 		}
       
   603 	
       
   604 	//the service record handle should be non-zero
       
   605 	__ASSERT_DEBUG(handlePckg() != 0, Panic(ESdpServerDeleteAttributeRecordHandleZero));
       
   606 	
       
   607  	TRAP(err, aMessage.ReadL(1, idPckg)); //get id into id package
       
   608 	if(err)
       
   609 		{
       
   610 		// Client has sent us a dodgy descriptor, punish them!
       
   611 		PanicClient(aMessage, ESdpBadDescriptor);
       
   612 		return;
       
   613 		}
       
   614 
       
   615 	CSdpServRecord* record = FindRecordByHandle(handlePckg());
       
   616 	if(!record)
       
   617 		{
       
   618 		PanicClient(aMessage, ESdpNonExistantRecordHandle);
       
   619 		return;
       
   620 		}
       
   621 
       
   622 	TRAP(err, CheckAllowedL(aMessage, *record));
       
   623 	if(err)
       
   624 		{
       
   625 		// Client has been naughty, trying to delete things they shouldn't!
       
   626 		PanicClient(aMessage, ESdpBadRequest);
       
   627 		return;
       
   628 		}
       
   629 	
       
   630 	CSdpAttr* attr = FindAttributeByID(*record, idPckg());
       
   631 	if(!attr)
       
   632 		{
       
   633 		return;
       
   634 		}
       
   635 
       
   636 	delete attr;
       
   637 
       
   638 	record->RecordStateChange();
       
   639 
       
   640 	return;
       
   641 	}
       
   642 
       
   643 void CSdpServer::DeleteServiceRecord(CSdpServRecord* aServiceRecord)
       
   644 /**
       
   645 Deletes a record on the global database using a pointer to the record. This 
       
   646 is used to delete records added to a session when the session is closed if 
       
   647 the records have not been deleted by the client.
       
   648 **/
       
   649 	{
       
   650 	LOG_FUNC
       
   651 	if (aServiceRecord)
       
   652 		{
       
   653 		//Destructor of a record removes/destroys all its 
       
   654 		//attributes and deques it from database list.
       
   655 		delete aServiceRecord;
       
   656 		DatabaseStateChange();
       
   657 		}
       
   658 	}
       
   659 
       
   660 TInt CSdpServer::RunError(TInt aError)
       
   661 /**
       
   662    Handle an error from ServiceL()
       
   663    A bad descriptor error implies a badly programmed client, so panic it;
       
   664    otherwise report the error to the client
       
   665 **/
       
   666 	{
       
   667 	LOG_FUNC
       
   668 	LOG1(_L("s\tCSdpServer::RunError(): %d"), aError);
       
   669 	if (aError==KErrBadDescriptor)
       
   670 		{
       
   671 		PanicClient(Message(),ESdpBadDescriptor);
       
   672 		}
       
   673 	else
       
   674 		{
       
   675 		Message().Complete(aError);
       
   676 		}
       
   677 	ReStart();
       
   678 	return KErrNone;	// handled the error fully
       
   679 	}
       
   680 
       
   681 void PanicClient(const RMessage2& aMessage, TSdpClientPanic aPanic)
       
   682 /**
       
   683    Panic the client and complete the message.
       
   684    RMessage2::Panic() also completes the message. This is:
       
   685    (a) important for efficient cleanup within the kernel
       
   686    (b) a problem if the message is completed a second time
       
   687 **/
       
   688 	{
       
   689 	LOG_STATIC_FUNC
       
   690 	LOG1(_L("s\tPanicClient: Reason = %d"), aPanic);
       
   691 	aMessage.Panic(KSdpClientPanic,aPanic);
       
   692 	}
       
   693 
       
   694 void PanicServer(TSdpServerPanic aPanic)
       
   695 /**
       
   696 Panic our own thread
       
   697 **/
       
   698 	{
       
   699 	LOG_STATIC_FUNC
       
   700 	LOG1(_L("s\tPanicServer: Reason = %d"), aPanic);
       
   701 	User::Panic(KSdpServerPanic, aPanic);
       
   702 	}
       
   703 
       
   704 class CAttrPrintVisitor : public CBase, public MAttributeVisitor
       
   705 	{
       
   706 public:
       
   707 	CAttrPrintVisitor(){}
       
   708 #ifdef _DEBUG
       
   709     void VisitAttributeL(CSdpAttr& aAttribute)
       
   710 #else
       
   711     void VisitAttributeL(CSdpAttr& /*aAttribute*/)
       
   712 #endif
       
   713 		{
       
   714 		Indent();
       
   715 		LOG1(_L("Attribute ID: 0x%x"), aAttribute.AttributeID());
       
   716 		}
       
   717 	void VisitAttributeValueL(CSdpAttrValue & aValue, TSdpElementType aType)
       
   718 		{
       
   719 		TBuf16<64> iString;
       
   720 		switch (aType)
       
   721 			{
       
   722 			case ETypeString:
       
   723 				iString.Copy(aValue.Des());
       
   724 				LOG1(_L("\"%S\""),&iString);
       
   725 				break;
       
   726 			case ETypeDES:
       
   727 				LOG(_L(" DES"));
       
   728 				break;
       
   729 			case ETypeUint:
       
   730 				LOG1(_L(" UInt:0x%x"), aValue.Uint());
       
   731 				break;
       
   732 			case ETypeUUID:
       
   733 				LOG(_L(" UUID:0x"));
       
   734 				HexDes(aValue.UUID().ShortestForm());
       
   735 				break;
       
   736 			case ETypeEncoded:
       
   737 				HexDes(aValue.Des());  // simplest
       
   738 				break;
       
   739 			default:
       
   740 				LOG1(_L("type %d"), aType);
       
   741 			}
       
   742 		}
       
   743     void StartListL(CSdpAttrValueList &/*aList*/)
       
   744 		{
       
   745 		++iIndent;
       
   746 		Indent();
       
   747 		LOG(_L("{"));
       
   748 		}
       
   749     void EndListL()
       
   750 		{
       
   751 		if(iIndent<=0)
       
   752 			{
       
   753 			LOG(_L("ERROR! Unmatched EndList!"));
       
   754 			__DEBUGGER();
       
   755 			}
       
   756 		Indent();
       
   757 		LOG(_L("}"));
       
   758 		--iIndent;
       
   759 		}
       
   760 private:
       
   761 #ifdef _DEBUG
       
   762 	void Indent() {for(TInt i=0; i<iIndent;++i)
       
   763 						LOG(_L("  "));}
       
   764 
       
   765 	void HexDes(const TDesC8& aDes)
       
   766 		{
       
   767 		for (TInt i = 0; i < aDes.Length(); ++i)
       
   768 			LOG1(_L("%02x"), aDes[i]);
       
   769 		};
       
   770 #else
       
   771 	void Indent() {}
       
   772 	void HexDes(const TDesC8&) {}
       
   773 #endif
       
   774 	TInt iIndent;
       
   775 	};
       
   776 
       
   777 void FlogDb(CSdpDatabase& aDb)
       
   778 	{
       
   779 	LOG_STATIC_FUNC
       
   780 	LOG(_L("Printing Database..."));
       
   781 
       
   782 	for(TServRecordIter recIter(aDb.RecordIter()); recIter; recIter++)
       
   783 		{// Iterate thru records in Db
       
   784 		LOG1(_L("...Printing Record 0x%x"), (*recIter).Handle());
       
   785 		for(TServAttrIter attrIter((*recIter).AttributeIter()); attrIter; attrIter++)
       
   786 			{// Iterate thru attributes in record
       
   787 			CAttrPrintVisitor* theVisitor = new CAttrPrintVisitor();
       
   788 			if (theVisitor)
       
   789 				{
       
   790 				TRAP_IGNORE((*attrIter).AcceptVisitorL(*theVisitor));
       
   791 				delete theVisitor;
       
   792 				}
       
   793 			}
       
   794 		}
       
   795 	LOG(_L("End Printing Database..."));
       
   796 	}
       
   797 
       
   798 
       
   799 	
       
   800 static void RunServerL(/*TSdpServerStart& aStart*/)
       
   801 
       
   802 /**
       
   803 Perform all server initialisation, in particular creation of the
       
   804 scheduler and server and then run the scheduler
       
   805 **/
       
   806 	{
       
   807 	LOG_STATIC_FUNC
       
   808 
       
   809 	CActiveScheduler *scheduler = new (ELeave) CActiveScheduler;
       
   810 	CleanupStack::PushL(scheduler); //1st Push
       
   811 	CActiveScheduler::Install(scheduler); 
       
   812 
       
   813 	// create the server (leave it on the cleanup stack)
       
   814 	CSdpServer::NewLC();//2nd Push
       
   815 	//
       
   816 	
       
   817 #ifdef __SDPSERVER_NO_PROCESSES__
       
   818 	RThread::Rendezvous(KErrNone);        // this causes the client's Rendezvous to complete 
       
   819 #else
       
   820 	// naming the server thread after the server helps to debug panics
       
   821 	// ignore the error returned here - it's not critcal
       
   822 	User::RenameThread(KSdpServerName);
       
   823 
       
   824 	// Initialisation complete, now signal the client
       
   825 	RProcess::Rendezvous(KErrNone);        // this causes the client's Rendezvous to complete 
       
   826 #endif
       
   827 	
       
   828 	//
       
   829 	// Ready to run
       
   830 	CActiveScheduler::Start();
       
   831 	//
       
   832 	// Cleanup the server and scheduler
       
   833 	CleanupStack::PopAndDestroy(2);
       
   834 	}
       
   835 
       
   836 
       
   837 TInt E32Main()
       
   838 /**
       
   839 Server process entry-point
       
   840 Recover the startup parameters and run the server
       
   841 **/
       
   842 	{
       
   843 
       
   844 	__UHEAP_MARK;
       
   845 #ifdef TEST_OOM //define TEST_OOM in preprocessor definitions in project settings
       
   846 	__UHEAP_SETFAIL(RHeap::ERandom, 100);	//Qualified - this results in a false positive error from leavescan (... may employ a macro), because the macro name ends with an 'L'.
       
   847 #endif
       
   848 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
   849 	TInt r=KErrNoMemory;
       
   850 	if (cleanup)
       
   851 		{
       
   852 		TRAP(r,RunServerL());
       
   853 		delete cleanup;
       
   854 		}
       
   855 	//
       
   856 	__UHEAP_MARKEND;
       
   857 	
       
   858 	return r;
       
   859 	}
       
   860 
       
   861 
       
   862 //=====================================================================
       
   863 //CSdpServSession
       
   864 //=====================================================================
       
   865 
       
   866 CSdpServer& CSdpServSession::Server()
       
   867 	{
       
   868 	LOG_FUNC
       
   869 	return *static_cast<CSdpServer*>(const_cast<CServer2*>(CSession2::Server()));
       
   870 	}
       
   871 
       
   872 // constructor - must pass client to CSession2
       
   873 CSdpServSession::CSdpServSession(const RMessage2& /*aMessage*/)
       
   874 	{
       
   875 	LOG_FUNC
       
   876 	}
       
   877 
       
   878 void CSdpServSession::CreateL(const CServer2& /*aServer*/)
       
   879 	{
       
   880 	LOG_FUNC
       
   881 	User::Leave(KErrNotSupported); //FIXME - PRE SECURE_API - NEEDED TO AVOID COMPILER WARNING
       
   882 	}
       
   883 
       
   884 void CSdpServSession::CreateL()
       
   885 /**
       
   886 2nd phase construct for sessions - called by the CServer2 framework
       
   887 **/
       
   888 	{
       
   889 	LOG_FUNC
       
   890 	//CSession2::CreateL();	// private and does nowt so removed
       
   891 	//Add session to server first. If anything leaves, it will be removed by the destructor
       
   892 	Server().AddSession();
       
   893 	ConstructL();
       
   894 	}
       
   895 
       
   896 void CSdpServSession::ConstructL()
       
   897 	{
       
   898 	LOG_FUNC
       
   899 	// try to reopen the acceptor
       
   900 	Server().Listener().TryRestartL();
       
   901 	}
       
   902 
       
   903 CSdpServSession::~CSdpServSession()
       
   904 	{
       
   905 	LOG_FUNC
       
   906 	Server().DropSession();
       
   907 	
       
   908 	//Cleanup any records that have been added during this session but not removed
       
   909 	RemoveSessionRecords();
       
   910 	}
       
   911 
       
   912 void CSdpServSession::RemoveSessionRecords()
       
   913 	{
       
   914 	LOG_FUNC
       
   915 	for (TInt index = iSessionRecords.Count()-1; index >= 0; index--)
       
   916 		{
       
   917 		Server().DeleteServiceRecord(iSessionRecords[index]);
       
   918 		}
       
   919 	iSessionRecords.Close();
       
   920 	}
       
   921 
       
   922 void CSdpServSession::ServiceL(const RMessage2& aMessage)
       
   923 /**
       
   924    Handle a client request.
       
   925 **/
       
   926 	{
       
   927 	LOG_FUNC
       
   928 	switch(aMessage.Function())
       
   929 		{
       
   930 	case ESdpCreateAgentSubSession:
       
   931 		NewSubSessionL(ESdpAgent, aMessage);
       
   932 		break;
       
   933 	case ESdpCreateDatabaseSubSession:
       
   934 		NewSubSessionL(ESdpDatabase, aMessage);
       
   935 		break;
       
   936 	case ESdpResourceCountMarkStart:
       
   937 		ResourceCountMarkStart();
       
   938 		aMessage.Complete(KErrNone);
       
   939 		break;
       
   940 	case ESdpResourceCountMarkEnd:
       
   941 		ResourceCountMarkEnd(aMessage); //ss//
       
   942 		aMessage.Complete(KErrNone);
       
   943 		break;
       
   944 	case ESdpResourceCount:
       
   945 		NumResourcesL(aMessage);
       
   946 		break;
       
   947 	case ESdpCloseSubSession:
       
   948 		CloseSubSession(aMessage);
       
   949 		break;
       
   950 
       
   951 	case ESdpDatabaseCreateServiceRecord:
       
   952 		{
       
   953 		if (aMessage.Int3() != KSdpDatabaseSubSessionHandle)
       
   954 			{
       
   955 			PanicClient(aMessage, ESdpBadSubSessionHandle);
       
   956 			return;
       
   957 			}
       
   958 	
       
   959 		CSdpServRecord* newRecord = NULL;
       
   960 		TRAPD(err, newRecord = Server().CreateServiceRecordL(aMessage));
       
   961 		// Inspect iHandle to see if we panicked the client and already completed 
       
   962 		if (aMessage.Handle())
       
   963 			{
       
   964 			if (newRecord)
       
   965 				{
       
   966 				// Update our list of records for this session. Ignore error as
       
   967 				// we wouldn't want to remove the record if an error did occur,
       
   968 				// which is very unlikely as typically only 1 or 2 records are
       
   969 				// added per session.
       
   970 				iSessionRecords.Append(newRecord);
       
   971 				}
       
   972 			aMessage.Complete(err);
       
   973 			}
       
   974 		return;
       
   975 		}
       
   976 	case ESdpDatabaseDeleteServiceRecord:
       
   977 		{
       
   978 		if (aMessage.Int3() != KSdpDatabaseSubSessionHandle)
       
   979 			{
       
   980 			PanicClient(aMessage, ESdpBadSubSessionHandle);
       
   981 			return;
       
   982 			}
       
   983 
       
   984 		CSdpServRecord* recordToBeDeleted = Server().FindAndCheckServiceRecordForDeletion(aMessage);
       
   985 		
       
   986 		// If recordToBeDeleted returned is NULL, PanicClient will have been called so aMessage.Handle() 
       
   987 		// is zero and we've already completed - see if this is not the case  
       
   988 		if (aMessage.Handle())
       
   989 			{
       
   990 			TInt index = iSessionRecords.Find(recordToBeDeleted); // Find the index of the record before deleting the record
       
   991 			// Ignore if the record is not found as it may not have been added
       
   992 			// in the first place.
       
   993 			if (index >= 0)
       
   994 				{
       
   995 				iSessionRecords.Remove(index);
       
   996 				}
       
   997 			Server().DeleteServiceRecord(recordToBeDeleted);
       
   998 			aMessage.Complete(KErrNone);
       
   999 			}
       
  1000 		return;
       
  1001 		}
       
  1002 	case ESdpDatabaseUpdateAttribute:
       
  1003 		{
       
  1004 		if (aMessage.Int3() != KSdpDatabaseSubSessionHandle)
       
  1005 			{
       
  1006 			PanicClient(aMessage, ESdpBadSubSessionHandle);
       
  1007 			return;
       
  1008 			}
       
  1009 
       
  1010 		TRAPD(err, Server().UpdateAttributeL(aMessage));
       
  1011 		// Inspect iHandle to see if we panicked the client and already completed 
       
  1012 		if (aMessage.Handle())
       
  1013 			{
       
  1014 			aMessage.Complete(err);
       
  1015 			}
       
  1016 		return;
       
  1017 		}
       
  1018 	case ESdpDatabaseDeleteAttribute:
       
  1019 		{
       
  1020 		if (aMessage.Int3() != KSdpDatabaseSubSessionHandle)
       
  1021 			{
       
  1022 			PanicClient(aMessage, ESdpBadSubSessionHandle);
       
  1023 			return;
       
  1024 			}
       
  1025 
       
  1026 		Server().DeleteAttribute(aMessage);
       
  1027 		// Inspect iHandle to see if we panicked the client and already completed 
       
  1028 		if (aMessage.Handle())
       
  1029 			{
       
  1030 			aMessage.Complete(KErrNone);
       
  1031 			}
       
  1032 		return;
       
  1033 		}
       
  1034 	case ESdpServerDbgMarkHeap:
       
  1035 		{
       
  1036 #ifdef _DEBUG
       
  1037 		LOG(_L("\tmark sdp server heap"));
       
  1038 		__UHEAP_MARK;
       
  1039 #endif // _DEBUG
       
  1040 		aMessage.Complete(KErrNone);
       
  1041 		break;
       
  1042 		}
       
  1043 	case ESdpServerDbgCheckHeap:
       
  1044 		{
       
  1045 #ifdef _DEBUG
       
  1046 		LOG1(_L("\tcheck sdp server heap (expecting %d cells)"), aMessage.Int0());
       
  1047 		__UHEAP_CHECK(aMessage.Int0());
       
  1048 #endif // _DEBUG
       
  1049 		aMessage.Complete(KErrNone);
       
  1050 		break;
       
  1051 		}
       
  1052 	case ESdpServerDbgMarkEnd:
       
  1053 		{
       
  1054 #ifdef _DEBUG
       
  1055 		LOG1(_L("\tmark end sdp server heap (expecting %d cells)"), aMessage.Int0());
       
  1056 		__UHEAP_MARKENDC(aMessage.Int0());
       
  1057 #endif // _DEBUG
       
  1058 		aMessage.Complete(KErrNone);
       
  1059 		break;
       
  1060 		}
       
  1061 	case ESdpServerDbgFailNext:
       
  1062 		{
       
  1063 #ifdef _DEBUG
       
  1064 		LOG1(_L("\tfail next sdp server alloc (simulating failure after %d allocation(s))"), aMessage.Int0());
       
  1065 		if ( aMessage.Int0() == 0 )
       
  1066 			{
       
  1067 			__UHEAP_RESET;
       
  1068 			}
       
  1069 		else
       
  1070 			{
       
  1071 			__UHEAP_FAILNEXT(aMessage.Int0());
       
  1072 			}
       
  1073 #endif // _DEBUG
       
  1074 		aMessage.Complete(KErrNone);
       
  1075 		break;
       
  1076 		}
       
  1077 	default:
       
  1078 		//not handled here so must be for subsession
       
  1079 		PanicClient(aMessage, ESdpBadRequest);
       
  1080 		}
       
  1081 	}
       
  1082 
       
  1083 void CSdpServSession::NewSubSessionL(TSubSessionType aType, const RMessage2& aMessage)
       
  1084 /**
       
  1085    Increment our subsession count and send the SDP subsession handle
       
  1086    back to the client.
       
  1087    If we succeed, we complete the message.  If we fail, we leave
       
  1088    and the server sends back the error for us.
       
  1089 **/
       
  1090 	{
       
  1091 	LOG_FUNC
       
  1092 	if (aType!=ESdpDatabase)
       
  1093 		{
       
  1094 		User::Leave(KErrNotSupported);
       
  1095 		}
       
  1096 
       
  1097 	//Write handle to client
       
  1098 	TPckg<TInt> pckg(KSdpDatabaseSubSessionHandle);
       
  1099 	TRAPD(err, aMessage.WriteL(3, pckg)); //ss//
       
  1100 	if(err)
       
  1101 		{
       
  1102 		User::Leave(err);
       
  1103 		}
       
  1104 	iSubSessionCount++;
       
  1105 	aMessage.Complete(KErrNone);
       
  1106 	}
       
  1107 
       
  1108 void CSdpServSession::DeleteSubsession(TUint aHandle, const RMessage2& aMessage)
       
  1109 	{
       
  1110 	LOG_FUNC
       
  1111 	//panic client if bad handle
       
  1112 	if ((aHandle != KSdpDatabaseSubSessionHandle) || (iSubSessionCount == 0))
       
  1113 		{
       
  1114 		PanicClient(aMessage, ESdpBadSubSessionRemove);
       
  1115 		return;
       
  1116 		}
       
  1117 	iSubSessionCount--;
       
  1118 	aMessage.Complete(KErrNone);
       
  1119 	}
       
  1120 
       
  1121 void CSdpServSession::CloseSubSession(const RMessage2& aMessage)
       
  1122 	{
       
  1123 	LOG_FUNC
       
  1124 
       
  1125 	DeleteSubsession((aMessage).Int3(), aMessage); //calls aMessage.Complete(KErrNone)	
       
  1126 	}
       
  1127 
       
  1128 void CSdpServSession::NumResourcesL(const RMessage2& aMessage)
       
  1129 	{
       
  1130 	LOG_FUNC
       
  1131 	TPckgBuf<TInt> pckg(CountResources());
       
  1132 	aMessage.WriteL(0, pckg); //ss//
       
  1133 	aMessage.Complete(KErrNone);
       
  1134 	}
       
  1135 
       
  1136 TInt CSdpServSession::CountResources()
       
  1137 	{
       
  1138 	LOG_FUNC
       
  1139 	return iSubSessionCount;
       
  1140 	}
       
  1141 
       
  1142 
       
  1143 //**********************************
       
  1144 // CEirPublisherSdpUuidBase
       
  1145 //**********************************
       
  1146 /**
       
  1147 CEirPublisherSdpUuidBase provides base class for Sdp Uuid Eir Publisher.
       
  1148 **/
       
  1149 
       
  1150 CEirPublisherSdpUuidBase::~CEirPublisherSdpUuidBase()
       
  1151 	{
       
  1152 	delete iPublisher;
       
  1153 	}
       
  1154 
       
  1155 CEirPublisherSdpUuidBase::CEirPublisherSdpUuidBase(CSdpUuidManager& aSdpUuidManager, TEirTag aTag)
       
  1156 : iParent(aSdpUuidManager), iTag(aTag)
       
  1157 	{
       
  1158 	}
       
  1159 
       
  1160 void CEirPublisherSdpUuidBase::ConstructL()
       
  1161 	{
       
  1162 	iPublisher = CEirPublisher::NewL(iTag, *this);
       
  1163 	}
       
  1164 
       
  1165 void CEirPublisherSdpUuidBase::UpdateUuids(TInt aLength)
       
  1166 	{
       
  1167 	iPublisher->PublishData(aLength);
       
  1168 	}
       
  1169 
       
  1170 //**********************************
       
  1171 // CEirPublisherSdpUuid16
       
  1172 //**********************************
       
  1173 /**
       
  1174 Provides functionality to publish 16 bit UUIDs to EIR.
       
  1175 **/
       
  1176 CEirPublisherSdpUuid16* CEirPublisherSdpUuid16::NewL(CSdpUuidManager& aSdpUuidManager)
       
  1177 	{
       
  1178 	CEirPublisherSdpUuid16* self = new (ELeave) CEirPublisherSdpUuid16(aSdpUuidManager);
       
  1179 	CleanupStack::PushL(self);
       
  1180 	self->ConstructL();
       
  1181 	CleanupStack::Pop();
       
  1182 	return self;
       
  1183 	}
       
  1184 	
       
  1185 CEirPublisherSdpUuid16::CEirPublisherSdpUuid16(CSdpUuidManager& aSdpUuidManager)
       
  1186 :	CEirPublisherSdpUuidBase(aSdpUuidManager, EEirTagSdpUuid16)
       
  1187 	{
       
  1188 	}
       
  1189 
       
  1190 CEirPublisherSdpUuid16::~CEirPublisherSdpUuid16()
       
  1191 	{
       
  1192 	delete iExtracted;
       
  1193 	}
       
  1194 
       
  1195 // From MEirPublisherNotifier
       
  1196 void CEirPublisherSdpUuid16::MepnSpaceAvailable(TUint aBytesAvailable)
       
  1197 	{
       
  1198 	// Ensure previous memory is freed
       
  1199 	delete iExtracted, iExtracted = NULL;
       
  1200 	TBool partial = EFalse;
       
  1201 	
       
  1202 	if (aBytesAvailable > 0)
       
  1203 		{
       
  1204 		iExtracted = iParent.GetAll16BitUUIDs(aBytesAvailable, partial);
       
  1205 		if(!iExtracted)
       
  1206 			{
       
  1207 			// OOM probably
       
  1208 			iPublisher->SetData(KNullDesC8, EEirDataPartial);
       
  1209 			}
       
  1210 		else if(partial)
       
  1211 			{
       
  1212 			iPublisher->SetData(*iExtracted, EEirDataPartial);
       
  1213 			}
       
  1214 		else
       
  1215 			{
       
  1216 			iPublisher->SetData(*iExtracted, EEirDataComplete);
       
  1217 			}
       
  1218 		}
       
  1219 	}
       
  1220 
       
  1221 void CEirPublisherSdpUuid16::MepnSetDataError(TInt /*aResult*/)
       
  1222 	{
       
  1223 	delete iExtracted;
       
  1224 	iExtracted = NULL;
       
  1225 	}
       
  1226 
       
  1227 
       
  1228 //**********************************
       
  1229 // CEirPublisherSdpUuid128
       
  1230 //**********************************
       
  1231 /**
       
  1232 Provides functionality to publish 128 bit UUIDs to EIR.
       
  1233 **/
       
  1234 CEirPublisherSdpUuid128* CEirPublisherSdpUuid128::NewL(CSdpUuidManager& aSdpUuidManager)
       
  1235 	{
       
  1236 	CEirPublisherSdpUuid128* self = new (ELeave) CEirPublisherSdpUuid128(aSdpUuidManager);
       
  1237 	CleanupStack::PushL(self);
       
  1238 	self->ConstructL();
       
  1239 	CleanupStack::Pop();
       
  1240 	return self;
       
  1241 	}
       
  1242 	
       
  1243 CEirPublisherSdpUuid128::CEirPublisherSdpUuid128(CSdpUuidManager& aSdpUuidManager)
       
  1244 :	CEirPublisherSdpUuidBase(aSdpUuidManager, EEirTagSdpUuid128)
       
  1245 	{
       
  1246 	}
       
  1247 
       
  1248 CEirPublisherSdpUuid128::~CEirPublisherSdpUuid128()
       
  1249 	{
       
  1250 	delete iExtracted;
       
  1251 	}
       
  1252 
       
  1253 // From MEirPublisherNotifier
       
  1254 void CEirPublisherSdpUuid128::MepnSpaceAvailable(TUint aBytesAvailable)
       
  1255 	{
       
  1256 	// Ensure previous memory is freed
       
  1257 	delete iExtracted, iExtracted = NULL;
       
  1258 	TBool partial = EFalse;
       
  1259 	
       
  1260 	if (aBytesAvailable > 0)
       
  1261 		{
       
  1262 		iExtracted = iParent.GetAll128BitUUIDs(aBytesAvailable, partial);
       
  1263 		if(!iExtracted)
       
  1264 			{
       
  1265 			// OOM probably
       
  1266 			iPublisher->SetData(KNullDesC8, EEirDataPartial);
       
  1267 			}
       
  1268 		else if(partial)
       
  1269 			{
       
  1270 			iPublisher->SetData(*iExtracted, EEirDataPartial);
       
  1271 			}
       
  1272 		else
       
  1273 			{
       
  1274 			iPublisher->SetData(*iExtracted, EEirDataComplete);
       
  1275 			}
       
  1276 		}
       
  1277 	}
       
  1278 
       
  1279 void CEirPublisherSdpUuid128::MepnSetDataError(TInt /*aResult*/)
       
  1280 	{
       
  1281 	delete iExtracted;
       
  1282 	iExtracted = NULL;
       
  1283 	}
       
  1284 
       
  1285 
       
  1286 CSdpUuidManager* CSdpUuidManager::NewL(CSdpDatabase& aSdpDatabase)
       
  1287 	{
       
  1288 	CSdpUuidManager* self = new (ELeave) CSdpUuidManager(aSdpDatabase);
       
  1289 	CleanupStack::PushL(self);
       
  1290 	self->ConstructL();
       
  1291 	CleanupStack::Pop();
       
  1292 	return self;
       
  1293 	}
       
  1294 	
       
  1295 CSdpUuidManager::~CSdpUuidManager()
       
  1296 	{
       
  1297 	i16BitUUIDs.Close();
       
  1298 	i128BitUUIDs.Close();
       
  1299 	
       
  1300 	delete iEirPublisherSdpUuid16;
       
  1301 	delete iEirPublisherSdpUuid128;
       
  1302 	delete iUuidVisitor;
       
  1303 	}
       
  1304 
       
  1305 void CSdpUuidManager::NotifySdpRecordChange()
       
  1306 	{
       
  1307 	TServRecordIter recIter(iSdpDatabase.RecordIter());
       
  1308 	CSdpServRecord* rec = NULL;
       
  1309 	CSdpAttr* attr = NULL;
       
  1310 	CSdpAttrValue* serviceClassValue = NULL;
       
  1311 	CSdpAttrValue* browseGroupValue = NULL;
       
  1312 	
       
  1313 	ResetUuids();
       
  1314 	while((rec = recIter++) != NULL)
       
  1315 		{// Iterate thru records in Db
       
  1316 		TServAttrIter attrIter(rec->AttributeIter());
       
  1317 		while((attr = attrIter++) != NULL)
       
  1318 			{
       
  1319 			if(attr->AttributeID()==KSdpAttrIdServiceClassIDList)
       
  1320 				{
       
  1321 				// Find the value of ServiceClassIDList attribute
       
  1322 				serviceClassValue = &(attr->Value());
       
  1323 				}
       
  1324 			if(attr->AttributeID()==KSdpAttrIdBrowseGroupList)
       
  1325 				{
       
  1326 				// Find the value of BrowseGroupList attribute
       
  1327 				browseGroupValue = &(attr->Value());
       
  1328 				}
       
  1329 			}
       
  1330 		if(serviceClassValue && browseGroupValue)
       
  1331 			{
       
  1332 			// Both ServiceClassIDList and BrowseGroupList have value
       
  1333 			iUuidVisitor->GetUuids().Reset();
       
  1334 			TRAPD(err, browseGroupValue->AcceptVisitorL(*iUuidVisitor));
       
  1335 			if(err == KErrNone)
       
  1336 				{
       
  1337 				TUUID publicBrowseGroupUUID = TUUID(static_cast<TUint32>(KPublicBrowseGroupUUID));
       
  1338 				if(iUuidVisitor->GetUuids().IsPresent(publicBrowseGroupUUID))
       
  1339 					{
       
  1340 					iUuidVisitor->GetUuids().Reset();
       
  1341 					TRAPD(err, serviceClassValue->AcceptVisitorL(*iUuidVisitor));
       
  1342 					if(err == KErrNone && iUuidVisitor->GetUuids().Count() > 0)
       
  1343 						{
       
  1344 						// In eir, we use the 1st uuid on the list, as it is the most specific one
       
  1345 						AddUuid(iUuidVisitor->GetUuids()[0]);
       
  1346 						}
       
  1347 					}
       
  1348 				}
       
  1349 			}
       
  1350 		// Reset the pointers for these two values
       
  1351 		serviceClassValue = NULL;
       
  1352 		browseGroupValue = NULL;
       
  1353 		}
       
  1354 	// Only publish UUIDs in public browse group
       
  1355 	// 16 bit UUIDs
       
  1356 	TUint8 count = i16BitUUIDs.Count();
       
  1357 	// Skip the 1st 16 bit uuid record, it's a SDP service UUID
       
  1358 	if(count > 0)
       
  1359 		{
       
  1360 		// UpdateUuids expects the length in bytes, so multiply number of uuids by 2
       
  1361 		iEirPublisherSdpUuid16->UpdateUuids(count<<1);
       
  1362 		}
       
  1363 		
       
  1364 	// 128 bit UUIDs
       
  1365 	count = i128BitUUIDs.Count();
       
  1366 	if(count > 0)
       
  1367 		{
       
  1368 		// UpdateUuids expects the length in bytes, so multiply number of uuids by 16
       
  1369 		iEirPublisherSdpUuid128->UpdateUuids(count<<4);
       
  1370 		}
       
  1371 	}
       
  1372 
       
  1373 void CSdpUuidManager::AddUuid(TUUID aUuid)
       
  1374 	{
       
  1375 	TUint8 count = aUuid.MinimumSize();
       
  1376 	if(count == KSizeOf16BitUUID)
       
  1377 		{
       
  1378 		// 16 bit UUID
       
  1379 		i16BitUUIDs.Add(aUuid);
       
  1380 		}
       
  1381 	else if(count == KSizeOf128BitUUID)
       
  1382 		{
       
  1383 		// 128 bit UUID
       
  1384 		i128BitUUIDs.Add(aUuid);
       
  1385 		}
       
  1386 	else
       
  1387 		{
       
  1388 		// 32 bit UUIDs are not supported
       
  1389 		}
       
  1390 	}
       
  1391 
       
  1392 void CSdpUuidManager::ResetUuids()
       
  1393 	{
       
  1394 	i16BitUUIDs.Reset();
       
  1395 	i128BitUUIDs.Reset();
       
  1396 	}
       
  1397 
       
  1398 HBufC8* CSdpUuidManager::GetAll16BitUUIDs(TInt aBytesAvailable, TBool& aPartial)
       
  1399 	{
       
  1400 	// Flatten the UUIDs into a little-endian buffer
       
  1401 	HBufC8* extracted = HBufC8::New(aBytesAvailable);
       
  1402 	if(extracted)
       
  1403 		{
       
  1404 		TPtr8 ptr = extracted->Des();
       
  1405 		TInt i = 0;
       
  1406 		TInt count = i16BitUUIDs.Count();
       
  1407 		// Iterate whilst not exhausted and there's space for a UUID
       
  1408 		while (i < count && ptr.Length() + KSizeOf16BitUUID <= aBytesAvailable)
       
  1409 			{
       
  1410 			// convert to 16 bit Little Endian for EIR
       
  1411 			TPtrC8 p = i16BitUUIDs[i].ShortestForm();
       
  1412 			ptr.Append(p[1]);
       
  1413 			ptr.Append(p[0]);
       
  1414 			i++;
       
  1415 			}
       
  1416 		__ASSERT_DEBUG(extracted->Length() <= aBytesAvailable, Panic(ESdpServerUuidFlattenBroken));
       
  1417 		// Let the caller know if there wasn't enough space for all UUIDs
       
  1418 		aPartial = EFalse;
       
  1419 		if (i < count)
       
  1420 			{
       
  1421 			aPartial = ETrue;
       
  1422 			}
       
  1423 		}
       
  1424 	return extracted;
       
  1425 	}
       
  1426 
       
  1427 HBufC8* CSdpUuidManager::GetAll128BitUUIDs(TInt aBytesAvailable, TBool& aPartial)
       
  1428 	{
       
  1429 	// Flatten the UUIDs into a little-endian buffer
       
  1430 	HBufC8* extracted = HBufC8::New(aBytesAvailable);
       
  1431 	if(extracted)
       
  1432 		{
       
  1433 		TPtr8 ptr = extracted->Des();
       
  1434 		TInt i = 0;
       
  1435 		TInt count = i128BitUUIDs.Count();
       
  1436 		
       
  1437 		// Iterate whilst not exhausted and there's space for a UUID
       
  1438 		while (i < count && ptr.Length() + KSizeOf128BitUUID <= aBytesAvailable)
       
  1439 			{
       
  1440 			// convert to 128 bits Little Endian for EIR
       
  1441 			for (TUint j = 1; j<= KSdpUUIDMaxLength ;j++)
       
  1442 				{
       
  1443 				ptr.Append(i128BitUUIDs[i][KSdpUUIDMaxLength - j]);
       
  1444 				}
       
  1445 			i++;
       
  1446 			}
       
  1447 		__ASSERT_DEBUG(extracted->Length() <= aBytesAvailable, Panic(ESdpServerUuidFlattenBroken));
       
  1448 		// Let the caller know if there wasn't enough space for all UUIDs
       
  1449 		aPartial = EFalse;
       
  1450 		if (i < count)
       
  1451 			{
       
  1452 			aPartial = ETrue;
       
  1453 			}
       
  1454 		}
       
  1455 	return extracted;
       
  1456 	}
       
  1457 
       
  1458 CSdpUuidManager::CSdpUuidManager(CSdpDatabase& aSdpDatabase)
       
  1459 : iSdpDatabase(aSdpDatabase)
       
  1460 	{
       
  1461 	}
       
  1462 	
       
  1463 void CSdpUuidManager::ConstructL()
       
  1464 	{
       
  1465 	iUuidVisitor = CAttrUuidVisitor::NewL();
       
  1466 	iEirPublisherSdpUuid16 = CEirPublisherSdpUuid16::NewL(*this);
       
  1467 	iEirPublisherSdpUuid128 = CEirPublisherSdpUuid128::NewL(*this);
       
  1468 	}
       
  1469