obex/obexprotocol/obex/src/obexserver.cpp
changeset 0 d0791faffa3f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/obex/obexprotocol/obex/src/obexserver.cpp	Tue Feb 02 01:11:40 2010 +0200
@@ -0,0 +1,1588 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <charconv.h>
+#include <utf.h>
+#include <obex/internal/obexinternalheader.h>
+#include <obextransportinfo.h>
+#include <obex.h>
+#include <obex/internal/obexpacket.h>
+#include <obex/transport/obextransportcontrollerbase.h>
+#include <obex/internal/obextransportconstants.h>
+#include <obex/extensionapis/mobexserverrequestpacketnotify.h>
+#include <obex/internal/mobexserverrequestpacketnotifyregister.h>
+#include "logger.h"
+#include "obexsetpathdata.h"
+#include "OBEXUTIL.H"
+#include "authentication.h"
+#include "obexnotifyhandlerserver.h"
+#include "obexserverstatemachine.h"
+#include "obexservernotifysyncwrapper.h"
+#include "obexheaderutil.h"
+#include "obexserverrequestpacketengine.h"
+#include "obexpacketsignaller.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "OBEX");
+#endif
+
+/**
+Constructor - set initial values 
+@internalTechnology
+*/
+CObexServer::CObexServer() : CObex()
+	{
+	iCurrentOperation = EOpIdle;
+	iEnabled = EFalse;
+
+	//the connectionID is fixed at the moment
+	ResetConnectionID();
+	SetConnectionID(0xc30fa596);
+
+	iTargetChecking = EIfPresent;
+	}
+
+void CObexServer::ConstructL(TObexTransportInfo& aObexTransportInfo)
+	{
+	CObex::ConstructL(aObexTransportInfo);
+	iNotifyHandler = new(ELeave)CObexNotifyHandlerServer(*this);
+	iTransportController->SetOwner(*iNotifyHandler);
+
+	iHeader = CObexHeader::NewL();
+	iStateMachine = CObexServerStateMachine::NewL(*this, *iTransportController);
+	iSyncWrapper = CObexServerNotifySyncWrapper::NewL(*this, *iStateMachine);
+	iPacketProcessSignaller = CObexPacketSignaller::NewL();
+	}
+
+/**
+Destructor. 
+*/
+CObexServer::~CObexServer()
+	{
+	FLOG(_L("CObexServer Destructor\r\n"));
+	Stop();
+	
+	delete iPacketProcessSignaller;
+	delete iSyncWrapper;
+	delete iStateMachine;
+	delete iHeader;
+	delete iNotifyHandler;
+	delete iServerRequestPacketEngine;
+	}
+
+void CObexServer::ResetConnectionID()
+	{
+	iConnectionID = KConnIDInvalid;
+	iConnectionIdSet = EFalse;
+	}
+
+void CObexServer::SetConnectionID(TUint32 aConnectionID)
+	{
+	iConnectionID = aConnectionID;
+	iConnectionIdSet = ETrue;
+	}
+
+TUint32 CObexServer::ConnectionID()
+	{
+	return (iConnectionID);
+	}
+
+TInt CObexServer::PrepareFinalChallResponse(CObexPacket& aPacket, TConnectState& aNextState)
+	{
+
+	FLOG(_L("CObexServer::PrepareFinalChallResponse\r\n"));
+
+	aPacket.SetOpcode(ERespSuccess); 
+
+	TInt retValue = AddConnectionIDHeader(aPacket);	
+	if (retValue == KErrNone)
+		{
+		FLOG(_L("PrepareFinalChallResponse ConnectionID header Added\r\n"));
+		if (iCallBack)
+			{
+			FLOG(_L("PrepareFinalChallResponse Requesting User Password\r\n"));
+
+			//the actual asking of the password happens later in the method OnPacketReceive
+			//wait for the reply
+			aNextState = EWaitForUserInput;
+			retValue = KErrGeneral; //mustn't send yet wait for reply from user
+			}
+		else //else can't Auth challenge so drop link
+			{
+			FLOG(_L("PrepareFinalChallResponse Can't request User Password for Chall dropping link\r\n"));
+
+			retValue = KErrIrObexConnectChallRejected;
+			aNextState = EConnTransport;
+			aPacket.SetOpcode(ERespNotImplemented);
+			}
+		}
+	else
+		{
+		aNextState = EDropLink;
+		}
+	return (retValue);
+	}
+
+
+/** A call back from the the service with the password required for use with generating 
+the challenge response. 
+
+@param aPassword Password
+
+@leave KErrNotReady if this function is not called from a MObexAuthChallengeHandler::GetUserPasswordL callback.
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexServer::UserPasswordL(const TDesC& aPassword)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	//now have a password, get a nonce, and get it hashed then reply
+	if (GetConnectState() == EWaitForUserInput)
+		{
+		FLOG(_L("CObexServer::UserPasswordL\r\n"));
+		PrepareChallResponseL(aPassword);
+		FLOG(_L("UserPasswordL - PrepareChallResponse Success\r\n"));
+
+		TObexInternalHeader hdr;
+		hdr.Set(TObexInternalHeader::EAuthResponse, (const_cast<TUint8*> (iOutgoingChallResp.Ptr())), iOutgoingChallResp.Size());
+		if(iTransportController->SendPacket().InsertData(hdr))
+			{
+			FLOG(_L("UserPasswordL Inserting EAuthResponse Header\r\n"));
+
+			SetConnectState(EConnObex); //all finished
+			iTransportController->SendPacket().SetFinal();
+			iTransportController->Send();
+			//inform the client that the connection was succesfull
+			iOwner->ObexConnectIndication(iRemoteInfo, TPtr8(NULL, 0));
+			iStateMachine->ConnectionComplete();
+			}
+		else
+			{
+			User::Leave(KErrGeneral);
+			}
+		}
+	else
+		{
+		User::Leave(KErrNotReady);
+		}
+	}
+
+
+TInt CObexServer::AddConnectionIDHeader(CObexPacket& aPacket)
+	{
+	TInt retValue = KErrNone;
+	//if the Target header was used for the connection
+	//then reply with ConnectionID and Who headers
+	if(iTargetReceived)
+		{
+		//this solution can only handle one connection at a time therefore
+		//can safely use the same connection ID repeatedly
+		//when used the ConnectionID must be first
+		TObexInternalHeader hdr;
+		FLOG(_L("CObexServer::AddConnectionIDHeader Inserting EConnectionID Header\r\n"));
+ 
+ 		hdr.Set(TObexInternalHeader::EConnectionID, iConnectionID);
+		
+		if(aPacket.InsertData(hdr))
+			{ 
+			// Connection ID header inserted correctly
+			// Now set a WHO header.
+			// This logic is a bit backwards due to problems with the 'no target header checking'
+			// state.  Instead of inserting our local Who header, we copy the Target header back.
+			// This works in the checking states because we drop any connection where the local
+			// Who is not identical to the Target header received.
+			// When not checking targets, this may mean that the client gets connected to a server
+			// which knows nothing about the service, yet thinks it is talking to a strict peer.
+			// However the server wouldn't understand what was going on anyway, so we're not really
+			// in a worse state than we would be if we did something more fancy.  Ultimately the
+			// application must drop the connection---probably by deleting the Obex server or
+			// returning errors to all attempted operations.
+			
+			FLOG(_L("CObexServer::AddConnectionIDHeader Inserting EWho Header\r\n"));
+
+			hdr.Set(TObexInternalHeader::EWho, (const_cast<TUint8*> (iRemoteInfo.iTargetHeader.Ptr())), 
+																iRemoteInfo.iTargetHeader.Size());
+			if(!aPacket.InsertData(hdr))
+				{
+				retValue = KErrGeneral;
+				}
+			}
+		else
+			{
+			retValue = KErrGeneral;
+			}
+		}
+	return (retValue);
+	}
+
+/**
+Allocates and constructs a new OBEX server object.
+
+The received protocol information object, aObexProtocolInfoPtr, specifies the 
+transport protocol to use:
+For the standard transports the following are used, TObexIrProtocolInfo for 
+IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
+
+@param aObexProtocolInfoPtr Protocol information object describing the 
+transport to use
+@return New OBEX server object 
+
+@publishedAll
+@released
+*/
+EXPORT_C CObexServer* CObexServer::NewL(TObexProtocolInfo& aObexProtocolInfoPtr)
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	TObexProtocolPolicy defaultProtocolPolicy;	// no packet sizing policy specified, so use default		
+	TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, defaultProtocolPolicy);
+	CleanupStack::PushL(transportInfo);
+	CObexServer* server = CObexServer::NewL(*transportInfo);
+	CleanupStack::PopAndDestroy(transportInfo);
+	return server;
+	}
+
+/**
+Allocates and constructs a new OBEX server object with packet sizing 
+information.
+
+The received protocol information object, aObexProtocolInfoPtr, specifies the 
+transport protocol to use:
+For the standard transports the following are used, TObexIrProtocolInfo for 
+IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
+
+The aObexProtocolPolicy parameter specifies the packet sizing policy for this 
+OBEX object.
+
+@param aObexProtocolInfoPtr Protocol information object describing the 
+transport to use
+@param aObexProtocolPolicy Protocol policy object specifying the packet sizes 
+to use
+@return New OBEX server object 
+	
+@publishedAll
+@released
+*/
+EXPORT_C CObexServer* CObexServer::NewL(TObexProtocolInfo& aObexProtocolInfoPtr, 
+										TObexProtocolPolicy& aObexProtocolPolicy)
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, aObexProtocolPolicy);	
+	CleanupStack::PushL(transportInfo);
+	CObexServer* server =  CObexServer::NewL(*transportInfo);
+	CleanupStack::PopAndDestroy(transportInfo);
+	return server;
+	}
+
+/** 
+Allocates and constructs a new OBEX server object with packet sizing 
+information.
+
+The received transport information object, aObexTransportInfo, specifies the 
+transport protocol and packet sizes to use:
+For the standard transports the following are used, TObexIrProtocolInfo for 
+IrDA, TObexBluetoothProtocolInfo for Bluetooth, TObexUsbProtocolInfo for USB.
+
+@param aObexTransportInfo  Transport information object describing the 
+transport and packet sizes  to use
+@return New OBEX server object 
+
+@capability WriteDeviceData If the TObexIrV3TransportInfo is passed as the argument
+                            and the associated name is valid.
+
+@publishedAll
+@released
+*/
+EXPORT_C CObexServer* CObexServer::NewL(TObexTransportInfo& aObexTransportInfo)
+	{
+	LOG_LINE
+	LOG_STATIC_FUNC_ENTRY
+
+	CObexServer* self = new(ELeave) CObexServer();
+	CleanupStack::PushL(self);
+	self->ConstructL(aObexTransportInfo);
+	CleanupStack::Pop(self);
+	return(self);
+	}
+
+/** Starts the server, specifying a synchronous notification interface.
+
+If the server is already started, no state changes occur (i.e. any connections/operations 
+in progress are not interrupted), but the notifications will be sent to aOwner. 
+This allows "child" servers to take over ownership of existing connections. 
+
+Details of this function behaviour depend on the transport specified when 
+constructed: in general a listener socket is created, its port number registered 
+as appropriate, and an accept queued.
+
+@param aOwner Server notification interface
+@return KErrArgument if parameter is NULL, KErrAlreadyExists if server has already
+been started (but notification object will still be updated), otherwise a system wide
+error code 
+@panic OBEX EChangeInterfaceDuringWait when attempting to change the interface at an inappropriate time.
+
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::Start(MObexServerNotify* aOwner)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	if(aOwner == NULL)
+		{
+		return(KErrArgument);
+		}
+	
+	// Pass this synchronous interface to the synchronous wrapper
+	// and pass the synchronous wrapper on to the asynchronous Start()
+	iSyncWrapper->SetNotifier(aOwner);
+	return Start(iSyncWrapper);
+	}
+
+
+/** Starts the server, specifying an asynchronous notification interface.
+
+If the server is already started, no state changes occur (i.e. any connections/operations 
+in progress are not interrupted), but the notifications will be sent to aOwner. 
+This allows "child" servers to take over ownership of existing connections. 
+
+Details of this function behaviour depend on the transport specified when 
+constructed: in general a listener socket is created, its port number registered 
+as appropriate, and an accept queued.
+
+@param aOwner Server notification interface
+@return KErrArgument if parameter is NULL, KErrAlreadyExists if server has already
+been started (but notification object will still be updated), otherwise a system wide
+error code 
+@panic OBEX EChangeInterfaceDuringWait when attempting to change the interface at an inappropriate time.
+
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::Start(MObexServerNotifyAsync* aOwner)
+	{
+	if(aOwner == NULL)
+		{
+		return(KErrArgument);
+		}
+
+	iOwner = aOwner;											
+
+	iStateMachine->Start(*iOwner);
+	if(iEnabled)
+		{
+		return(KErrAlreadyExists);
+		}
+	iEnabled = ETrue;
+	return(AcceptConnection());
+	}
+	
+
+/** Disconnects any transfer in progress and disables further connections. 
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexServer::Stop()
+	{// Cancel and Disable accepts, and bring and transport down.
+	LOG_LINE
+	LOG_FUNC
+
+	if(!iEnabled)
+		{
+		return;
+		}
+	iEnabled = EFalse;
+	ControlledTransportDown();
+	
+	// just check that iTransportController is still valid here (that is what we
+	// aspect to be)
+	__ASSERT_DEBUG(iTransportController, IrOBEXUtil::Fault(ETransportControllerNotCreated));
+	
+	iTransportController->CancelAccept();
+	iStateMachine->Stop();
+	iOwner = NULL;
+	iSyncWrapper->SetNotifier(NULL);
+	}
+
+TInt CObexServer::AcceptConnection()
+	{
+	if(iEnabled && iOwner)
+		{
+		iCurrentOperation = EOpIdle;
+		TRAPD(err, iTransportController->AcceptConnectionL());
+		if(err != KErrNone)
+			{
+			iEnabled = EFalse;
+			}
+		return(err);
+		}
+	else
+		{
+		return(KErrNone);
+		}
+	}
+
+
+
+/** Sets a password required to access the server.
+
+When a password is set, a client must specify it to access the server.
+
+@param aPassword Password 
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexServer::SetChallengeL(const TDesC& aPassword)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	delete iChallPassword;
+	iChallPassword = NULL;
+	iChallPassword = HBufC8::NewL(aPassword.Length());
+	TPtr8 ptr = iChallPassword->Des();
+	CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword);
+	iChallenge = ETrue;
+	}
+
+/** Resets the password.
+
+After this call, a client does not need to provide a password to access the 
+server. 
+
+@publishedAll
+@released
+*/
+EXPORT_C void CObexServer::ResetChallenge()
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	delete iChallPassword;
+	iChallPassword = NULL;
+	iChallenge = EFalse;
+	}
+
+/**	
+Specifies target header checking behaviour.
+	
+Supports three behaviours---never check, always check, and check only if a target
+header has been sent.  The default behaviour is to only check when a target header
+has been sent.
+	
+No checking allows a form of multiplexing to be used, where one server object may
+respond to multiple target headers.  The behaviour desired by the client can be
+determined by examining the target header specified in the Connect.
+	
+@param aChecking The desired level of target header checking.
+@publishedAll
+@released
+*/
+EXPORT_C void CObexServer::SetTargetChecking(TTargetChecking aChecking)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	iTargetChecking = aChecking;
+	}
+
+
+/**
+Prepare next packet for the connection attempt
+ConnectionID and Who headers are Mandatory if the Target header was used in the connection from
+@param aPacket Packet to fill
+@internalComponent
+*/
+TInt CObexServer::PrepareConnectPacket(CObexPacket& aPacket) 
+	{
+	FLOG(_L("CObexServer::PrepareConnectPacket\r\n"));
+	TInt retValue = KErrNone;
+	TConnectState nextState = GetConnectState();
+
+	if(!iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags))
+		{
+		FLOG(_L("PrepareConnectPacket Local data insertion FAILED\r\n"));
+		return(KErrGeneral);
+		}
+	FLOG(_L("PrepareConnectPacket Local data inserted\r\n"));
+
+	if(GetConnectState() == ESimpleConnRequest)	//no Auth requested by the Client
+		{
+		FLOG(_L("PrepareConnectPacket GetConnectState() == ESimpleConnRequest\r\n"));
+		//if the Server must challenge
+		if(iChallenge) 
+			{
+			FLOG(_L("PrepareConnectPacket Challenge Required\r\n"));
+
+			aPacket.SetOpcode(ERespUnauthorized);  
+			retValue = GenerateChallenge(aPacket);
+			if ( retValue == KErrNone ) 
+				{
+				FLOG(_L("PrepareConnectPacket Challenge generated\r\n"));
+				nextState = ESimpleConnChallIssued;
+				}
+			else
+				{
+				FLOG(_L("PrepareConnectPacket Challenge generation FAILED\r\n"));
+				nextState = EConnTransport;
+				aPacket.SetOpcode(ERespInternalError);
+				}
+			}
+		else //don't require Authentication
+			{
+			FLOG(_L("PrepareConnectPacket No Challenge Required\r\n"));
+
+			aPacket.SetOpcode(ERespSuccess); 
+			//if the Target header was used for the connection
+			//if so then reply with ConnectionID and Who headers
+			if ((retValue = AddConnectionIDHeader(aPacket)) == KErrNone)
+				{
+				FLOG(_L("PrepareConnectPacket ConnectionID Inserted\r\n"));
+				nextState = EConnObex;
+				}
+			else
+				{
+				nextState = EDropLink;
+				FLOG(_L("PrepareConnectPacket ConnectionID Insertion FAILED\r\n"));
+				}
+			}
+		} //end if(GetConnectState() == ESimpleConnRequest) 
+	else if (GetConnectState() == EChallConnRequested)
+		{
+		FLOG(_L("PrepareConnectPacket GetConnectState() == EChallConnRequested\r\n"));
+
+		//if the Server must challenge
+		if(iChallenge) 
+			{
+			FLOG(_L("PrepareConnectPacket Challenge required\r\n"));
+			aPacket.SetOpcode(ERespUnauthorized); 
+			retValue = GenerateChallenge(aPacket);
+			if ( retValue == KErrNone ) 
+				{
+				FLOG(_L("PrepareConnectPacket Challenge Generated\r\n"));
+				nextState = EChallConnChallIssued; //chall answered with another chall
+				}
+			else
+				{
+				FLOG(_L("PrepareConnectPacket Challenge Generation FAILED\r\n"));
+				nextState = EConnTransport;
+				aPacket.SetOpcode(ERespInternalError);
+				}
+			}
+		else //don't require Authentication
+			{ //the response would already have been verified in ParseConnectPacket() 
+			//get password from user, prepare a response to the challenge
+			FLOG(_L("PrepareConnectPacket Challenge Not Required\r\n"));
+			retValue = PrepareFinalChallResponse(aPacket, nextState);
+			}
+		} //end else if GetConnectState() == EChallConnRequested
+	else if (GetConnectState() == EFinalChallRxed)
+		{	//
+		retValue = PrepareFinalChallResponse(aPacket, nextState);
+		}
+	else if ( GetConnectState() == EFinalResponseReceived )
+		{ //the response had to be OK otherwise would never have gotten this far
+		aPacket.SetOpcode(ERespSuccess); 
+		//if the Target header was used for the connection
+		//if so then reply with ConnectionID and Who headers
+		if ((retValue = AddConnectionIDHeader(aPacket)) == KErrNone)
+			{
+			nextState = EConnObex;
+			FLOG(_L("PrepareConnectPacket ConnectionID header Added\r\n"));
+			}
+		else
+			{
+			nextState = EDropLink;
+			FLOG(_L("PrepareConnectPacket ConnectionID header Addition FAILED\r\n"));
+			}
+		}
+	else //it's all gone wrong
+		{
+		FLOG(_L("PrepareConnectPacket complete failure, bad state\r\n"));
+
+		//break connection, inform user
+		nextState = EConnTransport;
+		aPacket.SetOpcode(ERespInternalError);
+		retValue = KErrGeneral;
+		}
+	//if the Server is now connected inform the client
+	if ( nextState == EConnObex)
+		iOwner->ObexConnectIndication(iRemoteInfo, TPtr8(NULL, 0));
+
+	SetConnectState(nextState);
+	return(retValue);
+	}
+/**
+Prepare next packet for an  invalid connection attempt (i.e. the ParseConnectPacket failed).
+A fail response (to a connect request)  includes the version, flags, and packet size information.
+
+@param aPacket Packet to fill
+@internalComponent
+*/
+TInt CObexServer::PrepareErroredConnectPacket(CObexPacket& aPacket)
+	{
+	FLOG(_L("CObexServer::PrepareErroredConnectPacket\r\n"));
+	
+	if ( !iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags))
+		{
+		FLOG(_L("PrepareConnectPacket Local data insertion FAILED\r\n"));
+		return(KErrGeneral);
+		}	
+	return KErrNone;
+	}
+
+void CObexServer::SignalReadActivity()
+	{
+	iPacketProcessSignaller->Signal(EObexReadActivityDetected);
+	}
+	
+void CObexServer::CheckTarget(TConnectState& aNextState, TInt& aRetVal)
+	{
+	FLOG(_L("Local Who:\r\n"));
+	LOGHEXDESC(iLocalInfo.iWho);
+	FLOG(_L("Target:\r\n"));
+	LOGHEXDESC(iRemoteInfo.iTargetHeader);
+	
+	// Workaround for bug with PocketPC 2002---if target header is sixteen bytes of zeros, connect anyway.
+	_LIT8(KZeroTarget, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
+
+	// Allow connection iff:
+	//    PocketPC attempting to connect to inbox (Sixteen bytes of zeros), when no LocalWho
+	// or Target header matches LocalWho (includes Inbox connections)
+	
+	if (!(	// Negate as block below discards connection
+		    ((iLocalInfo.iWho == KNullDesC8) && (iRemoteInfo.iTargetHeader == KZeroTarget))
+		 || ( iLocalInfo.iWho == iRemoteInfo.iTargetHeader)
+	   ))
+		{
+		FLOG(_L("ParseConnectPacket ETarget header doesn't match local iWho, dropping link\r\n"));
+		aNextState = EConnTransport;
+		aRetVal = ERespNotFound;
+		}
+	}
+
+
+//if the Target header is sent then it must match the local iWho field
+TInt CObexServer::ParseConnectPacket(CObexPacket& aPacket)
+	{
+	TConnectState nextState = GetConnectState(); //must change otherwise it's all wrong
+	TBool challReceivedOK = EFalse; //authentication challenge received from client 
+									//after server has issued its own authentication challenge.
+	TBool respReceivedOK = EFalse;  //authentication received from client 
+									//after server has issued its own authentication challenge.
+	FLOG(_L("CObexServer::ParseConnectPacket\r\n"));
+
+	if(!iTransportController->ExtractRemoteConnectInfo(aPacket, iRemoteInfo.iVersion, iRemoteInfo.iFlags))
+		{
+		FLOG(_L("ParseConnectPacket remote connect info extraction FAILED\r\n"));
+		return KErrGeneral;
+		}
+	FLOG(_L("ParseConnectPacket remote connect info extracted\r\n"));
+
+	TObexInternalHeader hdr;
+  	iTargetReceived = EFalse; //if target received then must reply with ConnectionID
+
+	//if the present state is EConnTransport then no headers are actually
+	//required, a simple connect is sufficient
+	if(GetConnectState() == EConnTransport)
+		{
+		nextState = ESimpleConnRequest;
+		}
+
+	TInt retVal = KErrNone;
+	TBool authAttempted = EFalse;
+	
+	while (aPacket.ExtractData(hdr) && (nextState != EDropLink) && (nextState != EConnTransport))
+		{
+		switch(hdr.HI())
+			{
+			case TObexInternalHeader::ETarget:
+				{
+				FLOG(_L("ParseConnectPacket extracting ETarget header\r\n"));
+				iTargetReceived = ETrue;
+				//copy the target header into iRemoteInfo for the user
+				iRemoteInfo.iTargetHeader.Copy(hdr.HVByteSeq(), hdr.HVSize() > iRemoteInfo.iTargetHeader.MaxSize() ? iRemoteInfo.iTargetHeader.MaxSize() : hdr.HVSize());
+
+				if (iTargetChecking == EIfPresent)
+					{
+					FLOG(_L("EIfPresent target header checking..."));
+					CheckTarget(nextState, retVal);
+					}
+				}
+				break;
+			case TObexInternalHeader::EAuthChallenge:
+				{
+				FLOG(_L("ParseConnectPacket EAuthChallenge Header received processing\r\n"));
+				authAttempted = ETrue;
+				TRAPD(err, ProcessChallengeL(hdr));
+				if (!err)
+					{
+					FLOG(_L("ParseConnectPacket Processing Chall SUCCESS\r\n"));
+					if (GetConnectState() == EConnTransport)
+						{
+						nextState = EChallConnRequested;
+						}
+					else if ((GetConnectState() == ESimpleConnChallIssued) || (GetConnectState() == EChallConnChallIssued))
+						{
+						challReceivedOK = ETrue; //the response must be verified first
+						nextState = EFinalChallRxed;
+						}
+					else
+						{
+						nextState = EConnTransport;
+						retVal = ERespInternalError;
+						}
+					}
+				else
+					{
+					FLOG(_L("ParseConnectPacket Processing Chall FAILED\r\n"));
+
+					nextState = EConnTransport;
+					retVal = ERespInternalError;
+					}
+				}
+				break;
+			case TObexInternalHeader::EAuthResponse:
+				{
+				if (iChallenge)
+					//else there is no challenge password to check against!
+					{
+					FLOG(_L("ParseConnectPacket EAuthResponse Header received processing\r\n"));
+					authAttempted = ETrue;
+					TRAPD(err, ProcessChallResponseL(hdr));
+					if (err == KErrNone)
+						{
+						FLOG(_L("ParseConnectPacket Processing Chall Response SUCCESS\r\n"));
+						if (GetConnectState() == ESimpleConnChallIssued)
+							{
+							respReceivedOK =ETrue;
+							if (challReceivedOK) //was a new challenge issued by the Client?
+								{
+								nextState = EFinalChallRxed; //must respond to chall
+								}
+							else
+								{
+								nextState = EFinalResponseReceived; //everything is OK send Success
+								}
+							}
+						else if (GetConnectState() == EChallConnChallIssued)
+							{
+							respReceivedOK =ETrue;
+							if (challReceivedOK) //was a new challenge issued by the Client?
+								{
+								nextState = EFinalChallRxed; //must respond to chall
+								}
+							else
+								{
+								//If we do not later in the packet see a challenge,
+								//(in which case this 'nextState' value will be overwritten),
+								//the client will have come back WITHOUT re-issuing 
+								//either his original challenge or a new one.
+								//Treat as if client had never issued a challenge. 
+								//This sequence has been observed in FOMA phones.
+								nextState = EFinalResponseReceived; 
+								}
+							}
+						else
+							{
+							nextState = EConnTransport;
+							retVal = ERespInternalError;
+							}
+						}
+					else if (err == KErrAccessDenied)
+						{
+						nextState = EConnTransport;
+						retVal = ERespUnauthorized;
+						FLOG(_L("ParseConnectPacket Processing Chall Response FAILED with Access Denied\r\n"));
+						}
+					else
+						{
+						nextState = EConnTransport;
+						retVal = ERespInternalError;
+						FLOG(_L("ParseConnectPacket Processing Chall Response FAILED\r\n"));
+						}
+					}
+				else
+					{
+					// if no challenge was issued, then receiving a challenge response means the peer is badly
+					// behaved. For this case we simply ignore the header, anything else would be too drastic.
+					FLOG(_L("ParseConnectPacket Chall Response received when no Chall issued\r\n"));
+					}
+				}
+				break;
+		default:
+			break;
+			}
+		}
+		
+	if (((GetConnectState() == ESimpleConnChallIssued) || (GetConnectState() == EChallConnChallIssued)) && !respReceivedOK)
+		// Client's connect packet should have contained an authentication response.
+		// Treat as if we had rejected an authentication response.
+		{
+		nextState = EConnTransport;
+		retVal = ERespUnauthorized;
+		}
+		
+	if (iTargetChecking == EAlways)
+		{
+		FLOG(_L("EAlways target header checking..."));
+		CheckTarget(nextState, retVal);
+		}
+
+	if (!authAttempted && (GetConnectState() == ESimpleConnChallIssued))
+		nextState = ESimpleConnRequest;
+
+	SetConnectState(nextState);
+	
+	return retVal;
+	}
+
+
+/** 
+Check, if required, the object connection ID.
+
+@return ETrue if it was not necessary to receive the ConnectionID or
+		if it was necessary and was correctly received. Otherwise 
+		EFalse.
+@internalComponent
+*/
+TBool CObexServer::CheckObjectForConnectionId(CObexBaseObject& aObject)
+	{
+	TBool retValue = ETrue;
+
+	if( iTargetReceived )
+		{
+		retValue = EFalse;
+		if (aObject.iValidHeaders & KObexHdrConnectionID )
+			{
+			TUint32 connID = aObject.ConnectionID();
+			if (iConnectionIdSet && (iConnectionID == connID))
+				{
+				retValue = ETrue;
+				}
+			}
+		}
+	return (retValue);
+	}
+
+/**
+Check, if required, that the packet connection ID matches that of the Server's current connection
+@return ETrue if the connection ID matches or if Target was not used in the original connection
+@return EFalse if Target was not used in the original connection and the connection ID was not found
+@internalComponent
+*/
+TBool CObexServer::CheckPacketForConnectionId(CObexPacket& aPacket)
+	{
+	// Connection ID check is compulsory if Target was used in the original connection
+	if (!iTargetReceived)
+		{
+		return ETrue;
+		}
+
+	// Search for ConnectionID
+	// ConnectionID should be the first header, but we check all of them just in case
+	TObexInternalHeader header;
+	while (aPacket.ExtractData(header))
+		{
+		if (header.HI() == TObexInternalHeader::EConnectionID)
+			{
+			TUint32 newConnectionID = (header.HVByteSeq()[0] << 24) + (header.HVByteSeq()[1] << 16)
+						+ (header.HVByteSeq()[2] << 8)  + (header.HVByteSeq()[3]);
+
+			if (ConnectionID() == newConnectionID)
+				{
+				return ETrue;
+				}
+			}
+		}
+
+	// Target was used in original connection and could not find Connection ID
+	return EFalse;
+	}
+
+void CObexServer::OnPacketReceive(CObexPacket& aPacket)
+	{
+	FLOG(_L("CObexServer::OnPacketReceive\r\n"));
+	MObexServerRequestPacketNotify* packetNotify = NULL;
+	if (iServerRequestPacketEngine)
+		{
+		packetNotify = iServerRequestPacketEngine->RequestPacketNotify();		
+		}
+	// If a packet notify has been registered then we should tell it 
+	// about each request packet we receive.
+	if (packetNotify)
+		{
+		TObexResponse response;
+		TBool normalOperation = ETrue;
+		
+		// Rebuild full OBEX opcode to pass to observer
+		TObexOpcode opcode = aPacket.Opcode() | (aPacket.IsFinal() ? KObexPacketFinalBit : 0);
+		
+		switch (aPacket.Opcode())
+			{
+		case CObex::EOpConnect:
+				{
+				TObexConnectInfo connectInfo;
+				if (!iStateMachine->Transport().ExtractRemoteConnectInfo(aPacket, connectInfo.iVersion, connectInfo.iFlags))
+					{
+					// If the packet cannot be parsed correctly at this stage it is very malformed
+					// and so we should abort processing it for the server app, and defer handling
+					// the error to the state machine.
+					break;
+					}
+				
+				TObexInternalHeader header;
+				// Call ExtractData() until it returns 0 bytes read - then we know the extract
+				// point will have been reset so the CObexPacket can be parsed again in the 
+				// future.  For this reason do not attempt to optimise this loop.
+				while (aPacket.ExtractData(header))
+					{
+					switch (header.HI())
+						{
+					case TObexInternalHeader::ETarget:
+						 // Only take the first Target header found
+						 if (connectInfo.iTargetHeader.Length() == 0)
+							{
+							TInt size = header.HVSize() > connectInfo.iTargetHeader.MaxSize() ? connectInfo.iTargetHeader.MaxSize() : header.HVSize();
+							connectInfo.iTargetHeader.Copy(header.HVByteSeq(), size);
+							}
+						break;
+					case TObexInternalHeader::EWho:
+						 // Return the first Who header in packet
+						 if (connectInfo.iWho.Length() == 0)
+							{
+							TInt size = header.HVSize() > connectInfo.iWho.MaxSize() ? connectInfo.iWho.MaxSize() : header.HVSize();
+							connectInfo.iWho.Copy(header.HVByteSeq(), size);
+							}
+						break;
+					default:
+						break;
+						}
+					}
+				
+				normalOperation = packetNotify->RequestPacket(opcode, connectInfo, response);
+				}
+			break;
+		case CObex::EOpSetPath:
+				{
+				TObexSetPathData data;
+	
+				if (!aPacket.ExtractData(data))
+					{
+					// If the packet cannot be parsed correctly at this stage it is very malformed
+					// and so we should abort processing it for the server app, and defer handling
+					// the error to the state machine.
+					break;
+					}
+				CObex::TSetPathInfo info(data);
+					
+				TObexInternalHeader header;
+				// Call ExtractData() until it returns 0 bytes read - then we know the extract
+				// point will have been reset so the CObexPacket can be parsed again in the 
+				// future.  For this reason do not attempt to optimise this loop.
+				while(aPacket.ExtractData(header))
+					{
+					// Take the first name header we find.
+					if(!info.iNamePresent && header.HI() == TObexInternalHeader::EName && header.GetHVText(info.iName) == KErrNone)
+						{
+						info.iNamePresent = ETrue;
+						}
+					}
+	
+				normalOperation = packetNotify->RequestPacket(opcode, info, response);
+				}
+			break;	
+		case CObex::EOpDisconnect:
+		case CObex::EOpAbortNoFBit:
+		case CObex::EOpPut:
+		case CObex::EOpGet:	
+		default:
+			normalOperation = packetNotify->RequestPacket(opcode, response);
+			break;
+			}
+
+		if (!normalOperation) // Abandon processing of request
+			{
+			CheckServerAppResponseCode(aPacket.Opcode(), response); // a success response code => panic
+			iStateMachine->OverrideRequestHandling(response);
+			return;
+			}
+		}
+
+	// Normal processing
+	iStateMachine->OnPacketReceive(aPacket);
+	}
+
+/**
+This function is to ensure that a response a server application provides the Obex Server
+to respond to the Obex Client with when it has overriden the default handling of a request
+packet does not represent a success.
+
+The rationale for this is to attempt to keep the Obex peers synchronised.  As the packet has
+been dropped, the client should not be lead to believe it has been received successfully.
+
+Therefore, this function asserts that the application does not send a success response for 
+the request packet received.
+*/	
+void CObexServer::CheckServerAppResponseCode(TObexOpcode aOpcode, TObexResponse aResponse)
+	{
+	TBool valid = ETrue;
+	switch (aOpcode)
+		{
+		case CObex::EOpConnect:
+			if (aResponse == ERespSuccess)
+				{
+				valid = EFalse;
+				}
+			break;
+		case CObex::EOpPut:
+		case CObex::EOpGet:
+			if (aResponse == ERespSuccess || aResponse == ERespContinue)
+				{
+				valid = EFalse;
+				}
+			break;
+		case CObex::EOpSetPath:
+			if (aResponse == ERespSuccess)
+				{
+				valid = EFalse;
+				}
+			break;
+		case CObex::EOpDisconnect:
+		case CObex::EOpAbortNoFBit:
+			// We allow any response to a abort/disconnect request,
+			// as only success codes are allowed.
+		default:
+			break;
+		}
+	__ASSERT_ALWAYS(valid, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
+	}
+
+void CObexServer::OnError(TInt aError)
+	{
+	FTRACE(FPrint(_L("OnError aError: %d iCurrentOperation: %d, iConnectState: %d"), aError, iCurrentOperation, iConnectState));
+
+	if (aError == KErrDisconnected)
+		{
+		// Note: It is not clear that iCurrentOperation is ever equal
+		// to EOpDisconnect but the check has been retained just in case
+		if ((iCurrentOperation != EOpDisconnect) && (iConnectState > EConnTransport))
+			{
+			 //extended error for IrObex,("peer device aborted data transmission/obex sending") 
+			iOwner->ErrorIndication(KErrIrObexServerPutPeerAborted);
+			}
+		}
+	else
+		{
+		iOwner->ErrorIndication(aError);
+		}
+	// The state machine needs to know about the error regardless of whether ErrorIndication() is called
+	iStateMachine->Error();
+	}
+
+void CObexServer::OnTransportUp()
+	{
+	iTargetReceived = EFalse;
+
+	// For servers on the device using USB, there is a possibility that
+	// this function can be called, even though the server is stopped,
+	// as OBEX does not control the transport, the USB host does.
+	// Hence the need to check if there is an active iOwner.
+	if (iOwner)
+		{
+		iOwner->TransportUpIndication();
+		}
+	iStateMachine->TransportUp(); // state machine needs to know about the event regardless of Server state
+	}
+
+/**
+Tell the MObexServerNotifyAsync observer the transport is down and listen
+for another connection.
+*/
+void CObexServer::OnTransportDown()
+	{// Cancel Anything waiting. Restart the accepter	
+
+	// For servers on the device using USB, there is a possibility that
+	// this function can be called, even though the server is stopped,
+	// as OBEX does not control the transport, the USB host does
+	// Hence the need to check if there is an active iOwner.
+	if (iOwner)
+		{
+		iOwner->TransportDownIndication();
+		}
+	iStateMachine->TransportDown(); // state machine needs to know about the event regardless of Server state
+	TInt err = AcceptConnection();
+	if(err != KErrNone)
+		Error(err);
+	}
+
+/** Signals an event has ocurred.
+
+@released
+@internalComponent
+@param aEvent The event that has occurred. (TObexPacketProcessEvent)
+*/
+void CObexServer::SignalPacketProcessEvent(TInt aEvent)
+	{
+	LOG_FUNC
+
+	// This is how we signal the completed send of an ACK to a disconnect 
+	// command. Tell the state machine so it can finish the disconnection 
+	// sequence.
+	if(aEvent & EObexWriteCompletedFinal)
+		{
+		iStateMachine->WriteComplete();
+		}
+
+	// Server will have definitely finished with the read packet so queue the next read
+	if(aEvent & EObexWriteCompleted)
+		{
+		iTransportController->Receive();
+		}
+		
+	if(aEvent & EObexReadActivityDetected)
+		{
+		iStateMachine->ReadActivityDetected();
+		}
+	}
+	
+// CObexServer
+/** Tests if the server is started, and is available to accept connections.
+	
+@return ETrue if the server is started, EFalse otherwise
+	
+@publishedAll
+@released
+*/
+EXPORT_C TBool CObexServer::IsStarted() 
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	return iEnabled;
+	}
+
+/**
+Returns the operation currently being performed by the remote client, or 
+EOpIdle if between operations. Note that there is no implication of whether 
+the server is currently connected; EOpIdle will be returned regardless of 
+connection state, if no operation is currently being performed. Use 
+CObex::IsConnected () to find connection staus.
+
+@return Operation currently being performed by the remote client
+
+@publishedAll
+@released
+*/
+EXPORT_C CObex::TOperation CObexServer::CurrentOperation() const 
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	return iCurrentOperation;
+	}
+
+/**
+Setter function to allow other classes in the DLL to set the Server's current operation.
+Used by the Server state machine.
+@see CObexServerStateMachine
+@param aOperation The operation currently being performed by the remote client
+@internalComponent
+*/
+void CObexServer::SetCurrentOperation(const CObex::TOperation aOperation)
+	{
+	iCurrentOperation = aOperation;
+	}
+
+/**
+Specify the set of headers to return to remote Obex client in final
+Put response packet. The total length of the headers when encoded 
+should not exceed the maximum Obex packet payload size.
+
+This function may be called at any point during a Put operation.
+Repeated calls to this replace rather than add to the header set
+for inclusion in the final Put response packet.
+
+It may be called with a NULL pointer, which means that no headers
+will be sent with the Put Final Response.
+
+Even if this function returns with an error (even KErrNotReady) a
+best-effort attempt will be made to send as many headers as will fit
+in the final Put response packet.
+
+@param aHeaderSet A set of headers to be encoded in the final Put
+response packet. Ownership of the header set always passes to 
+CObexServer.
+
+@return KErrNone if the operation completes successfully.
+		KErrNotReady if the current operation is not a Put.
+		KErrArgument if the length of the headers when encoded
+		exceeds the maximum Obex packet payload size.
+		
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::SetPutFinalResponseHeaders(CObexHeaderSet* aHeaderSet)
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	//	First, let the state machine take ownership of the headerset
+	iStateMachine->SetPutFinalResponseHeaderSet(aHeaderSet);
+
+	TInt err=KErrNone;
+
+	//	Easy check first - are we currently engaged in a Put?
+	if(iCurrentOperation != EOpPut)
+		{
+		err=KErrNotReady;
+		}
+
+	if(!err && aHeaderSet)
+		{
+		//	Next, the not so easy check. Will all the headers, when encoded,
+		//	fit inside a send packet? 
+		//	First, how much space do we have to play with?
+		TInt available = iTransportController->SendPacket().DataLimit() - KObexPacketHeaderSize;
+		
+		//	Next, what is the combined encoded size of all the headers?
+		TInt required = 0;
+		aHeaderSet->First();
+		while(aHeaderSet->This(iHeader) == KErrNone)
+			{
+			required+=iHeader->EncodedSize();
+			(void)aHeaderSet->Next();
+			}
+
+		if(required>available)
+			{
+			err=KErrArgument;
+			}
+		}
+		
+	return err;
+	}
+
+
+/**
+Complete an asynchronous callback, supplying a CObexBaseObject derived object.
+Passing in NULL results in an Obex level error being sent to the client -- the
+semantics are that either a PUT request has been rejected or a GET request has
+not found a suitable object to return.
+
+@panic Obex ENoNotificationToComplete Raised if the server does not have a request
+outstanding.
+@param aObject The object passed back from application
+@return result of state changes
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::RequestIndicationCallback(CObexBaseObject* aObject)
+	{
+	LOG_LINE
+	LOG_FUNC
+	return iStateMachine->RequestNotificationCompleted(aObject);
+	}
+
+/**
+Complete an asynchronous callback, supplying a obex response code. Applications 
+should use this function when rejecting Get/Put RequestIndication in order to 
+specify the response code.
+
+@panic Obex ENoNotificationToComplete Raised if the server does not have a request
+outstanding.
+@panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode is outside range
+[1,255] or it is one of the successful response (e.g. ERespSuccess, ERespContinue) 
+@param TObexResponse aResponseCode Application's response to the indication as an Obex response Code. The Final bit is ignored.
+@return result of state changes
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::RequestIndicationCallbackWithError(TObexResponse aResponseCode)
+	{
+	LOG_LINE
+	LOG_FUNC
+	return iStateMachine->RequestNotificationCompleted(aResponseCode);
+	}
+
+/**
+Complete an asynchronous callback, supplying a obex response code. Applications 
+should use this function when rejecting Get/Put RequestIndication in order to 
+specify the error code.
+
+@panic Obex ENoNotificationToComplete Raised if the server does not have a request
+outstanding.
+@panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode non-negtive. Note: KErrNone is 
+not acceptable because this function is only used when there is an error.
+@param aErrorCode Application's response to the indication as an Obex response Code. 
+@return result of state changes
+@publishedAll
+@released
+*/	
+EXPORT_C TInt CObexServer::RequestIndicationCallbackWithError(TInt aErrorCode)
+	{
+	LOG_LINE
+	LOG_FUNC
+	__ASSERT_ALWAYS(aErrorCode <= 0, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
+	return iStateMachine->RequestNotificationCompleted(IrOBEXUtil::ObexResponse(aErrorCode, ERespSuccess));
+	}
+	
+	
+/**
+Complete an asynchronous callback, supplying a obex response code. This function is 
+used for asychronously handling PutComplete, GetComplete and SetPath Indication. 
+
+@panic Obex ENoNotificationToComplete Raised if the server does not have a request
+outstanding.
+@panic Obex EInvalidResponseCodeFromServerApp raised if TObexResponse aResponseCode is outside range
+[1,255] or it is ERespContinue (which would confuse the client)
+@param TObexResponse aResponseCode Application's response to the indication as an Obex response Code. The Final bit is ignored.
+@return result of state changes
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::RequestCompleteIndicationCallback(TObexResponse aResponseCode)
+	{
+	LOG_LINE
+	LOG_FUNC
+	return iStateMachine->RequestCompleteNotificationCompleted(aResponseCode);
+	}
+
+/**
+Complete an asynchronous callback, supplying a obex response code. This function is 
+used for asychronously handling PutComplete, GetComplete and SetPath Indication. 
+
+@panic Obex ENoNotificationToComplete Raised if the server does not have a request
+outstanding.
+@panic Obex EInvalidResponseCodeFromServerApp raised if aErrorCode is positive, i.e. 
+invalid Symbian error code
+@param TObexResponse aResponseCode Application's response to the indication as a Symbian error code
+@return result of state changes
+@publishedAll
+@released
+*/
+EXPORT_C TInt CObexServer::RequestCompleteIndicationCallback(TInt aErrorCode)
+	{
+	LOG_LINE
+	LOG_FUNC
+	__ASSERT_ALWAYS(aErrorCode <= 0, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp));
+	return iStateMachine->RequestCompleteNotificationCompleted(IrOBEXUtil::ObexResponse(aErrorCode, ERespSuccess));
+	}
+	
+/**
+Provides the pre-parsed contents of the most recently received request packet.
+
+@param aHeaderSet A reference to a pointer that will be modified to NULL if no headers
+are contained in the request packet, or to point to a new headerset containing
+representations of the headers within the packet. Ownership of the headerset
+(when aHeaderSet is not NULL) is passed to the caller.
+@return KErrNone if successful, otherwise a system wide error code.
+
+@publishedPartner
+@released
+*/
+EXPORT_C TInt CObexServer::PacketHeaders(CObexHeaderSet*& aHeaderSet)
+	{
+	FLOG(_L8("CObexServer::PacketHeaders"));
+
+	return DoPacketHeaders(aHeaderSet, NULL);	
+	}
+
+
+/**
+Provides the selectively pre-parsed contents of the most recently received request packet.
+
+@param aHeaderSet A reference to a pointer that will be modified to NULL if no interesting
+header are contained in the request packet, or to point to a new headerset containing
+representations of the headers within the packet that are of interest. Ownership of the 
+headerset (when aHeaderSet is not NULL) is passed to the caller.
+@param aHeaderCheck A reference to an MObexHeaderCheck derived class that encapsulates
+whether or not a particular header or headers should be included in the returned header
+set (i.e. whether the headers are "interesting").
+
+@return KErrNone if successful, otherwise a system wide error code.
+
+@publishedPartner
+@released
+*/
+EXPORT_C TInt CObexServer::PacketHeaders(CObexHeaderSet*& aHeaderSet, MObexHeaderCheck& aHeaderCheck)
+	{
+	FLOG(_L8("CObexServer::PacketHeaders (selective)"));
+
+	return DoPacketHeaders(aHeaderSet, &aHeaderCheck);
+	}
+
+/** Sets a read activity observer.
+
+This replaces any previous observer.  The observer will receive a callback
+when the first read arrives for a put or get request. 
+
+This does not transfer ownership.
+
+@publishedPartner
+@released
+@param aObserver The observer to receive packet process events.  This may
+				 be NULL.
+*/
+EXPORT_C void CObexServer::SetReadActivityObserver(MObexReadActivityObserver* aObserver)
+	{
+	iPacketProcessSignaller->SetReadActivityObserver(aObserver);
+	}
+/**
+Contains the functionality for the PacketHeader interface functions in a refactored way.
+
+@param aHeaderSet A reference to a pointer that will be modified to NULL if no interesting
+header are contained in the request packet, or to point to a new headerset containing
+representations of the headers within the packet that are of interest. Ownership of the 
+headerset (when aHeaderSet is not NULL) is passed to the caller.
+@param aHeaderCheck A pointer to an MObexHeaderCheck derived class that encapsulates
+whether or not a particular header or headers should be included in the returned header
+set (i.e. whether the headers are "interesting").  If the pointer is NULL then that is taken
+to mean that all headers should be added to the aHeaderSet.
+
+@return KErrNone if successful, otherwise a system wide error code.
+*/	
+TInt CObexServer::DoPacketHeaders(CObexHeaderSet*& aHeaderSet, MObexHeaderCheck* aHeaderCheck)
+	{
+	FLOG(_L8("CObexServer::DoPacketHeaders"));
+	
+	TRAPD(err, aHeaderSet = CObexHeaderSet::NewL());
+	if (err != KErrNone)
+		{
+		aHeaderSet = NULL;
+		return err;
+		}
+	
+	CObexPacket& packet = iTransportController->ReceivePacket();
+	
+	// for "non-standard" size requests ensure we correctly start
+	// extracting headers where they start.
+	switch (packet.Opcode())
+		{
+	case CObex::EOpConnect:
+			{
+			TObexConnectInfo connectInfo;
+			if (!iStateMachine->Transport().ExtractRemoteConnectInfo(packet, connectInfo.iVersion, connectInfo.iFlags))
+				{
+				err = KErrUnderflow;
+				}
+			}
+		break;
+	case CObex::EOpSetPath:
+			{
+			TObexSetPathData data;
+			if (!packet.ExtractData(data))
+				{
+				err = KErrUnderflow;
+				}
+			}
+		break;
+	default:	
+		break;	
+		}
+	
+	TBool interestingHeaders = EFalse;
+	TObexInternalHeader header;
+	// Call ExtractData() until it returns 0 bytes read - then we know the extract
+	// point will have been reset so the CObexPacket can be parsed again in the 
+	// future.  For this reason do not attempt to optimise this loop.
+	while(packet.ExtractData(header))
+		{
+		// if there was an error previously we want to just keep going through the
+		// loop to reset the CObexPacket extraction point.
+		if (err == KErrNone && (!aHeaderCheck || aHeaderCheck->Interested(header.HI())))
+			{
+			err = IrOBEXHeaderUtil::ParseHeader(header, *aHeaderSet);
+			if (!interestingHeaders && err == KErrNone)
+				{
+				interestingHeaders = ETrue;
+				}
+			}
+		}
+
+	if (err != KErrNone || !interestingHeaders)
+		{
+		delete aHeaderSet;
+		aHeaderSet = NULL;
+		}
+	return err;	
+	}
+
+/**
+Provides additional interfaces for CObexServer.
+
+@param aUid The UID of the interface that is required.
+@return A pointer to an instance implementing the interface represented by aUid.
+
+@leave KErrNotSupported if the given UID does not represent an interface CObexServer can provide.
+@leave KErrInUse if an instance of MObexServerRequestPacketNotifyRegister has already been provided
+				 by an earlier call to ExtensionInterfaceL, and it has not been released.
+
+@internalTechnology
+*/
+EXPORT_C TAny* CObexServer::ExtensionInterfaceL(TUid aUid)
+	{
+	// MObexServerRequestPacketNotifyRegister interface
+	if (aUid == KObexServerRequestPacketNotifyRegisterInterface)
+		{
+		// We only return an instance if there are no other packet access extensions
+		// hooked into the CObexServer instance (indicated by the existance of an engine).
+		if (iServerRequestPacketEngine)
+			{
+			User::Leave(KErrInUse);
+			}
+		iServerRequestPacketEngine = CObexServerRequestPacketEngine::NewL(*this);
+		return static_cast<MObexServerRequestPacketNotifyRegister*>(iServerRequestPacketEngine);
+		}
+	// if we don't know the interface UID then we don't support it.
+	User::Leave(KErrNotSupported);
+	return NULL; // to silence the compiler.
+	}
+
+/** 
+Returns a pointer to the TObexTransportInfo being used by the OBEX transport 
+layer. THE USER MUST NOT MODIFY THE OBJECT POINTED TO.
+This is useful primarily when using OBEX over RFCOMM and the user has 
+specified 'KRfcommPassiveAutoBind' as the port. KRfcommPassiveAutoBind makes 
+RFCOMM itself find a free port. The user needs to know which port is really 
+being used by RFCOMM in order to correctly populate the SDP record. 
+May be called meaningfully after CObexServer::Start has returned KErrNone. 
+@return Pointer to the transport layer's transport info.
+@publishedAll
+@released
+*/
+EXPORT_C const TObexTransportInfo* CObexServer::TransportInfo() const
+	{
+	LOG_LINE
+	LOG_FUNC
+
+	__ASSERT_DEBUG(iTransportController, IrOBEXUtil::Fault(ETransportControllerNotCreated));
+	return iTransportController->TransportInfo();
+	}
+