--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/networkcontrol/qoslib/src/qos_policy.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,684 @@
+// 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 "qoslib.h"
+#include "qoslib_glob.h"
+#include "pfqos_stream.h"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <networking/qoslib_internal.h>
+#endif
+
+/**
+Default constructor.
+
+RQoSPolicy::Open() must always be called before any other
+methods in the RQoSPolicy can be called.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+*/
+EXPORT_C RQoSPolicy::RQoSPolicy() : iPolicy(NULL)
+ {
+ }
+
+/**
+Destructor.
+
+Closes any open policy.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+*/
+EXPORT_C RQoSPolicy::~RQoSPolicy()
+ {
+ if (iPolicy)
+ iPolicy->Close();
+ }
+
+/**
+This must always be called before any other function can be used.
+
+It specifies the selector for a QoS policy.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aSelector Selector for the QoS policy.
+@return KErrNone, if successful; otherwise, an error code if the QoS channel
+cannot be opened.
+*/
+EXPORT_C TInt RQoSPolicy::Open(const TQoSSelector& aSelector)
+ {
+ if (iPolicy)
+ return KErrAlreadyExists;
+ CQoSMan* manager = NULL;
+ TRAPD(err,
+ manager = CQoSMan::NewL();
+ // There is manager->Open() in above NewL.
+ // How and when is that cancelled, if leave happens below? --msa
+ iPolicy = manager->OpenQoSPolicyL(aSelector)
+ );
+ return err;
+ }
+
+/**
+Sets the QoS parameters for the QoS policy.
+
+A CQoSAddEvent event is received asynchronously to indicate the success or
+failure of the request.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aPolicy QoS parameters.
+@return KErrNone, if successful; otherwise, an error code.
+*/
+EXPORT_C TInt RQoSPolicy::SetQoS(CQoSParameters& aPolicy)
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ TRAPD(err, iPolicy->SetQoSL(aPolicy));
+ return err;
+ }
+
+/**
+Gets the QoS policy from QoS policy database.
+
+A CQoSGetEvent event is received asynchronously to indicate the success or
+failure of the request.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@return KErrNone, if successful; otherwise, an error code.
+*/
+EXPORT_C TInt RQoSPolicy::GetQoS()
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ TRAPD(err, iPolicy->GetQoSL());
+ return err;
+ }
+
+/**
+Deletes the QoS policy.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@return KErrNone, if successful; otherwise, an error code (e.g. if
+RQoSPolicy::Open() was not called).
+*/
+EXPORT_C TInt RQoSPolicy::Close()
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ TRAPD(err, iPolicy->DeleteL());
+ if (err == KErrNone)
+ {
+ iPolicy->Close();
+ iPolicy = NULL;
+ }
+ return err;
+ }
+
+/**
+Registers an event observer to catch QoS events.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aObserver Event observer.
+@param aMask An event mask. An application can specify a set of QoS events
+that it wants to receive. By default all events are notified to the
+application. See TQoSEvent enumerations.
+@return KErrNone, if successful; otherwise, an error code.
+*/
+EXPORT_C TInt RQoSPolicy::NotifyEvent(MQoSObserver& aObserver, TUint aMask)
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ return iPolicy->NotifyEvent(aObserver, aMask);
+ }
+
+/**
+Deregisters an event observer to catch QoS events.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aObserver Event observer.
+@return KErrNone if successful, otherwise an error code.
+*/
+EXPORT_C TInt RQoSPolicy::CancelNotifyEvent(MQoSObserver& aObserver)
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ return iPolicy->CancelNotifyEvent(aObserver);
+ }
+
+/**
+Loads a QoS policy file into the QoS policy database.
+
+A TQoSEvent event (EQoSEventLoadPolicyFile) is received asynchronously to
+indicate the success or failure of the request.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aName Name of the QoS policy file to be loaded.
+@return KErrNone, if successful; otherwise, an error code.
+*/
+EXPORT_C TInt RQoSPolicy::LoadPolicyFile(const TDesC& aName)
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ TRAPD(err, iPolicy->LoadFileL(aName));
+ return err;
+ }
+
+/**
+Unloads a QoS policy file from the QoS policy database.
+
+A TQoSEvent event (EQoSEventUnloadPolicyFile) is received asynchronously to
+indicate the success or failure of the request.
+
+@publishedPartner
+@released
+@capability NetworkControl Restrict QoS policy operations because they may
+affect several data flows.
+@param aName Name of the QoS policy file to be unloaded.
+@return KErrNone, if successful; otherwise, an error code.
+*/
+EXPORT_C TInt RQoSPolicy::UnloadPolicyFile(const TDesC& aName)
+ {
+ if (!iPolicy)
+ return KErrNotReady;
+ TRAPD(err, iPolicy->UnloadFileL(aName));
+ return err;
+ }
+
+
+//
+CQoSRequestBase::~CQoSRequestBase()
+ {
+ iManager->ClearPendingRequest(this);
+ iManager->Close();
+ }
+
+void CQoSRequestBase::ParseExtensions(TPfqosMessage& aMsg, CQoSParameters& aPolicy)
+ {
+ aMsg.SetQoSParameters(aPolicy.iQoS);
+ TSglQueIter<CPfqosPolicyData> iter(aMsg.iExtensions);
+ CPfqosPolicyData *data;
+
+ while ((data = iter++) != NULL)
+ {
+ TInt extensionType;
+ TInt ret = GetExtensionType(data->Data(), extensionType);
+ if (ret == KErrNone)
+ {
+ CExtensionBase *ext = aPolicy.FindExtension(extensionType);
+ if (ext)
+ ext->ParseMessage(data->Data());
+ }
+ }
+ }
+
+TInt CQoSRequestBase::GetExtensionType(const TDesC8& aData, TInt& aType)
+ {
+ const TUint8 *p = aData.Ptr();
+ TInt length = aData.Length();
+ //lint -e{826} thinks this cast is suspicious -- is not!
+ struct pfqos_configure *ext = (struct pfqos_configure *) p;
+
+ if (length < (TInt)sizeof(pfqos_configure))
+ return KErrGeneral; // EMSGSIZE (impossible message size)
+
+ if (ext->pfqos_configure_len * 8 != length)
+ return KErrGeneral; // EMSGSIZE (incorrect message length)
+
+ if (ext->pfqos_ext_type != EPfqosExtExtension)
+ return KErrGeneral;
+
+ p += sizeof(struct pfqos_configure);
+ //lint -e{826} thinks this cast is suspicious -- is not!
+ pfqos_extension *extensionType = (pfqos_extension *) p;
+ aType = extensionType->pfqos_extension_type;
+ return KErrNone;
+ }
+
+TInt CQoSRequestBase::NotifyEvent(MQoSObserver& aObserver, TUint aMask)
+ {
+ if (aMask & ~KQoSEventAll)
+ return KErrNotSupported;
+ iEventMask = aMask;
+ iObserver = &aObserver;
+ return KErrNone;
+ }
+
+TInt CQoSRequestBase::CancelNotifyEvent(MQoSObserver& aObserver)
+ {
+ if (iObserver != &aObserver)
+ return KErrNotFound;
+ iObserver = NULL;
+ return KErrNone;
+ }
+
+
+//
+CPolicy* CPolicy::NewL(CQoSMan* aManager, const TQoSSelector& aSelector)
+ {
+ CPolicy* policy = new (ELeave) CPolicy(aManager, aSelector);
+ return policy;
+ }
+
+CPolicy::CPolicy(CQoSMan* aManager, const TQoSSelector& aSelector)
+ {
+ iManager = aManager;
+ iSelector = aSelector;
+ iPending = ENone;
+ iPolicyCreated = EFalse;
+ }
+
+CPolicy::~CPolicy()
+ {
+ iManager->RemoveQoSPolicy(this);
+ }
+
+void CPolicy::Close()
+ {
+ delete this;
+ }
+
+TBool CPolicy::Match(const TQoSSelector& aSelector)
+ {
+ return (iSelector == aSelector);
+ }
+
+void CPolicy::SetQoSL(CQoSParameters& aPolicy)
+ {
+ if (iPending != ENone)
+ User::Leave(KErrInUse);
+ iPolicy.CopyL(aPolicy);
+ CRequest* request = CRequest::NewL(this, KQoSDefaultBufSize);
+ if (iPolicyCreated)
+ {
+ request->iMsg->Init(EPfqosUpdate);
+ iPending = EPendingUpdate;
+ }
+ else
+ {
+ request->iMsg->Init(EPfqosAdd);
+ iPending = EPendingAdd;
+ }
+ request->iMsg->AddSelector((TUint8)iSelector.Protocol(),
+ iManager->Uid().UidType(),
+ EPfqosFlowspecPolicy,
+ iSelector.IapId(),
+ EPfqosApplicationPriority,
+ TPtr(0,0));
+ request->iMsg->AddSrcAddress(iSelector.GetSrc(),
+ iSelector.GetSrcMask(),
+ (TUint16)iSelector.MaxPortSrc());
+ request->iMsg->AddDstAddress(iSelector.GetDst(),
+ iSelector.GetDstMask(),
+ (TUint16)iSelector.MaxPortDst());
+ request->iMsg->AddQoSParameters(iPolicy.iQoS);
+
+ TQoSExtensionQueueIter iter(iPolicy.Extensions());
+ CExtensionBase *extension;
+ while ((extension=iter++) != NULL)
+ request->iMsg->AddExtensionPolicy(extension->Data());
+ iManager->Send(request);
+
+ }
+
+void CPolicy::GetQoSL()
+ {
+
+ if (iPending != ENone)
+ User::Leave(KErrInUse);
+ CRequest* request = CRequest::NewL(this, KQoSDefaultBufSize);
+ request->iMsg->Init(EPfqosGet);
+ iPending = EPendingGet;
+ request->iMsg->AddSelector((TUint8)iSelector.Protocol(),
+ iManager->Uid().UidType(),
+ EPfqosFlowspecPolicy,
+ iSelector.IapId(),
+ EPfqosApplicationPriority,
+ TPtr(0,0));
+ request->iMsg->AddSrcAddress(iSelector.GetSrc(),
+ iSelector.GetSrcMask(),
+ (TUint16)iSelector.MaxPortSrc());
+ request->iMsg->AddDstAddress(iSelector.GetDst(),
+ iSelector.GetDstMask(),
+ (TUint16)iSelector.MaxPortDst());
+
+ TQoSExtensionQueueIter iter(iPolicy.Extensions());
+ CExtensionBase *extension;
+ while ((extension=iter++) != NULL)
+ request->iMsg->AddExtensionPolicy(extension->Data());
+ iManager->Send(request);
+
+ }
+
+void CPolicy::DeleteL()
+ {
+ CRequest* request = CRequest::NewL(this,KQoSDefaultBufSize);
+ request->iMsg->Init(EPfqosDelete);
+ iPending = EPendingDelete;
+ request->iMsg->AddSelector((TUint8)iSelector.Protocol(),
+ iManager->Uid().UidType(),
+ EPfqosFlowspecPolicy,
+ iSelector.IapId(),
+ EPfqosApplicationPriority,
+ TPtr(0,0));
+ request->iMsg->AddSrcAddress(iSelector.GetSrc(),
+ iSelector.GetSrcMask(),
+ (TUint16)iSelector.MaxPortSrc());
+ request->iMsg->AddDstAddress(iSelector.GetDst(),
+ iSelector.GetDstMask(),
+ (TUint16)iSelector.MaxPortDst());
+
+ TQoSExtensionQueueIter iter(iPolicy.Extensions());
+ CExtensionBase *item;
+ while ((item = iter++) != NULL)
+ request->iMsg->AddExtensionHeader((TUint16)item->Type());
+
+ iManager->Send(request);
+ }
+
+void CPolicy::ProcessReply(TPfqosMessage& aMsg)
+ {
+ TInt aErrorCode = aMsg.iBase.iMsg->pfqos_msg_errno;
+
+
+
+ TPendingStatus status = iPending;
+
+ if (aErrorCode)
+ {
+ if (status == EPendingLoadFile || status == EPendingUnloadFile)
+ {
+ iPending = ENone;
+#if _UNICODE
+ TPtrC8 tmp((TUint8*)aMsg.iConfigFile.iExt->filename);
+ TFileName filename;
+ filename.Copy(tmp);
+#else
+ TPtrC8 filename((TUint8*)aMsg.iConfigFile.iExt->filename);
+#endif
+ TQoSEvent event_type;
+ if (status == EPendingLoadFile)
+ event_type = EQoSEventLoadPolicyFile;
+ else
+ event_type = EQoSEventUnloadPolicyFile;
+ CQoSLoadEvent event(event_type, aErrorCode, filename);
+ if (iObserver && iEventMask & EQoSEventLoadPolicyFile)
+ iObserver->Event(event);
+ }
+ else
+ {
+ NotifyError(aErrorCode);
+ }
+ }
+ else
+ {
+ iPending = ENone;
+
+ switch (status)
+ {
+ case EPendingAdd:
+ {
+ CQoSParameters policy;
+ ParseExtensions(aMsg, policy);
+ CQoSAddEvent event(&policy, aErrorCode);
+ if (iObserver && iEventMask & EQoSEventAddPolicy)
+ iObserver->Event(event);
+ iPolicyCreated = ETrue;
+ }
+ break;
+
+ case EPendingUpdate:
+ {
+ CQoSParameters policy;
+ ParseExtensions(aMsg, policy);
+ CQoSAddEvent event(&policy, aErrorCode);
+ if (iObserver && iEventMask & EQoSEventAddPolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ case EPendingDelete:
+ {
+ iPending = ENone;
+ CQoSDeleteEvent event(aErrorCode);
+ if (iObserver && iEventMask & EQoSEventDeletePolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ case EPendingGet:
+ {
+ CQoSParameters policy;
+
+
+ ParseExtensions(aMsg, policy);
+
+
+ CQoSGetEvent event(&policy, aErrorCode);
+
+
+ if (iObserver && iEventMask & EQoSEventGetPolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ case EPendingLoadFile:
+ case EPendingUnloadFile:
+ {
+#if _UNICODE
+ TPtrC8 tmp((TUint8*)aMsg.iConfigFile.iExt->filename);
+ TFileName filename;
+ filename.Copy(tmp);
+#else
+ TPtrC8 filename((TUint8*)aMsg.iConfigFile.iExt->filename);
+#endif
+ TQoSEvent event_type;
+ if (status == EPendingLoadFile)
+ event_type = EQoSEventLoadPolicyFile;
+ else
+ event_type = EQoSEventUnloadPolicyFile;
+ CQoSLoadEvent event(event_type, KErrNone, filename);
+ if (iObserver && iEventMask & EQoSEventLoadPolicyFile)
+ iObserver->Event(event);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+TBool CPolicy::MatchReply(const TPfqosMessage& aMsg, TUint8 aMsgType)
+ {
+ if (((iPending == EPendingAdd && aMsgType == EPfqosAdd) ||
+ (iPending == EPendingUpdate && aMsgType == EPfqosUpdate) ||
+ (iPending == EPendingGet && aMsgType == EPfqosGet) ||
+ (iPending == EPendingDelete && aMsgType == EPfqosDelete) ||
+ (iPending == EPendingLoadFile && aMsgType == EPfqosLoadFile) ||
+ (iPending == EPendingUnloadFile && aMsgType == EPfqosUnloadFile)) &&
+ (iSelector.GetDst().Match(*aMsg.iDstAddr.iAddr)) &&
+ (iSelector.GetSrc().Match(*aMsg.iSrcAddr.iAddr)) &&
+ (iSelector.Protocol() == aMsg.iSelector.iExt->protocol) &&
+ (iSelector.GetDst().Port() == aMsg.iDstAddr.iAddr->Port()) &&
+ (iSelector.GetSrc().Port() == aMsg.iSrcAddr.iAddr->Port()) &&
+ (iSelector.MaxPortDst() == aMsg.iDstAddr.iExt->pfqos_port_max) &&
+ (iSelector.MaxPortSrc() == aMsg.iSrcAddr.iExt->pfqos_port_max))
+ return ETrue;
+
+ return EFalse;
+ }
+
+void CPolicy::ProcessEvent(TPfqosMessage& aMsg)
+ {
+ if ((iSelector.GetDst().Match(*aMsg.iDstAddr.iAddr)) &&
+ (iSelector.GetSrc().Match(*aMsg.iSrcAddr.iAddr)) &&
+ (iSelector.Protocol() == aMsg.iSelector.iExt->protocol) &&
+ (iSelector.GetDst().Port() == aMsg.iDstAddr.iAddr->Port()) &&
+ (iSelector.GetSrc().Port() == aMsg.iSrcAddr.iAddr->Port()) &&
+ (iSelector.MaxPortDst() == aMsg.iDstAddr.iExt->pfqos_port_max) &&
+ (iSelector.MaxPortSrc() == aMsg.iSrcAddr.iExt->pfqos_port_max))
+ {
+ iCapabilities = aMsg.iEvent.iExt->event_value;
+
+ switch (aMsg.iEvent.iExt->event_type)
+ {
+ case KPfqosEventFailure:
+ if (iObserver && iEventMask & EQoSEventFailure)
+ {
+ ParseExtensions(aMsg, iPolicy);
+ CQoSFailureEvent event(iPolicy, aMsg.iBase.iMsg->pfqos_msg_errno);
+ iObserver->Event(event);
+ }
+ break;
+
+ case KPfqosEventConfirm:
+ if (iObserver && iEventMask & EQoSEventConfirm)
+ {
+ ParseExtensions(aMsg, iPolicy);
+ CQoSConfirmEvent event(iPolicy);
+ iObserver->Event(event);
+ }
+ break;
+
+ case KPfqosEventAdapt:
+ if (iObserver && iEventMask & EQoSEventAdapt)
+ {
+ ParseExtensions(aMsg, iPolicy);
+ CQoSAdaptEvent event(iPolicy, aMsg.iBase.iMsg->pfqos_msg_errno);
+ iObserver->Event(event);
+ }
+ break;
+
+ default:
+ return;
+ }
+ }
+ }
+
+void CPolicy::NotifyError(TInt aReason)
+ {
+ TPendingStatus status = iPending;
+ iPending = ENone;
+
+ if (aReason)
+ {
+ switch (status)
+ {
+ case EPendingAdd:
+ case EPendingUpdate:
+ {
+ CQoSAddEvent event(&iPolicy, aReason);
+ if (iObserver && iEventMask & EQoSEventAddPolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ case EPendingGet:
+ {
+ CQoSGetEvent event(NULL, aReason);
+ if (iObserver && iEventMask & EQoSEventGetPolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ case EPendingDelete:
+ {
+ CQoSDeleteEvent event(aReason);
+ if (iObserver && iEventMask & EQoSEventDeletePolicy)
+ iObserver->Event(event);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+
+void CPolicy::LoadFileL(const TDesC& aName)
+ {
+ if (iPending != ENone)
+ User::Leave(KErrInUse);
+ if (aName.Length() > KMaxFileName)
+ User::Leave(KErrArgument);
+ CRequest* request = CRequest::NewL(this, KQoSDefaultBufSize);
+ request->iMsg->Init(EPfqosLoadFile);
+ iPending = EPendingLoadFile;
+ request->iMsg->AddSelector((TUint8)iSelector.Protocol(),
+ iManager->Uid().UidType(),
+ EPfqosFlowspecPolicy,
+ iSelector.IapId(),
+ EPfqosApplicationPriority,
+ TPtr(0,0));
+ request->iMsg->AddSrcAddress(iSelector.GetSrc(),
+ iSelector.GetSrcMask(),
+ (TUint16)iSelector.MaxPortSrc());
+ request->iMsg->AddDstAddress(iSelector.GetDst(),
+ iSelector.GetDstMask(),
+ (TUint16)iSelector.MaxPortDst());
+ request->iMsg->AddConfigFile(aName);
+ iManager->Send(request);
+ }
+
+void CPolicy::UnloadFileL(const TDesC& aName)
+ {
+ if (iPending != ENone)
+ User::Leave(KErrInUse);
+ if (aName.Length() > KMaxFileName)
+ User::Leave(KErrArgument);
+ CRequest* request = CRequest::NewL(this, KQoSDefaultBufSize);
+ request->iMsg->Init(EPfqosUnloadFile);
+ iPending = EPendingUnloadFile;
+ request->iMsg->AddSelector((TUint8)iSelector.Protocol(),
+ iManager->Uid().UidType(),
+ EPfqosFlowspecPolicy,
+ iSelector.IapId(),
+ EPfqosApplicationPriority,
+ TPtr(0,0));
+ request->iMsg->AddSrcAddress(iSelector.GetSrc(),
+ iSelector.GetSrcMask(),
+ (TUint16)iSelector.MaxPortSrc());
+ request->iMsg->AddDstAddress(iSelector.GetDst(),
+ iSelector.GetDstMask(),
+ (TUint16)iSelector.MaxPortDst());
+ request->iMsg->AddConfigFile(aName);
+ iManager->Send(request);
+ }