networkcontrol/qoslib/src/qoslib.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/qoslib/src/qoslib.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,576 @@
+// Copyright (c) 2003-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:
+//
+
+#include <f32file.h>
+#include <es_ini.h>
+
+
+#include "qosliblog.h"
+
+#include "qoslib.h"
+#include "pfqosparser.h"
+#include "pfqos.h"
+#include "qos_ini.h"
+#include "qoslib_glob.h"
+#include "pfqos_stream.h"
+
+
+//
+// DLL entry point
+//
+GLDEF_C TInt E32Dll()
+	{
+	return(KErrNone);
+	}
+
+//
+CRequest* CRequest::NewL(CQoSRequestBase* aOwner, TUint aBufSize)
+	{
+	CRequest* request = new (ELeave) CRequest(aOwner);
+	CleanupStack::PushL(request);
+	request->ConstructL(aBufSize);
+	CleanupStack::Pop();
+	return request;
+	}
+
+CRequest::~CRequest()
+	{
+	delete iMsg;
+	}
+
+CRequest::CRequest(CQoSRequestBase* aOwner) : iOwner(aOwner)
+	{
+	iMsg = NULL;
+	}
+
+void CRequest::ConstructL(TUint aBufSize)
+	{
+	iMsg = CPfqosStream::NewL(aBufSize);
+	};
+
+
+//
+class CSender : public CActive
+	{
+	public:
+	static CSender* NewL(CQoSMan* aManager, TInt aPriority=EPriorityStandard);
+	~CSender();
+	void Send(CRequest* aRequest);
+	void ClearPendingRequest(CQoSRequestBase* aRequest);
+
+	protected:
+	CSender(CQoSMan* aManager, TInt aPriority);
+	void ConstructL();
+	void RunL();
+	void DoCancel();
+
+	private:
+	CQoSMan* iManager;
+	CRequest* iCurrentRequest;
+	TSglQue<CRequest> iRequests;
+	};
+
+CSender* CSender::NewL(CQoSMan* aManager, TInt aPriority)
+	{
+	CSender* sender = new (ELeave) CSender(aManager, aPriority);
+	CleanupStack::PushL(sender);
+	sender->ConstructL();
+	CleanupStack::Pop();
+	return sender;
+	}
+
+CSender::CSender(CQoSMan* aManager, TInt aPriority) : CActive(aPriority), iManager(aManager)
+	{
+	CActiveScheduler::Add(this);
+	iRequests.SetOffset(_FOFF(CRequest, iLink));
+	iCurrentRequest=NULL;
+	}
+
+void CSender::ConstructL()
+	{
+	}
+
+CSender::~CSender()
+	{
+	if (IsActive())
+		Cancel();
+
+	delete iCurrentRequest;
+
+	while (!iRequests.IsEmpty())
+		{
+		CRequest* request = iRequests.First();
+		iRequests.Remove(*request);
+		delete request;
+		}
+	iRequests.Reset();
+	}
+
+void CSender::Send(CRequest* aRequest)
+	{
+	if (IsActive())
+		iRequests.AddLast(*aRequest);
+	else
+		{
+		iCurrentRequest = aRequest;
+		iCurrentRequest->iMsg->Send(iManager->Socket(), iStatus);
+		SetActive();
+		}
+	}
+
+void CSender::ClearPendingRequest(CQoSRequestBase* aRequest)
+	{
+	if (iCurrentRequest != NULL)
+		{
+		if (iCurrentRequest->iOwner == aRequest)
+			iCurrentRequest->iOwner = NULL;
+		}
+	}
+
+void CSender::RunL()
+	{
+	TInt err = iStatus.Int();
+	if (err && iCurrentRequest->iOwner)
+		iCurrentRequest->iOwner->NotifyError(err);
+
+	delete iCurrentRequest;
+	iCurrentRequest = NULL;
+
+	if (!iRequests.IsEmpty())
+		{
+		CRequest* request = iRequests.First();
+		iRequests.Remove(*request);
+		iCurrentRequest = request;
+		iCurrentRequest->iMsg->Send(iManager->Socket(), iStatus);
+		SetActive();
+		}
+	}
+
+void CSender::DoCancel()
+	{
+	iManager->Socket().CancelWrite();
+	}
+
+
+//
+CQoSMan* CQoSMan::NewL(TInt aPriority)
+	{
+	CQoSMan* manager;
+	manager = QoSManGlobals::Get();
+	if (!manager)
+		{
+		manager = new (ELeave) CQoSMan(aPriority);
+		CleanupStack::PushL(manager);
+		manager->ConstructL();
+		CleanupStack::Pop();
+		QoSManGlobals::Set(manager);
+		}
+	manager->Open();
+	return manager;
+	}
+
+void CQoSMan::ConstructL()
+	{
+	_LIT(KDescPfqos, "pfqos");
+	User::LeaveIfError(iSocketServer.Connect());
+	User::LeaveIfError(iSocket.Open(iSocketServer, KDescPfqos));
+
+	iSender = CSender::NewL(this);
+	iBuf = HBufC8::NewL(KQoSDefaultBufSize);
+	TPtr8 tmp(iBuf->Des());
+	iRecBuf.Set(tmp);
+	iUid.Set(RProcess().Type());
+	iSocket.Recv(iRecBuf, 0, iStatus);
+	SetActive();
+	}
+
+CQoSMan::CQoSMan(TInt aPriority) : CActive(aPriority), iRecBuf(0,0)
+	{
+	CActiveScheduler::Add(this);
+	iRefCount = 0;
+	iChannels.SetOffset(_FOFF(CChannel, iNext));
+	iStaticPolicies.SetOffset(_FOFF(CPolicy,iNext));
+	iNotifyPending = EFalse;
+	iShutdown = EFalse;
+	}
+
+void CQoSMan::Close()
+	{
+	if (--iRefCount <= 0)
+		{
+		if (iNotifyPending)
+			iShutdown = ETrue;
+		else
+			delete this;
+		}
+	}
+
+CQoSMan::~CQoSMan()
+	{
+	while (!iChannels.IsEmpty())
+		{
+		CChannel* channel = iChannels.First();
+		iChannels.Remove(*channel);
+		delete channel;
+		}
+	iChannels.Reset();
+
+	while (!iStaticPolicies.IsEmpty())
+		{
+		CPolicy* policy = iStaticPolicies.First();
+		iStaticPolicies.Remove(*policy);
+		delete policy;
+		}
+	iStaticPolicies.Reset();
+
+	delete iSender;
+
+	if (IsActive())
+		Cancel();
+
+	iSocket.Close();
+	iSocketServer.Close();
+	delete iBuf;
+	QoSManGlobals::Set(NULL);
+	}
+
+CChannel* CQoSMan::OpenQoSChannelL(RSocket& aSocket)
+	{
+	CChannel* channel = CChannel::NewL(this, aSocket, NULL);
+	iChannels.AddLast(*channel);
+	return channel;
+	}
+
+void CQoSMan::RemoveQoSChannel(CChannel* aChannel)
+	{
+	TSglQueIter<CChannel> iter(iChannels);
+	CChannel* channel;
+	while ((channel = iter++) != NULL)
+		{
+		if (channel == aChannel)
+			{
+			iChannels.Remove(*aChannel);
+			break;
+			}
+		}
+	}
+
+void CQoSMan::SetQoSL(CChannel& aChannel)
+	{
+	CRequest* request = CRequest::NewL(&aChannel, KQoSDefaultBufSize);
+	request->iMsg->Init(EPfqosConfigChannel);
+	request->iMsg->AddQoSParameters(aChannel.GetPolicy().iQoS);
+	request->iMsg->AddChannel(aChannel.ChannelId());
+
+	TQoSExtensionQueueIter iter(aChannel.GetPolicy().Extensions());
+	CExtensionBase *extension;
+	while ((extension=iter++) != NULL)
+		request->iMsg->AddExtensionPolicy(extension->Data());
+	iSender->Send(request);
+	}
+
+void CQoSMan::CreateL(CChannel& aChannel, const TQoSSelector& aSelector)
+	{
+	CRequest* request = CRequest::NewL(&aChannel, KQoSDefaultBufSize);
+	request->iMsg->Init(EPfqosCreateChannel);
+	request->iMsg->AddSelector((TUint8)aSelector.Protocol(), iUid.UidType(), EPfqosFlowspecPolicy, aSelector.IapId(), EPfqosApplicationPriority, TPtr(0,0));
+	request->iMsg->AddSrcAddress(aSelector.GetSrc(), aSelector.GetSrcMask(), (TUint16)aSelector.MaxPortSrc()); 
+	request->iMsg->AddDstAddress(aSelector.GetDst(), aSelector.GetDstMask(), (TUint16)aSelector.MaxPortDst()); 
+	request->iMsg->AddChannel(0);
+	request->iMsg->AddQoSParameters(aChannel.GetPolicy().iQoS);
+	TQoSExtensionQueueIter iter(aChannel.GetPolicy().Extensions());
+	CExtensionBase *extension;
+	while ((extension=iter++) != NULL)
+		request->iMsg->AddExtensionPolicy(extension->Data());
+	Send(request);
+	}
+
+void CQoSMan::OpenExistingL(CChannel& aChannel, const TQoSSelector& aSelector)
+	{
+	CRequest* request = CRequest::NewL(&aChannel, KQoSDefaultBufSize);
+	request->iMsg->Init(EPfqosOpenExistingChannel);
+	request->iMsg->AddSelector((TUint8)aSelector.Protocol(), iUid.UidType(), EPfqosFlowspecPolicy, aSelector.IapId(), EPfqosApplicationPriority, TPtr(0,0));
+	request->iMsg->AddSrcAddress(aSelector.GetSrc(), aSelector.GetSrcMask(), (TUint16)aSelector.MaxPortSrc()); 
+	request->iMsg->AddDstAddress(aSelector.GetDst(), aSelector.GetDstMask(), (TUint16)aSelector.MaxPortDst()); 
+	request->iMsg->AddChannel(0);
+	Send(request);
+	}
+
+void CQoSMan::JoinL(CChannel& aChannel, const TQoSSelector& aSelector)
+	{
+	CRequest* request = CRequest::NewL(&aChannel, KQoSDefaultBufSize);
+	request->iMsg->Init(EPfqosJoin);
+	request->iMsg->AddSelector((TUint8)aSelector.Protocol(), iUid.UidType(), EPfqosFlowspecPolicy, aSelector.IapId(), EPfqosApplicationPriority, TPtr(0,0));
+	request->iMsg->AddSrcAddress(aSelector.GetSrc(), aSelector.GetSrcMask(), (TUint16)aSelector.MaxPortSrc()); 
+	request->iMsg->AddDstAddress(aSelector.GetDst(), aSelector.GetDstMask(), (TUint16)aSelector.MaxPortDst()); 
+	request->iMsg->AddChannel(aChannel.ChannelId());
+	Send(request);
+	}
+
+
+void CQoSMan::LeaveL(CChannel& aChannel, const TQoSSelector& aSelector)
+	{
+	CRequest* request = CRequest::NewL(&aChannel, KQoSDefaultBufSize);
+	request->iMsg->Init(EPfqosLeave);
+	request->iMsg->AddSelector((TUint8)aSelector.Protocol(), iUid.UidType(), EPfqosFlowspecPolicy, aSelector.IapId(), EPfqosApplicationPriority, TPtr(0,0));
+	request->iMsg->AddSrcAddress(aSelector.GetSrc(), aSelector.GetSrcMask(), (TUint16)aSelector.MaxPortSrc()); 
+	request->iMsg->AddDstAddress(aSelector.GetDst(), aSelector.GetDstMask(), (TUint16)aSelector.MaxPortDst()); 
+	request->iMsg->AddChannel(aChannel.ChannelId());
+	Send(request);
+	}
+
+
+//
+// Notify informs applications about events received from the kernel. 
+// A callback function is called, if application has registered for the event.
+// Selector is matched against flows to find out if an application ought to be notified.
+//
+void CQoSMan::Notify(TPfqosMessage& aMsg)
+	{
+	if (!aMsg.iBase.iMsg)
+		return;
+
+	switch (aMsg.iBase.iMsg->pfqos_msg_type)
+		{
+
+	case EPfqosEvent:
+		ExecEvent(aMsg);
+		return;
+
+	case EPfqosFlush:
+		// All policies have been deleted from the kernel. 
+		// Inform applications with POLICY_EVENT_QOS_FAILURE.
+		Flush();
+		break;
+
+	case EPfqosUpdate:
+	case EPfqosDelete:
+	case EPfqosAdd:
+	case EPfqosGet:
+	case EPfqosReject:
+	case EPfqosDump:
+	case EPfqosConfigure:
+	case EPfqosJoin:
+	case EPfqosLeave:
+	case EPfqosCreateChannel:
+	case EPfqosOpenExistingChannel:
+	case EPfqosDeleteChannel:
+	case EPfqosConfigChannel:
+	case EPfqosLoadFile:
+	case EPfqosUnloadFile:
+		ExecReply(aMsg);
+		break;
+	default:
+		break;
+		}
+	}
+
+// Flush deletes all flowinfo in CQoSMan. If aEvent > 0, inform applications.
+void CQoSMan::Flush()
+	{
+	while (!iStaticPolicies.IsEmpty())
+		{
+		CPolicy* policy = iStaticPolicies.First();
+		if (policy)
+			{
+			iStaticPolicies.Remove(*policy);
+			delete policy;
+			}
+		}
+	iStaticPolicies.Reset();
+	}
+
+
+CChannel* CQoSMan::Match(TPfqosMessage& aMsg)
+	{
+	if (!aMsg.iChannel.iExt)
+		return NULL;
+
+	TSglQueIter<CChannel> iter(iChannels);
+	CChannel* channel;
+	while ((channel = iter++) != NULL)
+		{
+		if (channel->Match(aMsg.iChannel.iExt->channel_id))
+			return channel;
+		}
+	return NULL;
+	}
+
+
+CChannel* CQoSMan::MatchChannelReply(TPfqosMessage& aMsg, TUint8 aMsgType)
+	{
+	if (aMsgType == EPfqosCreateChannel || aMsgType == EPfqosJoin || 
+	aMsgType == EPfqosLeave)
+	if (aMsg.iSrcAddr.iExt == NULL || aMsg.iDstAddr.iExt == NULL || aMsg.iSelector.iExt == NULL)
+		return NULL;
+
+	TSglQueIter<CChannel> iter(iChannels);
+	CChannel* channel;
+
+	while ((channel = iter++) != NULL)
+		{
+		if (channel->MatchReply(aMsg, aMsgType))
+			return channel;
+		}
+	return NULL;
+	}
+
+CPolicy* CQoSMan::MatchPolicyReply(TPfqosMessage& aMsg, TUint8 aMsgType)
+	{
+	TSglQueIter<CPolicy> iter(iStaticPolicies);
+	CPolicy* policy;
+
+	while ((policy = iter++) != NULL)
+		{
+		if (policy->MatchReply(aMsg, aMsgType))
+			return policy;
+		}
+	return NULL;
+	}
+
+//
+// POLICY_EVENT message has to contain <header, selector, srcaddr, dstaddr, policy_event,(flowspec)>
+// flowspec is mandatory for all others but POLICY_EVENT_QOS_FAILURE event.
+//
+void CQoSMan::ExecEvent(TPfqosMessage& aMsg)
+	{
+	if (aMsg.iEvent.iExt == NULL || aMsg.iFlowSpec.iExt == NULL)
+		return;
+
+	TUint event = aMsg.iEvent.iExt->event_type;
+	switch (event)
+		{
+	case KPfqosEventReceivers:
+	case KPfqosEventSenders:
+		break;
+
+	default:
+		if (aMsg.iChannel.iExt)
+			{
+			TSglQueIter<CChannel> iter(iChannels);
+			CChannel* channel;
+			while ((channel = iter++) != NULL)
+				{
+				if (channel->Match(aMsg.iChannel.iExt->channel_id))
+					channel->ProcessEvent(aMsg);
+				}
+			}
+		else
+			{
+			if (aMsg.iSrcAddr.iExt == NULL || aMsg.iDstAddr.iExt == NULL || aMsg.iSelector.iExt == NULL)
+				return;
+			TSglQueIter<CPolicy> iter(iStaticPolicies);
+			CPolicy* policy;
+			while ((policy = iter++) != NULL)
+				policy->ProcessEvent(aMsg);
+			}
+		break;
+		}
+	}
+
+
+void CQoSMan::ExecReply(TPfqosMessage& aMsg)
+	{
+	TUint8 type = aMsg.iBase.iMsg->pfqos_msg_type;
+	CChannel* request = MatchChannelReply(aMsg, type);
+	if (request)
+		request->ProcessReply(aMsg);
+	else
+		{
+		if (aMsg.iSrcAddr.iExt == NULL || aMsg.iDstAddr.iExt == NULL || aMsg.iSelector.iExt == NULL)
+			return;
+		CPolicy* policy = MatchPolicyReply(aMsg, type);
+		if (policy)
+			policy->ProcessReply(aMsg);
+		}
+	}
+
+void CQoSMan::RunL()
+	{
+	if (iStatus.Int() == KErrNone)
+		{
+		TPfqosMessage msg(iRecBuf);
+		__ASSERT_DEBUG(msg.iError == KErrNone, User::Panic(_L("CQoSMan*::RunL(): Msg corrupted"),msg.iError));
+		// Should log the error
+		if (msg.iError == KErrNone)
+			{
+			iNotifyPending = ETrue;
+
+			LOG(Log::Printf(_L("CQoSMan::RunL() - [%d] "),msg.iBase.iMsg->pfqos_msg_errno));
+
+			Notify(msg);
+			iNotifyPending = EFalse;
+			}
+		}
+
+	if (!iShutdown)
+		{
+		iRecBuf.Zero();
+		iSocket.Recv(iRecBuf, 0, iStatus);
+		SetActive();
+		}
+	else
+		delete this;
+	}
+
+void CQoSMan::DoCancel()
+	{
+	iSocket.CancelRecv();
+	}
+
+CPolicy* CQoSMan::OpenQoSPolicyL(const TQoSSelector& aSelector)
+	{
+	CPolicy* policy = CPolicy::NewL(this, aSelector);
+	iStaticPolicies.AddLast(*policy);
+	return policy;
+	}
+
+void CQoSMan::RemoveQoSPolicy(CPolicy* aPolicy)
+	{
+	TSglQueIter<CPolicy> iter(iStaticPolicies);
+	CPolicy* policy;
+	while ((policy = iter++) != NULL)
+		{
+		if (policy == aPolicy)
+			{
+			iStaticPolicies.Remove(*aPolicy);
+			return;
+			}
+		}
+	}
+
+CPolicy* CQoSMan::FindPolicy(const TQoSSelector& aSelector)
+	{
+	TSglQueIter<CPolicy> iter(iStaticPolicies);
+	CPolicy* policy;
+
+	while ((policy=iter++) != NULL)
+		{
+		if (policy->Match(aSelector))
+			return policy;
+		}
+	return NULL;
+	}
+
+void CQoSMan::ClearPendingRequest(CQoSRequestBase* aRequest)
+	{
+	iSender->ClearPendingRequest(aRequest);
+	}
+
+void CQoSMan::Send(CRequest* aRequest)
+	{
+	iSender->Send(aRequest);
+	}
+