diff -r 000000000000 -r af10295192d8 networkcontrol/qoslib/src/qoslib.cpp --- /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 +#include + + +#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 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 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 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 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 iter(iStaticPolicies); + CPolicy* policy; + + while ((policy = iter++) != NULL) + { + if (policy->MatchReply(aMsg, aMsgType)) + return policy; + } + return NULL; + } + +// +// POLICY_EVENT message has to contain +// 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 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 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 iter(iStaticPolicies); + CPolicy* policy; + while ((policy = iter++) != NULL) + { + if (policy == aPolicy) + { + iStaticPolicies.Remove(*aPolicy); + return; + } + } + } + +CPolicy* CQoSMan::FindPolicy(const TQoSSelector& aSelector) + { + TSglQueIter 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); + } +