obex/obexprotocol/obex/src/obexserver.cpp
changeset 54 4dc88a4ac6f4
parent 52 866b4af7ffbe
child 57 f6055a57ae18
equal deleted inserted replaced
52:866b4af7ffbe 54:4dc88a4ac6f4
     1 // Copyright (c) 1997-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 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <charconv.h>
       
    22 #include <utf.h>
       
    23 #include <obex/internal/obexinternalheader.h>
       
    24 #include <obextransportinfo.h>
       
    25 #include <obex.h>
       
    26 #include <obex/internal/obexpacket.h>
       
    27 #include <obex/transport/obextransportcontrollerbase.h>
       
    28 #include <obex/internal/obextransportconstants.h>
       
    29 #include <obex/extensionapis/mobexserverrequestpacketnotify.h>
       
    30 #include <obex/internal/mobexserverrequestpacketnotifyregister.h>
       
    31 #include "logger.h"
       
    32 #include "obexsetpathdata.h"
       
    33 #include "OBEXUTIL.H"
       
    34 #include "authentication.h"
       
    35 #include "obexnotifyhandlerserver.h"
       
    36 #include "obexserverstatemachine.h"
       
    37 #include "obexservernotifysyncwrapper.h"
       
    38 #include "obexheaderutil.h"
       
    39 #include "obexserverrequestpacketengine.h"
       
    40 #include "obexpacketsignaller.h"
       
    41 
       
    42 #ifdef __FLOG_ACTIVE
       
    43 _LIT8(KLogComponent, "OBEX");
       
    44 #endif
       
    45 
       
    46 /**
       
    47 Constructor - set initial values 
       
    48 @internalTechnology
       
    49 */
       
    50 CObexServer::CObexServer() : CObex()
       
    51 	{
       
    52 	iCurrentOperation = EOpIdle;
       
    53 	iEnabled = EFalse;
       
    54 
       
    55 	//the connectionID is fixed at the moment
       
    56 	ResetConnectionID();
       
    57 	SetConnectionID(0xc30fa596);
       
    58 
       
    59 	iTargetChecking = EIfPresent;
       
    60 	}
       
    61 
       
    62 void CObexServer::ConstructL(TObexTransportInfo& aObexTransportInfo)
       
    63 	{
       
    64 	CObex::ConstructL(aObexTransportInfo);
       
    65 	iNotifyHandler = new(ELeave)CObexNotifyHandlerServer(*this);
       
    66 	iTransportController->SetOwner(*iNotifyHandler);
       
    67 
       
    68 	iHeader = CObexHeader::NewL();
       
    69 	iStateMachine = CObexServerStateMachine::NewL(*this, *iTransportController);
       
    70 	iSyncWrapper = CObexServerNotifySyncWrapper::NewL(*this, *iStateMachine);
       
    71 	iPacketProcessSignaller = CObexPacketSignaller::NewL();
       
    72 	}
       
    73 
       
    74 /**
       
    75 Destructor. 
       
    76 */
       
    77 CObexServer::~CObexServer()
       
    78 	{
       
    79 	FLOG(_L("CObexServer Destructor\r\n"));
       
    80 	Stop();
       
    81 	
       
    82 	delete iPacketProcessSignaller;
       
    83 	delete iSyncWrapper;
       
    84 	delete iStateMachine;
       
    85 	delete iHeader;
       
    86 	delete iNotifyHandler;
       
    87 	delete iServerRequestPacketEngine;
       
    88 	}
       
    89 
       
    90 void CObexServer::ResetConnectionID()
       
    91 	{
       
    92 	iConnectionID = KConnIDInvalid;
       
    93 	iConnectionIdSet = EFalse;
       
    94 	}
       
    95 
       
    96 void CObexServer::SetConnectionID(TUint32 aConnectionID)
       
    97 	{
       
    98 	iConnectionID = aConnectionID;
       
    99 	iConnectionIdSet = ETrue;
       
   100 	}
       
   101 
       
   102 TUint32 CObexServer::ConnectionID()
       
   103 	{
       
   104 	return (iConnectionID);
       
   105 	}
       
   106 
       
   107 TInt CObexServer::PrepareFinalChallResponse(CObexPacket& aPacket, TConnectState& aNextState)
       
   108 	{
       
   109 
       
   110 	FLOG(_L("CObexServer::PrepareFinalChallResponse\r\n"));
       
   111 
       
   112 	aPacket.SetOpcode(ERespSuccess); 
       
   113 
       
   114 	TInt retValue = AddConnectionIDHeader(aPacket);	
       
   115 	if (retValue == KErrNone)
       
   116 		{
       
   117 		FLOG(_L("PrepareFinalChallResponse ConnectionID header Added\r\n"));
       
   118 		if (iCallBack)
       
   119 			{
       
   120 			FLOG(_L("PrepareFinalChallResponse Requesting User Password\r\n"));
       
   121 
       
   122 			//the actual asking of the password happens later in the method OnPacketReceive
       
   123 			//wait for the reply
       
   124 			aNextState = EWaitForUserInput;
       
   125 			retValue = KErrGeneral; //mustn't send yet wait for reply from user
       
   126 			}
       
   127 		else //else can't Auth challenge so drop link
       
   128 			{
       
   129 			FLOG(_L("PrepareFinalChallResponse Can't request User Password for Chall dropping link\r\n"));
       
   130 
       
   131 			retValue = KErrIrObexConnectChallRejected;
       
   132 			aNextState = EConnTransport;
       
   133 			aPacket.SetOpcode(ERespNotImplemented);
       
   134 			}
       
   135 		}
       
   136 	else
       
   137 		{
       
   138 		aNextState = EDropLink;
       
   139 		}
       
   140 	return (retValue);
       
   141 	}
       
   142 
       
   143 
       
   144 /** A call back from the the service with the password required for use with generating 
       
   145 the challenge response. 
       
   146 
       
   147 @param aPassword Password
       
   148 
       
   149 @leave KErrNotReady if this function is not called from a MObexAuthChallengeHandler::GetUserPasswordL callback.
       
   150 
       
   151 @publishedAll
       
   152 @released
       
   153 */
       
   154 EXPORT_C void CObexServer::UserPasswordL(const TDesC& aPassword)
       
   155 	{
       
   156 	LOG_LINE
       
   157 	LOG_FUNC
       
   158 
       
   159 	//now have a password, get a nonce, and get it hashed then reply
       
   160 	if (GetConnectState() == EWaitForUserInput)
       
   161 		{
       
   162 		FLOG(_L("CObexServer::UserPasswordL\r\n"));
       
   163 		PrepareChallResponseL(aPassword);
       
   164 		FLOG(_L("UserPasswordL - PrepareChallResponse Success\r\n"));
       
   165 
       
   166 		TObexInternalHeader hdr;
       
   167 		hdr.Set(TObexInternalHeader::EAuthResponse, (const_cast<TUint8*> (iOutgoingChallResp.Ptr())), iOutgoingChallResp.Size());
       
   168 		if(iTransportController->SendPacket().InsertData(hdr))
       
   169 			{
       
   170 			FLOG(_L("UserPasswordL Inserting EAuthResponse Header\r\n"));
       
   171 
       
   172 			SetConnectState(EConnObex); //all finished
       
   173 			iTransportController->SendPacket().SetFinal();
       
   174 			iTransportController->Send();
       
   175 			//inform the client that the connection was succesfull
       
   176 			iOwner->ObexConnectIndication(iRemoteInfo, TPtr8(NULL, 0));
       
   177 			iStateMachine->ConnectionComplete();
       
   178 			}
       
   179 		else
       
   180 			{
       
   181 			User::Leave(KErrGeneral);
       
   182 			}
       
   183 		}
       
   184 	else
       
   185 		{
       
   186 		User::Leave(KErrNotReady);
       
   187 		}
       
   188 	}
       
   189 
       
   190 
       
   191 TInt CObexServer::AddConnectionIDHeader(CObexPacket& aPacket)
       
   192 	{
       
   193 	TInt retValue = KErrNone;
       
   194 	//if the Target header was used for the connection
       
   195 	//then reply with ConnectionID and Who headers
       
   196 	if(iTargetReceived)
       
   197 		{
       
   198 		//this solution can only handle one connection at a time therefore
       
   199 		//can safely use the same connection ID repeatedly
       
   200 		//when used the ConnectionID must be first
       
   201 		TObexInternalHeader hdr;
       
   202 		FLOG(_L("CObexServer::AddConnectionIDHeader Inserting EConnectionID Header\r\n"));
       
   203  
       
   204  		hdr.Set(TObexInternalHeader::EConnectionID, iConnectionID);
       
   205 		
       
   206 		if(aPacket.InsertData(hdr))
       
   207 			{ 
       
   208 			// Connection ID header inserted correctly
       
   209 			// Now set a WHO header.
       
   210 			// This logic is a bit backwards due to problems with the 'no target header checking'
       
   211 			// state.  Instead of inserting our local Who header, we copy the Target header back.
       
   212 			// This works in the checking states because we drop any connection where the local
       
   213 			// Who is not identical to the Target header received.
       
   214 			// When not checking targets, this may mean that the client gets connected to a server
       
   215 			// which knows nothing about the service, yet thinks it is talking to a strict peer.
       
   216 			// However the server wouldn't understand what was going on anyway, so we're not really
       
   217 			// in a worse state than we would be if we did something more fancy.  Ultimately the
       
   218 			// application must drop the connection---probably by deleting the Obex server or
       
   219 			// returning errors to all attempted operations.
       
   220 			
       
   221 			FLOG(_L("CObexServer::AddConnectionIDHeader Inserting EWho Header\r\n"));
       
   222 
       
   223 			hdr.Set(TObexInternalHeader::EWho, (const_cast<TUint8*> (iRemoteInfo.iTargetHeader.Ptr())), 
       
   224 																iRemoteInfo.iTargetHeader.Size());
       
   225 			if(!aPacket.InsertData(hdr))
       
   226 				{
       
   227 				retValue = KErrGeneral;
       
   228 				}
       
   229 			}
       
   230 		else
       
   231 			{
       
   232 			retValue = KErrGeneral;
       
   233 			}
       
   234 		}
       
   235 	return (retValue);
       
   236 	}
       
   237 
       
   238 /**
       
   239 Allocates and constructs a new OBEX server object.
       
   240 
       
   241 The received protocol information object, aObexProtocolInfoPtr, specifies the 
       
   242 transport protocol to use:
       
   243 For the standard transports the following are used, TObexIrProtocolInfo for 
       
   244 IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
       
   245 
       
   246 @param aObexProtocolInfoPtr Protocol information object describing the 
       
   247 transport to use
       
   248 @return New OBEX server object 
       
   249 
       
   250 @publishedAll
       
   251 @released
       
   252 */
       
   253 EXPORT_C CObexServer* CObexServer::NewL(TObexProtocolInfo& aObexProtocolInfoPtr)
       
   254 	{
       
   255 	LOG_LINE
       
   256 	LOG_STATIC_FUNC_ENTRY
       
   257 
       
   258 	TObexProtocolPolicy defaultProtocolPolicy;	// no packet sizing policy specified, so use default		
       
   259 	TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, defaultProtocolPolicy);
       
   260 	CleanupStack::PushL(transportInfo);
       
   261 	CObexServer* server = CObexServer::NewL(*transportInfo);
       
   262 	CleanupStack::PopAndDestroy(transportInfo);
       
   263 	return server;
       
   264 	}
       
   265 
       
   266 /**
       
   267 Allocates and constructs a new OBEX server object with packet sizing 
       
   268 information.
       
   269 
       
   270 The received protocol information object, aObexProtocolInfoPtr, specifies the 
       
   271 transport protocol to use:
       
   272 For the standard transports the following are used, TObexIrProtocolInfo for 
       
   273 IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
       
   274 
       
   275 The aObexProtocolPolicy parameter specifies the packet sizing policy for this 
       
   276 OBEX object.
       
   277 
       
   278 @param aObexProtocolInfoPtr Protocol information object describing the 
       
   279 transport to use
       
   280 @param aObexProtocolPolicy Protocol policy object specifying the packet sizes 
       
   281 to use
       
   282 @return New OBEX server object 
       
   283 	
       
   284 @publishedAll
       
   285 @released
       
   286 */
       
   287 EXPORT_C CObexServer* CObexServer::NewL(TObexProtocolInfo& aObexProtocolInfoPtr, 
       
   288 										TObexProtocolPolicy& aObexProtocolPolicy)
       
   289 	{
       
   290 	LOG_LINE
       
   291 	LOG_STATIC_FUNC_ENTRY
       
   292 
       
   293 	TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, aObexProtocolPolicy);	
       
   294 	CleanupStack::PushL(transportInfo);
       
   295 	CObexServer* server =  CObexServer::NewL(*transportInfo);
       
   296 	CleanupStack::PopAndDestroy(transportInfo);
       
   297 	return server;
       
   298 	}
       
   299 
       
   300 /** 
       
   301 Allocates and constructs a new OBEX server object with packet sizing 
       
   302 information.
       
   303 
       
   304 The received transport information object, aObexTransportInfo, specifies the 
       
   305 transport protocol and packet sizes to use:
       
   306 For the standard transports the following are used, TObexIrProtocolInfo for 
       
   307 IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
       
   308 
       
   309 @param aObexTransportInfo  Transport information object describing the 
       
   310 transport and packet sizes  to use
       
   311 @return New OBEX server object 
       
   312 
       
   313 @capability WriteDeviceData If the TObexIrV3TransportInfo is passed as the argument
       
   314                             and the associated name is valid.
       
   315 
       
   316 @publishedAll
       
   317 @released
       
   318 */
       
   319 EXPORT_C CObexServer* CObexServer::NewL(TObexTransportInfo& aObexTransportInfo)
       
   320 	{
       
   321 	LOG_LINE
       
   322 	LOG_STATIC_FUNC_ENTRY
       
   323 
       
   324 	CObexServer* self = new(ELeave) CObexServer();
       
   325 	CleanupStack::PushL(self);
       
   326 	self->ConstructL(aObexTransportInfo);
       
   327 	CleanupStack::Pop(self);
       
   328 	return(self);
       
   329 	}
       
   330 
       
   331 /** Starts the server, specifying a synchronous notification interface.
       
   332 
       
   333 If the server is already started, no state changes occur (i.e. any connections/operations 
       
   334 in progress are not interrupted), but the notifications will be sent to aOwner. 
       
   335 This allows "child" servers to take over ownership of existing connections. 
       
   336 
       
   337 Details of this function behaviour depend on the transport specified when 
       
   338 constructed: in general a listener socket is created, its port number registered 
       
   339 as appropriate, and an accept queued.
       
   340 
       
   341 @param aOwner Server notification interface
       
   342 @return KErrArgument if parameter is NULL, KErrAlreadyExists if server has already
       
   343 been started (but notification object will still be updated), otherwise a system wide
       
   344 error code 
       
   345 @panic OBEX EChangeInterfaceDuringWait when attempting to change the interface at an inappropriate time.
       
   346 
       
   347 @publishedAll
       
   348 @released
       
   349 */
       
   350 EXPORT_C TInt CObexServer::Start(MObexServerNotify* aOwner)
       
   351 	{
       
   352 	LOG_LINE
       
   353 	LOG_FUNC
       
   354 
       
   355 	if(aOwner == NULL)
       
   356 		{
       
   357 		return(KErrArgument);
       
   358 		}
       
   359 	
       
   360 	// Pass this synchronous interface to the synchronous wrapper
       
   361 	// and pass the synchronous wrapper on to the asynchronous Start()
       
   362 	iSyncWrapper->SetNotifier(aOwner);
       
   363 	return Start(iSyncWrapper);
       
   364 	}
       
   365 
       
   366 
       
   367 /** Starts the server, specifying an asynchronous notification interface.
       
   368 
       
   369 If the server is already started, no state changes occur (i.e. any connections/operations 
       
   370 in progress are not interrupted), but the notifications will be sent to aOwner. 
       
   371 This allows "child" servers to take over ownership of existing connections. 
       
   372 
       
   373 Details of this function behaviour depend on the transport specified when 
       
   374 constructed: in general a listener socket is created, its port number registered 
       
   375 as appropriate, and an accept queued.
       
   376 
       
   377 @param aOwner Server notification interface
       
   378 @return KErrArgument if parameter is NULL, KErrAlreadyExists if server has already
       
   379 been started (but notification object will still be updated), otherwise a system wide
       
   380 error code 
       
   381 @panic OBEX EChangeInterfaceDuringWait when attempting to change the interface at an inappropriate time.
       
   382 
       
   383 @publishedAll
       
   384 @released
       
   385 */
       
   386 EXPORT_C TInt CObexServer::Start(MObexServerNotifyAsync* aOwner)
       
   387 	{
       
   388 	if(aOwner == NULL)
       
   389 		{
       
   390 		return(KErrArgument);
       
   391 		}
       
   392 
       
   393 	iOwner = aOwner;											
       
   394 
       
   395 	iStateMachine->Start(*iOwner);
       
   396 	if(iEnabled)
       
   397 		{
       
   398 		return(KErrAlreadyExists);
       
   399 		}
       
   400 	iEnabled = ETrue;
       
   401 	return(AcceptConnection());
       
   402 	}
       
   403 	
       
   404 
       
   405 /** Disconnects any transfer in progress and disables further connections. 
       
   406 
       
   407 @publishedAll
       
   408 @released
       
   409 */
       
   410 EXPORT_C void CObexServer::Stop()
       
   411 	{// Cancel and Disable accepts, and bring and transport down.
       
   412 	LOG_LINE
       
   413 	LOG_FUNC
       
   414 
       
   415 	if(!iEnabled)
       
   416 		{
       
   417 		return;
       
   418 		}
       
   419 	iEnabled = EFalse;
       
   420 	ControlledTransportDown();
       
   421 	
       
   422 	// just check that iTransportController is still valid here (that is what we
       
   423 	// aspect to be)
       
   424 	__ASSERT_DEBUG(iTransportController, IrOBEXUtil::Fault(ETransportControllerNotCreated));
       
   425 	
       
   426 	iTransportController->CancelAccept();
       
   427 	iStateMachine->Stop();
       
   428 	iOwner = NULL;
       
   429 	iSyncWrapper->SetNotifier(NULL);
       
   430 	}
       
   431 
       
   432 TInt CObexServer::AcceptConnection()
       
   433 	{
       
   434 	if(iEnabled && iOwner)
       
   435 		{
       
   436 		iCurrentOperation = EOpIdle;
       
   437 		TRAPD(err, iTransportController->AcceptConnectionL());
       
   438 		if(err != KErrNone)
       
   439 			{
       
   440 			iEnabled = EFalse;
       
   441 			}
       
   442 		return(err);
       
   443 		}
       
   444 	else
       
   445 		{
       
   446 		return(KErrNone);
       
   447 		}
       
   448 	}
       
   449 
       
   450 
       
   451 
       
   452 /** Sets a password required to access the server.
       
   453 
       
   454 When a password is set, a client must specify it to access the server.
       
   455 
       
   456 @param aPassword Password 
       
   457 
       
   458 @publishedAll
       
   459 @released
       
   460 */
       
   461 EXPORT_C void CObexServer::SetChallengeL(const TDesC& aPassword)
       
   462 	{
       
   463 	LOG_LINE
       
   464 	LOG_FUNC
       
   465 
       
   466 	delete iChallPassword;
       
   467 	iChallPassword = NULL;
       
   468 	iChallPassword = HBufC8::NewL(aPassword.Length());
       
   469 	TPtr8 ptr = iChallPassword->Des();
       
   470 	CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword);
       
   471 	iChallenge = ETrue;
       
   472 	}
       
   473 
       
   474 /** Resets the password.
       
   475 
       
   476 After this call, a client does not need to provide a password to access the 
       
   477 server. 
       
   478 
       
   479 @publishedAll
       
   480 @released
       
   481 */
       
   482 EXPORT_C void CObexServer::ResetChallenge()
       
   483 	{
       
   484 	LOG_LINE
       
   485 	LOG_FUNC
       
   486 
       
   487 	delete iChallPassword;
       
   488 	iChallPassword = NULL;
       
   489 	iChallenge = EFalse;
       
   490 	}
       
   491 
       
   492 /**	
       
   493 Specifies target header checking behaviour.
       
   494 	
       
   495 Supports three behaviours---never check, always check, and check only if a target
       
   496 header has been sent.  The default behaviour is to only check when a target header
       
   497 has been sent.
       
   498 	
       
   499 No checking allows a form of multiplexing to be used, where one server object may
       
   500 respond to multiple target headers.  The behaviour desired by the client can be
       
   501 determined by examining the target header specified in the Connect.
       
   502 	
       
   503 @param aChecking The desired level of target header checking.
       
   504 @publishedAll
       
   505 @released
       
   506 */
       
   507 EXPORT_C void CObexServer::SetTargetChecking(TTargetChecking aChecking)
       
   508 	{
       
   509 	LOG_LINE
       
   510 	LOG_FUNC
       
   511 
       
   512 	iTargetChecking = aChecking;
       
   513 	}
       
   514 
       
   515 
       
   516 /**
       
   517 Prepare next packet for the connection attempt
       
   518 ConnectionID and Who headers are Mandatory if the Target header was used in the connection from
       
   519 @param aPacket Packet to fill
       
   520 @internalComponent
       
   521 */
       
   522 TInt CObexServer::PrepareConnectPacket(CObexPacket& aPacket) 
       
   523 	{
       
   524 	FLOG(_L("CObexServer::PrepareConnectPacket\r\n"));
       
   525 	TInt retValue = KErrNone;
       
   526 	TConnectState nextState = GetConnectState();
       
   527 
       
   528 	if(!iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags))
       
   529 		{
       
   530 		FLOG(_L("PrepareConnectPacket Local data insertion FAILED\r\n"));
       
   531 		return(KErrGeneral);
       
   532 		}
       
   533 	FLOG(_L("PrepareConnectPacket Local data inserted\r\n"));
       
   534 
       
   535 	if(GetConnectState() == ESimpleConnRequest)	//no Auth requested by the Client
       
   536 		{
       
   537 		FLOG(_L("PrepareConnectPacket GetConnectState() == ESimpleConnRequest\r\n"));
       
   538 		//if the Server must challenge
       
   539 		if(iChallenge) 
       
   540 			{
       
   541 			FLOG(_L("PrepareConnectPacket Challenge Required\r\n"));
       
   542 
       
   543 			aPacket.SetOpcode(ERespUnauthorized);  
       
   544 			retValue = GenerateChallenge(aPacket);
       
   545 			if ( retValue == KErrNone ) 
       
   546 				{
       
   547 				FLOG(_L("PrepareConnectPacket Challenge generated\r\n"));
       
   548 				nextState = ESimpleConnChallIssued;
       
   549 				}
       
   550 			else
       
   551 				{
       
   552 				FLOG(_L("PrepareConnectPacket Challenge generation FAILED\r\n"));
       
   553 				nextState = EConnTransport;
       
   554 				aPacket.SetOpcode(ERespInternalError);
       
   555 				}
       
   556 			}
       
   557 		else //don't require Authentication
       
   558 			{
       
   559 			FLOG(_L("PrepareConnectPacket No Challenge Required\r\n"));
       
   560 
       
   561 			aPacket.SetOpcode(ERespSuccess); 
       
   562 			//if the Target header was used for the connection
       
   563 			//if so then reply with ConnectionID and Who headers
       
   564 			if ((retValue = AddConnectionIDHeader(aPacket)) == KErrNone)
       
   565 				{
       
   566 				FLOG(_L("PrepareConnectPacket ConnectionID Inserted\r\n"));
       
   567 				nextState = EConnObex;
       
   568 				}
       
   569 			else
       
   570 				{
       
   571 				nextState = EDropLink;
       
   572 				FLOG(_L("PrepareConnectPacket ConnectionID Insertion FAILED\r\n"));
       
   573 				}
       
   574 			}
       
   575 		} //end if(GetConnectState() == ESimpleConnRequest) 
       
   576 	else if (GetConnectState() == EChallConnRequested)
       
   577 		{
       
   578 		FLOG(_L("PrepareConnectPacket GetConnectState() == EChallConnRequested\r\n"));
       
   579 
       
   580 		//if the Server must challenge
       
   581 		if(iChallenge) 
       
   582 			{
       
   583 			FLOG(_L("PrepareConnectPacket Challenge required\r\n"));
       
   584 			aPacket.SetOpcode(ERespUnauthorized); 
       
   585 			retValue = GenerateChallenge(aPacket);
       
   586 			if ( retValue == KErrNone ) 
       
   587 				{
       
   588 				FLOG(_L("PrepareConnectPacket Challenge Generated\r\n"));
       
   589 				nextState = EChallConnChallIssued; //chall answered with another chall
       
   590 				}
       
   591 			else
       
   592 				{
       
   593 				FLOG(_L("PrepareConnectPacket Challenge Generation FAILED\r\n"));
       
   594 				nextState = EConnTransport;
       
   595 				aPacket.SetOpcode(ERespInternalError);
       
   596 				}
       
   597 			}
       
   598 		else //don't require Authentication
       
   599 			{ //the response would already have been verified in ParseConnectPacket() 
       
   600 			//get password from user, prepare a response to the challenge
       
   601 			FLOG(_L("PrepareConnectPacket Challenge Not Required\r\n"));
       
   602 			retValue = PrepareFinalChallResponse(aPacket, nextState);
       
   603 			}
       
   604 		} //end else if GetConnectState() == EChallConnRequested
       
   605 	else if (GetConnectState() == EFinalChallRxed)
       
   606 		{	//
       
   607 		retValue = PrepareFinalChallResponse(aPacket, nextState);
       
   608 		}
       
   609 	else if ( GetConnectState() == EFinalResponseReceived )
       
   610 		{ //the response had to be OK otherwise would never have gotten this far
       
   611 		aPacket.SetOpcode(ERespSuccess); 
       
   612 		//if the Target header was used for the connection
       
   613 		//if so then reply with ConnectionID and Who headers
       
   614 		if ((retValue = AddConnectionIDHeader(aPacket)) == KErrNone)
       
   615 			{
       
   616 			nextState = EConnObex;
       
   617 			FLOG(_L("PrepareConnectPacket ConnectionID header Added\r\n"));
       
   618 			}
       
   619 		else
       
   620 			{
       
   621 			nextState = EDropLink;
       
   622 			FLOG(_L("PrepareConnectPacket ConnectionID header Addition FAILED\r\n"));
       
   623 			}
       
   624 		}
       
   625 	else //it's all gone wrong
       
   626 		{
       
   627 		FLOG(_L("PrepareConnectPacket complete failure, bad state\r\n"));
       
   628 
       
   629 		//break connection, inform user
       
   630 		nextState = EConnTransport;
       
   631 		aPacket.SetOpcode(ERespInternalError);
       
   632 		retValue = KErrGeneral;
       
   633 		}
       
   634 	//if the Server is now connected inform the client
       
   635 	if ( nextState == EConnObex)
       
   636 		iOwner->ObexConnectIndication(iRemoteInfo, TPtr8(NULL, 0));
       
   637 
       
   638 	SetConnectState(nextState);
       
   639 	return(retValue);
       
   640 	}
       
   641 /**
       
   642 Prepare next packet for an  invalid connection attempt (i.e. the ParseConnectPacket failed).
       
   643 A fail response (to a connect request)  includes the version, flags, and packet size information.
       
   644 
       
   645 @param aPacket Packet to fill
       
   646 @internalComponent
       
   647 */
       
   648 TInt CObexServer::PrepareErroredConnectPacket(CObexPacket& aPacket)
       
   649 	{
       
   650 	FLOG(_L("CObexServer::PrepareErroredConnectPacket\r\n"));
       
   651 	
       
   652 	if ( !iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags))
       
   653 		{
       
   654 		FLOG(_L("PrepareConnectPacket Local data insertion FAILED\r\n"));
       
   655 		return(KErrGeneral);
       
   656 		}	
       
   657 	return KErrNone;
       
   658 	}
       
   659 
       
   660 void CObexServer::SignalReadActivity()
       
   661 	{
       
   662 	iPacketProcessSignaller->Signal(EObexReadActivityDetected);
       
   663 	}
       
   664 	
       
   665 void CObexServer::CheckTarget(TConnectState& aNextState, TInt& aRetVal)
       
   666 	{
       
   667 	FLOG(_L("Local Who:\r\n"));
       
   668 	LOGHEXDESC(iLocalInfo.iWho);
       
   669 	FLOG(_L("Target:\r\n"));
       
   670 	LOGHEXDESC(iRemoteInfo.iTargetHeader);
       
   671 	
       
   672 	// Workaround for bug with PocketPC 2002---if target header is sixteen bytes of zeros, connect anyway.
       
   673 	_LIT8(KZeroTarget, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
       
   674 
       
   675 	// Allow connection iff:
       
   676 	//    PocketPC attempting to connect to inbox (Sixteen bytes of zeros), when no LocalWho
       
   677 	// or Target header matches LocalWho (includes Inbox connections)
       
   678 	
       
   679 	if (!(	// Negate as block below discards connection
       
   680 		    ((iLocalInfo.iWho == KNullDesC8) && (iRemoteInfo.iTargetHeader == KZeroTarget))
       
   681 		 || ( iLocalInfo.iWho == iRemoteInfo.iTargetHeader)
       
   682 	   ))
       
   683 		{
       
   684 		FLOG(_L("ParseConnectPacket ETarget header doesn't match local iWho, dropping link\r\n"));
       
   685 		aNextState = EConnTransport;
       
   686 		aRetVal = ERespNotFound;
       
   687 		}
       
   688 	}
       
   689 
       
   690 
       
   691 //if the Target header is sent then it must match the local iWho field
       
   692 TInt CObexServer::ParseConnectPacket(CObexPacket& aPacket)
       
   693 	{
       
   694 	TConnectState nextState = GetConnectState(); //must change otherwise it's all wrong
       
   695 	TBool challReceivedOK = EFalse; //authentication challenge received from client 
       
   696 									//after server has issued its own authentication challenge.
       
   697 	TBool respReceivedOK = EFalse;  //authentication received from client 
       
   698 									//after server has issued its own authentication challenge.
       
   699 	FLOG(_L("CObexServer::ParseConnectPacket\r\n"));
       
   700 
       
   701 	if(!iTransportController->ExtractRemoteConnectInfo(aPacket, iRemoteInfo.iVersion, iRemoteInfo.iFlags))
       
   702 		{
       
   703 		FLOG(_L("ParseConnectPacket remote connect info extraction FAILED\r\n"));
       
   704 		return KErrGeneral;
       
   705 		}
       
   706 	FLOG(_L("ParseConnectPacket remote connect info extracted\r\n"));
       
   707 
       
   708 	TObexInternalHeader hdr;
       
   709   	iTargetReceived = EFalse; //if target received then must reply with ConnectionID
       
   710 
       
   711 	//if the present state is EConnTransport then no headers are actually
       
   712 	//required, a simple connect is sufficient
       
   713 	if(GetConnectState() == EConnTransport)
       
   714 		{
       
   715 		nextState = ESimpleConnRequest;
       
   716 		}
       
   717 
       
   718 	TInt retVal = KErrNone;
       
   719 	TBool authAttempted = EFalse;
       
   720 	
       
   721 	while (aPacket.ExtractData(hdr) && (nextState != EDropLink) && (nextState != EConnTransport))
       
   722 		{
       
   723 		switch(hdr.HI())
       
   724 			{
       
   725 			case TObexInternalHeader::ETarget:
       
   726 				{
       
   727 				FLOG(_L("ParseConnectPacket extracting ETarget header\r\n"));
       
   728 				iTargetReceived = ETrue;
       
   729 				//copy the target header into iRemoteInfo for the user
       
   730 				iRemoteInfo.iTargetHeader.Copy(hdr.HVByteSeq(), hdr.HVSize() > iRemoteInfo.iTargetHeader.MaxSize() ? iRemoteInfo.iTargetHeader.MaxSize() : hdr.HVSize());
       
   731 
       
   732 				if (iTargetChecking == EIfPresent)
       
   733 					{
       
   734 					FLOG(_L("EIfPresent target header checking..."));
       
   735 					CheckTarget(nextState, retVal);
       
   736 					}
       
   737 				}
       
   738 				break;
       
   739 			case TObexInternalHeader::EAuthChallenge:
       
   740 				{
       
   741 				FLOG(_L("ParseConnectPacket EAuthChallenge Header received processing\r\n"));
       
   742 				authAttempted = ETrue;
       
   743 				TRAPD(err, ProcessChallengeL(hdr));
       
   744 				if (!err)
       
   745 					{
       
   746 					FLOG(_L("ParseConnectPacket Processing Chall SUCCESS\r\n"));
       
   747 					if (GetConnectState() == EConnTransport)
       
   748 						{
       
   749 						nextState = EChallConnRequested;
       
   750 						}
       
   751 					else if ((GetConnectState() == ESimpleConnChallIssued) || (GetConnectState() == EChallConnChallIssued))
       
   752 						{
       
   753 						challReceivedOK = ETrue; //the response must be verified first
       
   754 						nextState = EFinalChallRxed;
       
   755 						}
       
   756 					else
       
   757 						{
       
   758 						nextState = EConnTransport;
       
   759 						retVal = ERespInternalError;
       
   760 						}
       
   761 					}
       
   762 				else
       
   763 					{
       
   764 					FLOG(_L("ParseConnectPacket Processing Chall FAILED\r\n"));
       
   765 
       
   766 					nextState = EConnTransport;
       
   767 					retVal = ERespInternalError;
       
   768 					}
       
   769 				}
       
   770 				break;
       
   771 			case TObexInternalHeader::EAuthResponse:
       
   772 				{
       
   773 				if (iChallenge)
       
   774 					//else there is no challenge password to check against!
       
   775 					{
       
   776 					FLOG(_L("ParseConnectPacket EAuthResponse Header received processing\r\n"));
       
   777 					authAttempted = ETrue;
       
   778 					TRAPD(err, ProcessChallResponseL(hdr));
       
   779 					if (err == KErrNone)
       
   780 						{
       
   781 						FLOG(_L("ParseConnectPacket Processing Chall Response SUCCESS\r\n"));
       
   782 						if (GetConnectState() == ESimpleConnChallIssued)
       
   783 							{
       
   784 							respReceivedOK =ETrue;
       
   785 							if (challReceivedOK) //was a new challenge issued by the Client?
       
   786 								{
       
   787 								nextState = EFinalChallRxed; //must respond to chall
       
   788 								}
       
   789 							else
       
   790 								{
       
   791 								nextState = EFinalResponseReceived; //everything is OK send Success
       
   792 								}
       
   793 							}
       
   794 						else if (GetConnectState() == EChallConnChallIssued)
       
   795 							{
       
   796 							respReceivedOK =ETrue;
       
   797 							if (challReceivedOK) //was a new challenge issued by the Client?
       
   798 								{
       
   799 								nextState = EFinalChallRxed; //must respond to chall
       
   800 								}
       
   801 							else
       
   802 								{
       
   803 								//If we do not later in the packet see a challenge,
       
   804 								//(in which case this 'nextState' value will be overwritten),
       
   805 								//the client will have come back WITHOUT re-issuing 
       
   806 								//either his original challenge or a new one.
       
   807 								//Treat as if client had never issued a challenge. 
       
   808 								//This sequence has been observed in FOMA phones.
       
   809 								nextState = EFinalResponseReceived; 
       
   810 								}
       
   811 							}
       
   812 						else
       
   813 							{
       
   814 							nextState = EConnTransport;
       
   815 							retVal = ERespInternalError;
       
   816 							}
       
   817 						}
       
   818 					else if (err == KErrAccessDenied)
       
   819 						{
       
   820 						nextState = EConnTransport;
       
   821 						retVal = ERespUnauthorized;
       
   822 						FLOG(_L("ParseConnectPacket Processing Chall Response FAILED with Access Denied\r\n"));
       
   823 						}
       
   824 					else
       
   825 						{
       
   826 						nextState = EConnTransport;
       
   827 						retVal = ERespInternalError;
       
   828 						FLOG(_L("ParseConnectPacket Processing Chall Response FAILED\r\n"));
       
   829 						}
       
   830 					}
       
   831 				else
       
   832 					{
       
   833 					// if no challenge was issued, then receiving a challenge response means the peer is badly
       
   834 					// behaved. For this case we simply ignore the header, anything else would be too drastic.
       
   835 					FLOG(_L("ParseConnectPacket Chall Response received when no Chall issued\r\n"));
       
   836 					}
       
   837 				}
       
   838 				break;
       
   839 		default:
       
   840 			break;
       
   841 			}
       
   842 		}
       
   843 		
       
   844 	if (((GetConnectState() == ESimpleConnChallIssued) || (GetConnectState() == EChallConnChallIssued)) && !respReceivedOK)
       
   845 		// Client's connect packet should have contained an authentication response.
       
   846 		// Treat as if we had rejected an authentication response.
       
   847 		{
       
   848 		nextState = EConnTransport;
       
   849 		retVal = ERespUnauthorized;
       
   850 		}
       
   851 		
       
   852 	if (iTargetChecking == EAlways)
       
   853 		{
       
   854 		FLOG(_L("EAlways target header checking..."));
       
   855 		CheckTarget(nextState, retVal);
       
   856 		}
       
   857 
       
   858 	if (!authAttempted && (GetConnectState() == ESimpleConnChallIssued))
       
   859 		nextState = ESimpleConnRequest;
       
   860 
       
   861 	SetConnectState(nextState);
       
   862 	
       
   863 	return retVal;
       
   864 	}
       
   865 
       
   866 
       
   867 /** 
       
   868 Check, if required, the object connection ID.
       
   869 
       
   870 @return ETrue if it was not necessary to receive the ConnectionID or
       
   871 		if it was necessary and was correctly received. Otherwise 
       
   872 		EFalse.
       
   873 @internalComponent
       
   874 */
       
   875 TBool CObexServer::CheckObjectForConnectionId(CObexBaseObject& aObject)
       
   876 	{
       
   877 	TBool retValue = ETrue;
       
   878 
       
   879 	if( iTargetReceived )
       
   880 		{
       
   881 		retValue = EFalse;
       
   882 		if (aObject.iValidHeaders & KObexHdrConnectionID )
       
   883 			{
       
   884 			TUint32 connID = aObject.ConnectionID();
       
   885 			if (iConnectionIdSet && (iConnectionID == connID))
       
   886 				{
       
   887 				retValue = ETrue;
       
   888 				}
       
   889 			}
       
   890 		}
       
   891 	return (retValue);
       
   892 	}
       
   893 
       
   894 /**
       
   895 Check, if required, that the packet connection ID matches that of the Server's current connection
       
   896 @return ETrue if the connection ID matches or if Target was not used in the original connection
       
   897 @return EFalse if Target was not used in the original connection and the connection ID was not found
       
   898 @internalComponent
       
   899 */
       
   900 TBool CObexServer::CheckPacketForConnectionId(CObexPacket& aPacket)
       
   901 	{
       
   902 	// Connection ID check is compulsory if Target was used in the original connection
       
   903 	if (!iTargetReceived)
       
   904 		{
       
   905 		return ETrue;
       
   906 		}
       
   907 
       
   908 	// Search for ConnectionID
       
   909 	// ConnectionID should be the first header, but we check all of them just in case
       
   910 	TObexInternalHeader header;
       
   911 	while (aPacket.ExtractData(header))
       
   912 		{
       
   913 		if (header.HI() == TObexInternalHeader::EConnectionID)
       
   914 			{
       
   915 			TUint32 newConnectionID = (header.HVByteSeq()[0] << 24) + (header.HVByteSeq()[1] << 16)
       
   916 						+ (header.HVByteSeq()[2] << 8)  + (header.HVByteSeq()[3]);
       
   917 
       
   918 			if (ConnectionID() == newConnectionID)
       
   919 				{
       
   920 				return ETrue;
       
   921 				}
       
   922 			}
       
   923 		}
       
   924 
       
   925 	// Target was used in original connection and could not find Connection ID
       
   926 	return EFalse;
       
   927 	}
       
   928 
       
   929 void CObexServer::OnPacketReceive(CObexPacket& aPacket)
       
   930 	{
       
   931 	FLOG(_L("CObexServer::OnPacketReceive\r\n"));
       
   932 	MObexServerRequestPacketNotify* packetNotify = NULL;
       
   933 	if (iServerRequestPacketEngine)
       
   934 		{
       
   935 		packetNotify = iServerRequestPacketEngine->RequestPacketNotify();		
       
   936 		}
       
   937 	// If a packet notify has been registered then we should tell it 
       
   938 	// about each request packet we receive.
       
   939 	if (packetNotify)
       
   940 		{
       
   941 		TObexResponse response;
       
   942 		TBool normalOperation = ETrue;
       
   943 		
       
   944 		// Rebuild full OBEX opcode to pass to observer
       
   945 		TObexOpcode opcode = aPacket.Opcode() | (aPacket.IsFinal() ? KObexPacketFinalBit : 0);
       
   946 		
       
   947 		switch (aPacket.Opcode())
       
   948 			{
       
   949 		case CObex::EOpConnect:
       
   950 				{
       
   951 				TObexConnectInfo connectInfo;
       
   952 				if (!iStateMachine->Transport().ExtractRemoteConnectInfo(aPacket, connectInfo.iVersion, connectInfo.iFlags))
       
   953 					{
       
   954 					// If the packet cannot be parsed correctly at this stage it is very malformed
       
   955 					// and so we should abort processing it for the server app, and defer handling
       
   956 					// the error to the state machine.
       
   957 					break;
       
   958 					}
       
   959 				
       
   960 				TObexInternalHeader header;
       
   961 				// Call ExtractData() until it returns 0 bytes read - then we know the extract
       
   962 				// point will have been reset so the CObexPacket can be parsed again in the 
       
   963 				// future.  For this reason do not attempt to optimise this loop.
       
   964 				while (aPacket.ExtractData(header))
       
   965 					{
       
   966 					switch (header.HI())
       
   967 						{
       
   968 					case TObexInternalHeader::ETarget:
       
   969 						 // Only take the first Target header found
       
   970 						 if (connectInfo.iTargetHeader.Length() == 0)
       
   971 							{
       
   972 							TInt size = header.HVSize() > connectInfo.iTargetHeader.MaxSize() ? connectInfo.iTargetHeader.MaxSize() : header.HVSize();
       
   973 							connectInfo.iTargetHeader.Copy(header.HVByteSeq(), size);
       
   974 							}
       
   975 						break;
       
   976 					case TObexInternalHeader::EWho:
       
   977 						 // Return the first Who header in packet
       
   978 						 if (connectInfo.iWho.Length() == 0)
       
   979 							{
       
   980 							TInt size = header.HVSize() > connectInfo.iWho.MaxSize() ? connectInfo.iWho.MaxSize() : header.HVSize();
       
   981 							connectInfo.iWho.Copy(header.HVByteSeq(), size);
       
   982 							}
       
   983 						break;
       
   984 					default:
       
   985 						break;
       
   986 						}
       
   987 					}
       
   988 				
       
   989 				normalOperation = packetNotify->RequestPacket(opcode, connectInfo, response);
       
   990 				}
       
   991 			break;
       
   992 		case CObex::EOpSetPath:
       
   993 				{
       
   994 				TObexSetPathData data;
       
   995 	
       
   996 				if (!aPacket.ExtractData(data))
       
   997 					{
       
   998 					// If the packet cannot be parsed correctly at this stage it is very malformed
       
   999 					// and so we should abort processing it for the server app, and defer handling
       
  1000 					// the error to the state machine.
       
  1001 					break;
       
  1002 					}
       
  1003 				CObex::TSetPathInfo info(data);
       
  1004 					
       
  1005 				TObexInternalHeader header;
       
  1006 				// Call ExtractData() until it returns 0 bytes read - then we know the extract
       
  1007 				// point will have been reset so the CObexPacket can be parsed again in the 
       
  1008 				// future.  For this reason do not attempt to optimise this loop.
       
  1009 				while(aPacket.ExtractData(header))
       
  1010 					{
       
  1011 					// Take the first name header we find.
       
  1012 					if(!info.iNamePresent && header.HI() == TObexInternalHeader::EName && header.GetHVText(info.iName) == KErrNone)
       
  1013 						{
       
  1014 						info.iNamePresent = ETrue;
       
  1015 						}
       
  1016 					}
       
  1017 	
       
  1018 				normalOperation = packetNotify->RequestPacket(opcode, info, response);
       
  1019 				}
       
  1020 			break;	
       
  1021 		case CObex::EOpDisconnect:
       
  1022 		case CObex::EOpAbortNoFBit:
       
  1023 		case CObex::EOpPut:
       
  1024 		case CObex::EOpGet:	
       
  1025 		default:
       
  1026 			normalOperation = packetNotify->RequestPacket(opcode, response);
       
  1027 			break;
       
  1028 			}
       
  1029 
       
  1030 		if (!normalOperation) // Abandon processing of request
       
  1031 			{
       
  1032 			CheckServerAppResponseCode(aPacket.Opcode(), response); // a success response code => panic
       
  1033 			iStateMachine->OverrideRequestHandling(response);
       
  1034 			return;
       
  1035 			}
       
  1036 		}
       
  1037 
       
  1038 	// Normal processing
       
  1039 	iStateMachine->OnPacketReceive(aPacket);
       
  1040 	}
       
  1041 
       
  1042 /**
       
  1043 This function is to ensure that a response a server application provides the Obex Server
       
  1044 to respond to the Obex Client with when it has overriden the default handling of a request
       
  1045 packet does not represent a success.
       
  1046 
       
  1047 The rationale for this is to attempt to keep the Obex peers synchronised.  As the packet has
       
  1048 been dropped, the client should not be lead to believe it has been received successfully.
       
  1049 
       
  1050 Therefore, this function asserts that the application does not send a success response for 
       
  1051 the request packet received.
       
  1052 */	
       
  1053 void CObexServer::CheckServerAppResponseCode(TObexOpcode aOpcode, TObexResponse aResponse)
       
  1054 	{
       
  1055 	TBool valid = ETrue;
       
  1056 	switch (aOpcode)
       
  1057 		{
       
  1058 		case CObex::EOpConnect:
       
  1059 			if (aResponse == ERespSuccess)
       
  1060 				{
       
  1061 				valid = EFalse;
       
  1062 				}
       
  1063 			break;
       
  1064 		case CObex::EOpPut:
       
  1065 		case CObex::EOpGet:
       
  1066 			if (aResponse == ERespSuccess || aResponse == ERespContinue)
       
  1067 				{
       
  1068 				valid = EFalse;
       
  1069 				}
       
  1070 			break;
       
  1071 		case CObex::EOpSetPath:
       
  1072 			if (aResponse == ERespSuccess)
       
  1073 				{
       
  1074 				valid = EFalse;
       
  1075 				}
       
  1076 			break;
       
  1077 		case CObex::EOpDisconnect:
       
  1078 		case CObex::EOpAbortNoFBit:
       
  1079 			// We allow any response to a abort/disconnect request,
       
  1080 			// as only success codes are allowed.
       
  1081 		default:
       
  1082 			break;
       
  1083 		}
       
  1084 	__ASSERT_ALWAYS(valid, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
       
  1085 	}
       
  1086 
       
  1087 void CObexServer::OnError(TInt aError)
       
  1088 	{
       
  1089 	FTRACE(FPrint(_L("OnError aError: %d iCurrentOperation: %d, iConnectState: %d"), aError, iCurrentOperation, iConnectState));
       
  1090 
       
  1091 	if (aError == KErrDisconnected)
       
  1092 		{
       
  1093 		// Note: It is not clear that iCurrentOperation is ever equal
       
  1094 		// to EOpDisconnect but the check has been retained just in case
       
  1095 		if ((iCurrentOperation != EOpDisconnect) && (iConnectState > EConnTransport))
       
  1096 			{
       
  1097 			 //extended error for IrObex,("peer device aborted data transmission/obex sending") 
       
  1098 			iOwner->ErrorIndication(KErrIrObexServerPutPeerAborted);
       
  1099 			}
       
  1100 		}
       
  1101 	else
       
  1102 		{
       
  1103 		iOwner->ErrorIndication(aError);
       
  1104 		}
       
  1105 	// The state machine needs to know about the error regardless of whether ErrorIndication() is called
       
  1106 	iStateMachine->Error();
       
  1107 	}
       
  1108 
       
  1109 void CObexServer::OnTransportUp()
       
  1110 	{
       
  1111 	iTargetReceived = EFalse;
       
  1112 
       
  1113 	// For servers on the device using USB, there is a possibility that
       
  1114 	// this function can be called, even though the server is stopped,
       
  1115 	// as OBEX does not control the transport, the USB host does.
       
  1116 	// Hence the need to check if there is an active iOwner.
       
  1117 	if (iOwner)
       
  1118 		{
       
  1119 		iOwner->TransportUpIndication();
       
  1120 		}
       
  1121 	iStateMachine->TransportUp(); // state machine needs to know about the event regardless of Server state
       
  1122 	}
       
  1123 
       
  1124 /**
       
  1125 Tell the MObexServerNotifyAsync observer the transport is down and listen
       
  1126 for another connection.
       
  1127 */
       
  1128 void CObexServer::OnTransportDown()
       
  1129 	{// Cancel Anything waiting. Restart the accepter	
       
  1130 
       
  1131 	// For servers on the device using USB, there is a possibility that
       
  1132 	// this function can be called, even though the server is stopped,
       
  1133 	// as OBEX does not control the transport, the USB host does
       
  1134 	// Hence the need to check if there is an active iOwner.
       
  1135 	if (iOwner)
       
  1136 		{
       
  1137 		iOwner->TransportDownIndication();
       
  1138 		}
       
  1139 	iStateMachine->TransportDown(); // state machine needs to know about the event regardless of Server state
       
  1140 	TInt err = AcceptConnection();
       
  1141 	if(err != KErrNone)
       
  1142 		Error(err);
       
  1143 	}
       
  1144 
       
  1145 /** Signals an event has ocurred.
       
  1146 
       
  1147 @released
       
  1148 @internalComponent
       
  1149 @param aEvent The event that has occurred. (TObexPacketProcessEvent)
       
  1150 */
       
  1151 void CObexServer::SignalPacketProcessEvent(TInt aEvent)
       
  1152 	{
       
  1153 	LOG_FUNC
       
  1154 
       
  1155 	// This is how we signal the completed send of an ACK to a disconnect 
       
  1156 	// command. Tell the state machine so it can finish the disconnection 
       
  1157 	// sequence.
       
  1158 	if(aEvent & EObexWriteCompletedFinal)
       
  1159 		{
       
  1160 		iStateMachine->WriteComplete();
       
  1161 		}
       
  1162 
       
  1163 	// Server will have definitely finished with the read packet so queue the next read
       
  1164 	if(aEvent & EObexWriteCompleted)
       
  1165 		{
       
  1166 		iTransportController->Receive();
       
  1167 		}
       
  1168 		
       
  1169 	if(aEvent & EObexReadActivityDetected)
       
  1170 		{
       
  1171 		iStateMachine->ReadActivityDetected();
       
  1172 		}
       
  1173 	}
       
  1174 	
       
  1175 // CObexServer
       
  1176 /** Tests if the server is started, and is available to accept connections.
       
  1177 	
       
  1178 @return ETrue if the server is started, EFalse otherwise
       
  1179 	
       
  1180 @publishedAll
       
  1181 @released
       
  1182 */
       
  1183 EXPORT_C TBool CObexServer::IsStarted() 
       
  1184 	{
       
  1185 	LOG_LINE
       
  1186 	LOG_FUNC
       
  1187 
       
  1188 	return iEnabled;
       
  1189 	}
       
  1190 
       
  1191 /**
       
  1192 Returns the operation currently being performed by the remote client, or 
       
  1193 EOpIdle if between operations. Note that there is no implication of whether 
       
  1194 the server is currently connected; EOpIdle will be returned regardless of 
       
  1195 connection state, if no operation is currently being performed. Use 
       
  1196 CObex::IsConnected () to find connection staus.
       
  1197 
       
  1198 @return Operation currently being performed by the remote client
       
  1199 
       
  1200 @publishedAll
       
  1201 @released
       
  1202 */
       
  1203 EXPORT_C CObex::TOperation CObexServer::CurrentOperation() const 
       
  1204 	{
       
  1205 	LOG_LINE
       
  1206 	LOG_FUNC
       
  1207 
       
  1208 	return iCurrentOperation;
       
  1209 	}
       
  1210 
       
  1211 /**
       
  1212 Setter function to allow other classes in the DLL to set the Server's current operation.
       
  1213 Used by the Server state machine.
       
  1214 @see CObexServerStateMachine
       
  1215 @param aOperation The operation currently being performed by the remote client
       
  1216 @internalComponent
       
  1217 */
       
  1218 void CObexServer::SetCurrentOperation(const CObex::TOperation aOperation)
       
  1219 	{
       
  1220 	iCurrentOperation = aOperation;
       
  1221 	}
       
  1222 
       
  1223 /**
       
  1224 Specify the set of headers to return to remote Obex client in final
       
  1225 Put response packet. The total length of the headers when encoded 
       
  1226 should not exceed the maximum Obex packet payload size.
       
  1227 
       
  1228 This function may be called at any point during a Put operation.
       
  1229 Repeated calls to this replace rather than add to the header set
       
  1230 for inclusion in the final Put response packet.
       
  1231 
       
  1232 It may be called with a NULL pointer, which means that no headers
       
  1233 will be sent with the Put Final Response.
       
  1234 
       
  1235 Even if this function returns with an error (even KErrNotReady) a
       
  1236 best-effort attempt will be made to send as many headers as will fit
       
  1237 in the final Put response packet.
       
  1238 
       
  1239 @param aHeaderSet A set of headers to be encoded in the final Put
       
  1240 response packet. Ownership of the header set always passes to 
       
  1241 CObexServer.
       
  1242 
       
  1243 @return KErrNone if the operation completes successfully.
       
  1244 		KErrNotReady if the current operation is not a Put.
       
  1245 		KErrArgument if the length of the headers when encoded
       
  1246 		exceeds the maximum Obex packet payload size.
       
  1247 		
       
  1248 @publishedAll
       
  1249 @released
       
  1250 */
       
  1251 EXPORT_C TInt CObexServer::SetPutFinalResponseHeaders(CObexHeaderSet* aHeaderSet)
       
  1252 	{
       
  1253 	LOG_LINE
       
  1254 	LOG_FUNC
       
  1255 
       
  1256 	//	First, let the state machine take ownership of the headerset
       
  1257 	iStateMachine->SetPutFinalResponseHeaderSet(aHeaderSet);
       
  1258 
       
  1259 	TInt err=KErrNone;
       
  1260 
       
  1261 	//	Easy check first - are we currently engaged in a Put?
       
  1262 	if(iCurrentOperation != EOpPut)
       
  1263 		{
       
  1264 		err=KErrNotReady;
       
  1265 		}
       
  1266 
       
  1267 	if(!err && aHeaderSet)
       
  1268 		{
       
  1269 		//	Next, the not so easy check. Will all the headers, when encoded,
       
  1270 		//	fit inside a send packet? 
       
  1271 		//	First, how much space do we have to play with?
       
  1272 		TInt available = iTransportController->SendPacket().DataLimit() - KObexPacketHeaderSize;
       
  1273 		
       
  1274 		//	Next, what is the combined encoded size of all the headers?
       
  1275 		TInt required = 0;
       
  1276 		aHeaderSet->First();
       
  1277 		while(aHeaderSet->This(iHeader) == KErrNone)
       
  1278 			{
       
  1279 			required+=iHeader->EncodedSize();
       
  1280 			(void)aHeaderSet->Next();
       
  1281 			}
       
  1282 
       
  1283 		if(required>available)
       
  1284 			{
       
  1285 			err=KErrArgument;
       
  1286 			}
       
  1287 		}
       
  1288 		
       
  1289 	return err;
       
  1290 	}
       
  1291 
       
  1292 
       
  1293 /**
       
  1294 Complete an asynchronous callback, supplying a CObexBaseObject derived object.
       
  1295 Passing in NULL results in an Obex level error being sent to the client -- the
       
  1296 semantics are that either a PUT request has been rejected or a GET request has
       
  1297 not found a suitable object to return.
       
  1298 
       
  1299 @panic Obex ENoNotificationToComplete Raised if the server does not have a request
       
  1300 outstanding.
       
  1301 @param aObject The object passed back from application
       
  1302 @return result of state changes
       
  1303 @publishedAll
       
  1304 @released
       
  1305 */
       
  1306 EXPORT_C TInt CObexServer::RequestIndicationCallback(CObexBaseObject* aObject)
       
  1307 	{
       
  1308 	LOG_LINE
       
  1309 	LOG_FUNC
       
  1310 	return iStateMachine->RequestNotificationCompleted(aObject);
       
  1311 	}
       
  1312 
       
  1313 /**
       
  1314 Complete an asynchronous callback, supplying a obex response code. Applications 
       
  1315 should use this function when rejecting Get/Put RequestIndication in order to 
       
  1316 specify the response code.
       
  1317 
       
  1318 @panic Obex ENoNotificationToComplete Raised if the server does not have a request
       
  1319 outstanding.
       
  1320 @panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode is outside range
       
  1321 [1,255] or it is one of the successful response (e.g. ERespSuccess, ERespContinue) 
       
  1322 @param TObexResponse aResponseCode Application's response to the indication as an Obex response Code. The Final bit is ignored.
       
  1323 @return result of state changes
       
  1324 @publishedAll
       
  1325 @released
       
  1326 */
       
  1327 EXPORT_C TInt CObexServer::RequestIndicationCallbackWithError(TObexResponse aResponseCode)
       
  1328 	{
       
  1329 	LOG_LINE
       
  1330 	LOG_FUNC
       
  1331 	return iStateMachine->RequestNotificationCompleted(aResponseCode);
       
  1332 	}
       
  1333 
       
  1334 /**
       
  1335 Complete an asynchronous callback, supplying a obex response code. Applications 
       
  1336 should use this function when rejecting Get/Put RequestIndication in order to 
       
  1337 specify the error code.
       
  1338 
       
  1339 @panic Obex ENoNotificationToComplete Raised if the server does not have a request
       
  1340 outstanding.
       
  1341 @panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode non-negtive. Note: KErrNone is 
       
  1342 not acceptable because this function is only used when there is an error.
       
  1343 @param aErrorCode Application's response to the indication as an Obex response Code. 
       
  1344 @return result of state changes
       
  1345 @publishedAll
       
  1346 @released
       
  1347 */	
       
  1348 EXPORT_C TInt CObexServer::RequestIndicationCallbackWithError(TInt aErrorCode)
       
  1349 	{
       
  1350 	LOG_LINE
       
  1351 	LOG_FUNC
       
  1352 	__ASSERT_ALWAYS(aErrorCode <= 0, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
       
  1353 	return iStateMachine->RequestNotificationCompleted(IrOBEXUtil::ObexResponse(aErrorCode, ERespSuccess));
       
  1354 	}
       
  1355 	
       
  1356 	
       
  1357 /**
       
  1358 Complete an asynchronous callback, supplying a obex response code. This function is 
       
  1359 used for asychronously handling PutComplete, GetComplete and SetPath Indication. 
       
  1360 
       
  1361 @panic Obex ENoNotificationToComplete Raised if the server does not have a request
       
  1362 outstanding.
       
  1363 @panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode is outside range
       
  1364 [1,255] or it is ERespContinue (which would confuse the client)
       
  1365 @param TObexResponse aResponseCode Application's response to the indication as an Obex response Code. The Final bit is ignored.
       
  1366 @return result of state changes
       
  1367 @publishedAll
       
  1368 @released
       
  1369 */
       
  1370 EXPORT_C TInt CObexServer::RequestCompleteIndicationCallback(TObexResponse aResponseCode)
       
  1371 	{
       
  1372 	LOG_LINE
       
  1373 	LOG_FUNC
       
  1374 	return iStateMachine->RequestCompleteNotificationCompleted(aResponseCode);
       
  1375 	}
       
  1376 
       
  1377 /**
       
  1378 Complete an asynchronous callback, supplying a obex response code. This function is 
       
  1379 used for asychronously handling PutComplete, GetComplete and SetPath Indication. 
       
  1380 
       
  1381 @panic Obex ENoNotificationToComplete Raised if the server does not have a request
       
  1382 outstanding.
       
  1383 @panic Obex EInvalidResponseCodeFromServerApp raised if aErrorCode is positive, i.e. 
       
  1384 invalid Symbian error code
       
  1385 @param TObexResponse aResponseCode Application's response to the indication as a Symbian error code
       
  1386 @return result of state changes
       
  1387 @publishedAll
       
  1388 @released
       
  1389 */
       
  1390 EXPORT_C TInt CObexServer::RequestCompleteIndicationCallback(TInt aErrorCode)
       
  1391 	{
       
  1392 	LOG_LINE
       
  1393 	LOG_FUNC
       
  1394 	__ASSERT_ALWAYS(aErrorCode <= 0, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
       
  1395 	return iStateMachine->RequestCompleteNotificationCompleted(IrOBEXUtil::ObexResponse(aErrorCode, ERespSuccess));
       
  1396 	}
       
  1397 	
       
  1398 /**
       
  1399 Provides the pre-parsed contents of the most recently received request packet.
       
  1400 
       
  1401 @param aHeaderSet A reference to a pointer that will be modified to NULL if no headers
       
  1402 are contained in the request packet, or to point to a new headerset containing
       
  1403 representations of the headers within the packet. Ownership of the headerset
       
  1404 (when aHeaderSet is not NULL) is passed to the caller.
       
  1405 @return KErrNone if successful, otherwise a system wide error code.
       
  1406 
       
  1407 @publishedPartner
       
  1408 @released
       
  1409 */
       
  1410 EXPORT_C TInt CObexServer::PacketHeaders(CObexHeaderSet*& aHeaderSet)
       
  1411 	{
       
  1412 	FLOG(_L8("CObexServer::PacketHeaders"));
       
  1413 
       
  1414 	return DoPacketHeaders(aHeaderSet, NULL);	
       
  1415 	}
       
  1416 
       
  1417 
       
  1418 /**
       
  1419 Provides the selectively pre-parsed contents of the most recently received request packet.
       
  1420 
       
  1421 @param aHeaderSet A reference to a pointer that will be modified to NULL if no interesting
       
  1422 header are contained in the request packet, or to point to a new headerset containing
       
  1423 representations of the headers within the packet that are of interest. Ownership of the 
       
  1424 headerset (when aHeaderSet is not NULL) is passed to the caller.
       
  1425 @param aHeaderCheck A reference to an MObexHeaderCheck derived class that encapsulates
       
  1426 whether or not a particular header or headers should be included in the returned header
       
  1427 set (i.e. whether the headers are "interesting").
       
  1428 
       
  1429 @return KErrNone if successful, otherwise a system wide error code.
       
  1430 
       
  1431 @publishedPartner
       
  1432 @released
       
  1433 */
       
  1434 EXPORT_C TInt CObexServer::PacketHeaders(CObexHeaderSet*& aHeaderSet, MObexHeaderCheck& aHeaderCheck)
       
  1435 	{
       
  1436 	FLOG(_L8("CObexServer::PacketHeaders (selective)"));
       
  1437 
       
  1438 	return DoPacketHeaders(aHeaderSet, &aHeaderCheck);
       
  1439 	}
       
  1440 
       
  1441 /** Sets a read activity observer.
       
  1442 
       
  1443 This replaces any previous observer.  The observer will receive a callback
       
  1444 when the first read arrives for a put or get request. 
       
  1445 
       
  1446 This does not transfer ownership.
       
  1447 
       
  1448 @publishedPartner
       
  1449 @released
       
  1450 @param aObserver The observer to receive packet process events.  This may
       
  1451 				 be NULL.
       
  1452 */
       
  1453 EXPORT_C void CObexServer::SetReadActivityObserver(MObexReadActivityObserver* aObserver)
       
  1454 	{
       
  1455 	iPacketProcessSignaller->SetReadActivityObserver(aObserver);
       
  1456 	}
       
  1457 /**
       
  1458 Contains the functionality for the PacketHeader interface functions in a refactored way.
       
  1459 
       
  1460 @param aHeaderSet A reference to a pointer that will be modified to NULL if no interesting
       
  1461 header are contained in the request packet, or to point to a new headerset containing
       
  1462 representations of the headers within the packet that are of interest. Ownership of the 
       
  1463 headerset (when aHeaderSet is not NULL) is passed to the caller.
       
  1464 @param aHeaderCheck A pointer to an MObexHeaderCheck derived class that encapsulates
       
  1465 whether or not a particular header or headers should be included in the returned header
       
  1466 set (i.e. whether the headers are "interesting").  If the pointer is NULL then that is taken
       
  1467 to mean that all headers should be added to the aHeaderSet.
       
  1468 
       
  1469 @return KErrNone if successful, otherwise a system wide error code.
       
  1470 */	
       
  1471 TInt CObexServer::DoPacketHeaders(CObexHeaderSet*& aHeaderSet, MObexHeaderCheck* aHeaderCheck)
       
  1472 	{
       
  1473 	FLOG(_L8("CObexServer::DoPacketHeaders"));
       
  1474 	
       
  1475 	TRAPD(err, aHeaderSet = CObexHeaderSet::NewL());
       
  1476 	if (err != KErrNone)
       
  1477 		{
       
  1478 		aHeaderSet = NULL;
       
  1479 		return err;
       
  1480 		}
       
  1481 	
       
  1482 	CObexPacket& packet = iTransportController->ReceivePacket();
       
  1483 	
       
  1484 	// for "non-standard" size requests ensure we correctly start
       
  1485 	// extracting headers where they start.
       
  1486 	switch (packet.Opcode())
       
  1487 		{
       
  1488 	case CObex::EOpConnect:
       
  1489 			{
       
  1490 			TObexConnectInfo connectInfo;
       
  1491 			if (!iStateMachine->Transport().ExtractRemoteConnectInfo(packet, connectInfo.iVersion, connectInfo.iFlags))
       
  1492 				{
       
  1493 				err = KErrUnderflow;
       
  1494 				}
       
  1495 			}
       
  1496 		break;
       
  1497 	case CObex::EOpSetPath:
       
  1498 			{
       
  1499 			TObexSetPathData data;
       
  1500 			if (!packet.ExtractData(data))
       
  1501 				{
       
  1502 				err = KErrUnderflow;
       
  1503 				}
       
  1504 			}
       
  1505 		break;
       
  1506 	default:	
       
  1507 		break;	
       
  1508 		}
       
  1509 	
       
  1510 	TBool interestingHeaders = EFalse;
       
  1511 	TObexInternalHeader header;
       
  1512 	// Call ExtractData() until it returns 0 bytes read - then we know the extract
       
  1513 	// point will have been reset so the CObexPacket can be parsed again in the 
       
  1514 	// future.  For this reason do not attempt to optimise this loop.
       
  1515 	while(packet.ExtractData(header))
       
  1516 		{
       
  1517 		// if there was an error previously we want to just keep going through the
       
  1518 		// loop to reset the CObexPacket extraction point.
       
  1519 		if (err == KErrNone && (!aHeaderCheck || aHeaderCheck->Interested(header.HI())))
       
  1520 			{
       
  1521 			err = IrOBEXHeaderUtil::ParseHeader(header, *aHeaderSet);
       
  1522 			if (!interestingHeaders && err == KErrNone)
       
  1523 				{
       
  1524 				interestingHeaders = ETrue;
       
  1525 				}
       
  1526 			}
       
  1527 		}
       
  1528 
       
  1529 	if (err != KErrNone || !interestingHeaders)
       
  1530 		{
       
  1531 		delete aHeaderSet;
       
  1532 		aHeaderSet = NULL;
       
  1533 		}
       
  1534 	return err;	
       
  1535 	}
       
  1536 
       
  1537 /**
       
  1538 Provides additional interfaces for CObexServer.
       
  1539 
       
  1540 @param aUid The UID of the interface that is required.
       
  1541 @return A pointer to an instance implementing the interface represented by aUid.
       
  1542 
       
  1543 @leave KErrNotSupported if the given UID does not represent an interface CObexServer can provide.
       
  1544 @leave KErrInUse if an instance of MObexServerRequestPacketNotifyRegister has already been provided
       
  1545 				 by an earlier call to ExtensionInterfaceL, and it has not been released.
       
  1546 
       
  1547 @internalTechnology
       
  1548 */
       
  1549 EXPORT_C TAny* CObexServer::ExtensionInterfaceL(TUid aUid)
       
  1550 	{
       
  1551 	// MObexServerRequestPacketNotifyRegister interface
       
  1552 	if (aUid == KObexServerRequestPacketNotifyRegisterInterface)
       
  1553 		{
       
  1554 		// We only return an instance if there are no other packet access extensions
       
  1555 		// hooked into the CObexServer instance (indicated by the existance of an engine).
       
  1556 		if (iServerRequestPacketEngine)
       
  1557 			{
       
  1558 			User::Leave(KErrInUse);
       
  1559 			}
       
  1560 		iServerRequestPacketEngine = CObexServerRequestPacketEngine::NewL(*this);
       
  1561 		return static_cast<MObexServerRequestPacketNotifyRegister*>(iServerRequestPacketEngine);
       
  1562 		}
       
  1563 	// if we don't know the interface UID then we don't support it.
       
  1564 	User::Leave(KErrNotSupported);
       
  1565 	return NULL; // to silence the compiler.
       
  1566 	}
       
  1567 
       
  1568 /** 
       
  1569 Returns a pointer to the TObexTransportInfo being used by the OBEX transport 
       
  1570 layer. THE USER MUST NOT MODIFY THE OBJECT POINTED TO.
       
  1571 This is useful primarily when using OBEX over RFCOMM and the user has 
       
  1572 specified 'KRfcommPassiveAutoBind' as the port. KRfcommPassiveAutoBind makes 
       
  1573 RFCOMM itself find a free port. The user needs to know which port is really 
       
  1574 being used by RFCOMM in order to correctly populate the SDP record. 
       
  1575 May be called meaningfully after CObexServer::Start has returned KErrNone. 
       
  1576 @return Pointer to the transport layer's transport info.
       
  1577 @publishedAll
       
  1578 @released
       
  1579 */
       
  1580 EXPORT_C const TObexTransportInfo* CObexServer::TransportInfo() const
       
  1581 	{
       
  1582 	LOG_LINE
       
  1583 	LOG_FUNC
       
  1584 
       
  1585 	__ASSERT_DEBUG(iTransportController, IrOBEXUtil::Fault(ETransportControllerNotCreated));
       
  1586 	return iTransportController->TransportInfo();
       
  1587 	}
       
  1588