obex/obexprotocol/obex/src/obexserverstatemachine.cpp
changeset 0 d0791faffa3f
equal deleted inserted replaced
-1:000000000000 0:d0791faffa3f
       
     1 // Copyright (c) 2005-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 #include <obex.h>
       
    18 #include <obex/internal/obexinternalheader.h>
       
    19 #include "obexserverstatemachine.h"
       
    20 
       
    21 #if ( defined __FLOG_ACTIVE && defined __LOG_FUNCTIONS__ )
       
    22 _LIT8(KLogComponent, "OBEX");
       
    23 #endif
       
    24 
       
    25 /**
       
    26 @file
       
    27 @internalComponent
       
    28 */
       
    29 
       
    30 /**
       
    31 Constructs the state machine and the state classes
       
    32 
       
    33 @param aOwner Server object that owns the state machine
       
    34 @param aTransport Transport Controller associated with the Server
       
    35 
       
    36 @return Contructed CObexServerStateMachine object
       
    37 */
       
    38 CObexServerStateMachine* CObexServerStateMachine::NewL(CObexServer& aOwner, CObexTransportControllerBase& aTransport)
       
    39 	{
       
    40 	CObexServerStateMachine* self = new(ELeave) CObexServerStateMachine(aOwner, aTransport);
       
    41 	CleanupStack::PushL(self);
       
    42 	self->ConstructL();
       
    43 	CleanupStack::Pop(self);
       
    44 	return self;
       
    45 	}
       
    46 
       
    47 /**
       
    48 First phase constructor
       
    49 
       
    50 @param aOwner Server object that owns the state machine
       
    51 @param aTransport Transport Controller associated with the Server
       
    52 */
       
    53 CObexServerStateMachine::CObexServerStateMachine(CObexServer& aOwner, CObexTransportControllerBase& aTransport)
       
    54 	: iCurrentState(&iStates[EDisconnected]), iTransport(aTransport), iOwner(aOwner), iServerStarted(EFalse)
       
    55 	{
       
    56 	// Use placement new here to create the state objects and put them into a pre-defined array
       
    57 	// This is done as the number of states is known at compile time and this avoids heap fragmentation
       
    58 	new(&iStates[EDisconnected]) TObexServerStateDisconnected();
       
    59 	new(&iStates[ETransportConnected]) TObexServerStateTransportConnected();
       
    60 	new(&iStates[EObexConnecting]) TObexServerStateObexConnecting();
       
    61 	new(&iStates[EWaitForUserPassword]) TObexServerStateWaitForUserPassword();
       
    62 	new(&iStates[EReady]) TObexServerStateReady();
       
    63 	new(&iStates[EPutOpWaitForUser]) TObexServerStatePutOpWaitForUser();
       
    64 	new(&iStates[EPutOpReceiveObject]) TObexServerStatePutOpReceiveObject();
       
    65 	new(&iStates[EGetOpReceiveSpecification]) TObexServerStateGetOpReceiveSpecification();
       
    66 	new(&iStates[EGetOpWaitForUser]) TObexServerStateGetOpWaitForUser();
       
    67 	new(&iStates[EGetOpSendObject]) TObexServerStateGetOpSendObject();
       
    68 	new(&iStates[ESetPathOp]) TObexServerStateSetPathOp();
       
    69 	new(&iStates[EPutOpFinal]) TObexServerStatePutOpFinal();
       
    70 	new(&iStates[EGetOpFinal]) TObexServerStateGetOpFinal();
       
    71 	new(&iStates[EDisconnecting]) TObexServerStateDisconnecting();
       
    72 	}
       
    73 
       
    74 /**
       
    75 Second phase constructor
       
    76 */
       
    77 void CObexServerStateMachine::ConstructL()
       
    78 	{
       
    79 	iSpecObject = CObexNullObject::NewL();
       
    80 	iHeader = CObexHeader::NewL();
       
    81 	iCallBack = new(ELeave) CAsyncCallBack(CActive::EPriorityStandard);
       
    82 	}
       
    83 
       
    84 /**
       
    85 Destructor
       
    86 */
       
    87 CObexServerStateMachine::~CObexServerStateMachine()
       
    88 	{
       
    89 	// No need to delete state array
       
    90 	delete iHeader;
       
    91 	delete iSpecObject;
       
    92 	delete iPutFinalResponseHeaderSet;
       
    93 	delete iCallBack;
       
    94 	}
       
    95 
       
    96 /**
       
    97 Move machine to a new state
       
    98 Note that this function is synchronous, so any code after calling this function
       
    99 will be executed with the machine in a different state.
       
   100 Usually the action after changing state should be to return from the current function.
       
   101 
       
   102 @param aState Index of new state
       
   103 @return Result of state change
       
   104 */
       
   105 void CObexServerStateMachine::ChangeState(TObexServerOperationStateEnum aState)
       
   106 	{
       
   107 	STATE_LOG_2(_L8("Changing from state %S to %S"), &iCurrentState->iName, &iStates[aState].iName);
       
   108 	iCurrentState = &(iStates[aState]);
       
   109 	iCurrentStateEnum = aState;
       
   110 	iCurrentState->Entry(*this);
       
   111 	}
       
   112 
       
   113 void CObexServerStateMachine::ControlledTransportDown()
       
   114 	{
       
   115 	LOG_FUNC
       
   116 
       
   117 	iOwner.ControlledTransportDown();
       
   118 	}
       
   119 
       
   120 /**
       
   121 Process a received packet according to the packet's op-code and the current state
       
   122 
       
   123 @param aPacket Packet to process
       
   124 @return Result of any state changes
       
   125 */
       
   126 void CObexServerStateMachine::OnPacketReceive(CObexPacket& aPacket)
       
   127 	{
       
   128 	if (!iServerStarted)
       
   129 		{
       
   130 		__ASSERT_DEBUG(iServerStarted, IrOBEXUtil::Fault(EPacketReceivedWhenServerNotStarted));
       
   131 		return;
       
   132 		}
       
   133 
       
   134 	iLastReceivedPacket = &aPacket;
       
   135 
       
   136 	if(Transport().IsWriteActive())
       
   137  		{
       
   138  		FLOG(_L("OnPacketReceive received request whilst writing... dropping connection\r\n"));
       
   139 		Notification().ObexDisconnectIndication(KNullDesC8);
       
   140 		// change state before issuing the transport down, as it may cause notifications
       
   141 		ChangeState(ETransportConnected);
       
   142 		ControlledTransportDown();
       
   143 		return;
       
   144  		}
       
   145 
       
   146 	// Initialise the send packet to ensure that we do not
       
   147 	// accidentally send the same packet as last time!
       
   148 	iTransport.SendPacket().Init(0);
       
   149 
       
   150 	switch (aPacket.Opcode())
       
   151 		{
       
   152 	case CObex::EOpConnect:
       
   153 		STATE_LOG(_L8("Calling connect"));
       
   154 		iCurrentState->Connect(*this, aPacket);
       
   155 		break;
       
   156 	case CObex::EOpDisconnect:
       
   157 		STATE_LOG(_L8("Calling disconnect"));
       
   158 		iCurrentState->Disconnect(*this, aPacket);
       
   159 		break;
       
   160 	case CObex::EOpPut:
       
   161 		STATE_LOG(_L8("Calling put"));
       
   162 		iCurrentState->Put(*this, aPacket);
       
   163 		break;
       
   164 	case CObex::EOpGet:
       
   165 		STATE_LOG(_L8("Calling get"));
       
   166 		iCurrentState->Get(*this, aPacket);
       
   167 		break;
       
   168 	case CObex::EOpSetPath:
       
   169 		STATE_LOG(_L8("Calling SetPath"));
       
   170 		iCurrentState->SetPath(*this, aPacket);
       
   171 		break;
       
   172 	case CObex::EOpAbortNoFBit:
       
   173 		// Abort does not check target headers (hence no need to send the packet to the event)
       
   174 		STATE_LOG(_L8("Calling abort"));
       
   175 		iCurrentState->Abort(*this);
       
   176 		break;
       
   177 
       
   178 	default:
       
   179 		// Unknown packet type
       
   180 		STATE_LOG(_L8("Unknown packet type"));
       
   181 		iTransport.Send(ERespNotImplemented);
       
   182 		break;
       
   183 		}
       
   184 	}
       
   185 
       
   186 /**
       
   187 Indicates a transport-level connection has been made to the Server
       
   188 */
       
   189 void CObexServerStateMachine::TransportUp()
       
   190 	{
       
   191 	// This event could happen while the Server is stopped (as the transport state
       
   192 	// can be independent of whether the Server has requested a read)
       
   193 	iCurrentState->TransportUp(*this);
       
   194 	}
       
   195 
       
   196 /**
       
   197 Indicates the transport-level connection to the Server has disappeared
       
   198 */
       
   199 void CObexServerStateMachine::TransportDown()
       
   200 	{
       
   201 	// This event could happen while the Server is stopped (as the transport state
       
   202 	// can be independent of whether the Server has requested a read)
       
   203 	iCurrentState->Reset(*this);
       
   204 	}
       
   205 
       
   206 /**
       
   207 Indicates a Protocol Error has occurred
       
   208 */
       
   209 void CObexServerStateMachine::Error()
       
   210 	{
       
   211 	// This event could happen while the Server is stopped (as the transport state
       
   212 	// can be independent of whether the Server has requested a read)
       
   213 	iCurrentState->Reset(*this);
       
   214 	}
       
   215 
       
   216 /**
       
   217 Process an OBEX object received as part of an asynchronous Put/Get indication
       
   218 This object pointer can be NULL to indicate an error condition
       
   219 @see MObexServerNotifyAsync::PutRequestInidication
       
   220 @see MObexServerNotifyAsync::GetRequestInidication
       
   221 @see CObexServer::RequestIndicationCallback
       
   222 
       
   223 @param aObject OBEX object to use (NULL to indication an error condition)
       
   224 @return Result of any state changes
       
   225 */
       
   226 TInt CObexServerStateMachine::RequestNotificationCompleted(CObexBaseObject* aObject)
       
   227 	{
       
   228 	__ASSERT_ALWAYS(iCurrentStateEnum == EPutOpWaitForUser ||
       
   229 					iCurrentStateEnum == EGetOpWaitForUser, IrOBEXUtil::Panic(EInvalidResponseCallback));
       
   230 	if (!iServerStarted)
       
   231 		{
       
   232 		return KErrIrObexServerStopped;
       
   233 		}
       
   234 
       
   235 	iCurrentState->RequestNotificationCompleted(*this, aObject);
       
   236 	return KErrNone;
       
   237 	}
       
   238 
       
   239 /**
       
   240 Process the response received as part of an asynchronous PutComplete/GetComplete/SetPath indication
       
   241 
       
   242 @param 	aAppResponse Application's response to the indication
       
   243 @return result of state changes
       
   244 */
       
   245 TInt CObexServerStateMachine::RequestNotificationCompleted(TObexResponse aAppResponse)
       
   246 	{
       
   247 	__ASSERT_ALWAYS(iCurrentStateEnum == EPutOpWaitForUser ||
       
   248 					iCurrentStateEnum == EGetOpWaitForUser, IrOBEXUtil::Panic(EInvalidResponseCallback));
       
   249 	__ASSERT_ALWAYS(iCurrentState->ValidResponse(aAppResponse), IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
       
   250 	if (!iServerStarted)
       
   251 		{
       
   252 		return KErrIrObexServerStopped;
       
   253 		}
       
   254 
       
   255 	iCurrentState->RequestNotificationCompleted(*this, aAppResponse);
       
   256 	return KErrNone;
       
   257 	}
       
   258 	
       
   259 /**
       
   260 Process the response received as part of an asynchronous PutComplete/GetComplete/SetPath indication
       
   261 
       
   262 @param 	aAppResponse Application's response to the indication
       
   263 @return result of state changes
       
   264 */
       
   265 TInt CObexServerStateMachine::RequestCompleteNotificationCompleted(TObexResponse aAppResponse)
       
   266 	{
       
   267 	__ASSERT_ALWAYS(iCurrentStateEnum == ESetPathOp || iCurrentStateEnum == EGetOpFinal ||
       
   268 					iCurrentStateEnum == EPutOpFinal, IrOBEXUtil::Panic(EInvalidResponseCallback));
       
   269 	__ASSERT_ALWAYS(iCurrentState->ValidResponse(aAppResponse), IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
       
   270 	if (!iServerStarted)
       
   271 		{
       
   272 		return KErrIrObexServerStopped;
       
   273 		}
       
   274 
       
   275 	iCurrentState->RequestCompleteNotificationCompleted(*this, aAppResponse);
       
   276 	return KErrNone;
       
   277 	}
       
   278 
       
   279 /**
       
   280 Indicates an OBEX level connection has been established
       
   281 
       
   282 @return Result of any state changes
       
   283 */
       
   284 void CObexServerStateMachine::ConnectionComplete()
       
   285 	{
       
   286 	__ASSERT_ALWAYS(iServerStarted, IrOBEXUtil::Fault(EConnectionCompleteWhenServerStopped));
       
   287 
       
   288 	iCurrentState->ConnectionComplete(*this);
       
   289 	}
       
   290 
       
   291 /**
       
   292 Indicates Server has been started
       
   293 
       
   294 @param aNotify Notification interface to use
       
   295 */
       
   296 void CObexServerStateMachine::Start(MObexServerNotifyAsync& aNotify)
       
   297 	{
       
   298 	iServerStarted = ETrue;
       
   299 	iNotification = &aNotify;	// state will panic if trying to change interface at an inappropriate point
       
   300 	iCurrentState->Start(*this);
       
   301 	}
       
   302 
       
   303 /**
       
   304 Indicates Server has been stopped
       
   305 */
       
   306 void CObexServerStateMachine::Stop()
       
   307 	{
       
   308 	iCurrentState->Reset(*this);
       
   309 	iServerStarted = EFalse;
       
   310 	}
       
   311 	
       
   312 /**
       
   313 Indication that the Obex server application has chosen to override the
       
   314 handling of the request packet that has been received.
       
   315 
       
   316 @param aResponse The response the server application has indicated that should
       
   317 				 be sent to the Obex client.  The actual sending of the response
       
   318 				 is delegated to the individual states to handle as appropriate.
       
   319 @return Result of any state changes
       
   320 */
       
   321 void CObexServerStateMachine::OverrideRequestHandling(TObexResponse aResponse)
       
   322 	{
       
   323 	iCurrentState->OverrideRequestHandling(*this, aResponse);
       
   324 	}
       
   325 
       
   326 /**
       
   327 Indicates that a write of a packet has been completed successfully at the 
       
   328 transport level.
       
   329 */
       
   330 void CObexServerStateMachine::WriteComplete()
       
   331 	{
       
   332 	LOG_FUNC
       
   333 
       
   334 	iCurrentState->WriteComplete(*this);
       
   335 	}
       
   336 
       
   337 /**
       
   338 Indicates that a new obex packet is being read.
       
   339 */
       
   340 void CObexServerStateMachine::ReadActivityDetected()
       
   341 	{
       
   342 	LOG_FUNC
       
   343 
       
   344 	iCurrentState->ReadActivityDetected(*this);
       
   345 	}
       
   346 
       
   347 /**
       
   348 @return Last packet processed by the state machine
       
   349 */
       
   350 CObexPacket& CObexServerStateMachine::LastReceivedPacket() const
       
   351 	{
       
   352 	__ASSERT_DEBUG(iLastReceivedPacket, IrOBEXUtil::Fault(ENoReceivePacketAvailable));
       
   353 	return *iLastReceivedPacket;
       
   354 	}
       
   355 
       
   356 /**
       
   357 This sets pointer of the object received from the application
       
   358 and so can be NULL to indicate an error
       
   359 
       
   360 @see CObexServerStateMachine::NotificationComplete
       
   361 @return Specification Object - used to describe the OBEX object to Get
       
   362 */
       
   363 CObexBaseObject* CObexServerStateMachine::SpecObject() const
       
   364 	{
       
   365 	return iSpecObject;
       
   366 	}
       
   367 
       
   368 /**
       
   369 This returns pointer to the object received from the application
       
   370 and so can be NULL to indicate an error
       
   371 
       
   372 @see CObexServerStateMachine::NotificationComplete
       
   373 @return Transfer object to exchange with the Client
       
   374 */
       
   375 CObexBaseObject* CObexServerStateMachine::TransObject() const
       
   376 	{
       
   377 	return iTransObject;
       
   378 	}
       
   379 
       
   380 /**
       
   381 @param aTransObject New transfer object to exchange with the Client
       
   382 */
       
   383 void CObexServerStateMachine::SetTransObject(CObexBaseObject* aTransObject)
       
   384 	{
       
   385 	iTransObject = aTransObject;
       
   386 	}
       
   387 
       
   388 /**
       
   389 @return Transport Controller associated with the Server
       
   390 */
       
   391 CObexTransportControllerBase& CObexServerStateMachine::Transport() const
       
   392 	{
       
   393 	return iTransport;
       
   394 	}
       
   395 
       
   396 /**
       
   397 @return Server object associated with the State Machine
       
   398 */
       
   399 CObexServer& CObexServerStateMachine::Owner() const
       
   400 	{
       
   401 	return iOwner;
       
   402 	}
       
   403 
       
   404 /**
       
   405 @return Notification interface associated with the Server
       
   406 */
       
   407 MObexServerNotifyAsync& CObexServerStateMachine::Notification() const
       
   408 	{
       
   409 	__ASSERT_DEBUG(iNotification, IrOBEXUtil::Fault(ENoNotifierAvailable));
       
   410 	return *iNotification;
       
   411 	}
       
   412 
       
   413 /**
       
   414 @return Final Header set to send at the end of a Put operation
       
   415 */
       
   416 CObexHeaderSet* CObexServerStateMachine::PutFinalResponseHeaderSet()
       
   417 	{
       
   418 	return iPutFinalResponseHeaderSet;
       
   419 	}
       
   420 
       
   421 /**
       
   422 @param aHeaderSet Final Header set to send at the end of a Put operation
       
   423 */
       
   424 void CObexServerStateMachine::SetPutFinalResponseHeaderSet(CObexHeaderSet* aHeaderSet)
       
   425 	{
       
   426 	delete iPutFinalResponseHeaderSet;
       
   427 	iPutFinalResponseHeaderSet = aHeaderSet;
       
   428 	}
       
   429 
       
   430 /**
       
   431 @return Internal header object (used for sizing the final response header set)
       
   432 */
       
   433 CObexHeader* CObexServerStateMachine::GetHeader()
       
   434 	{
       
   435 	return iHeader;
       
   436 	}
       
   437 
       
   438 /**
       
   439 Activate one-shot call-back to run from the Active Scheduler
       
   440 @param aFunction Pointer to the function to call
       
   441 */
       
   442 void CObexServerStateMachine::CallBack(TInt (*aFunction)(TAny* aPtr))
       
   443 	{
       
   444 	iCallBack->Set(TCallBack(aFunction, this));
       
   445 	iCallBack->CallBack();
       
   446 	}
       
   447 
       
   448 /**
       
   449 Cancel one-shot call-back
       
   450 */
       
   451 void CObexServerStateMachine::CancelCallBack()
       
   452 	{
       
   453 	iCallBack->Cancel();
       
   454 	}
       
   455 
       
   456 /**
       
   457 @return If one-shot call-back is active
       
   458 */
       
   459 TBool CObexServerStateMachine::IsCallBackActive() const
       
   460 	{
       
   461 	return iCallBack->IsActive();
       
   462 	}
       
   463 
       
   464 TObexResponse CObexServerStateMachine::AppResponse() const
       
   465 	{
       
   466 	return iAppResponse;
       
   467 	}
       
   468 
       
   469 void CObexServerStateMachine::SetAppResponse(TObexResponse aAppResponse)
       
   470 	{
       
   471 	__ASSERT_DEBUG(aAppResponse>0 && aAppResponse<=255, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp ));
       
   472 	
       
   473 	//remove the final bit, sorry about the horrible double casting. 
       
   474 	aAppResponse = static_cast<TObexResponse>(static_cast<TInt> (aAppResponse) & 0x7F); 
       
   475 	iAppResponse = aAppResponse;
       
   476 	}
       
   477