Still not completed the review. Check comments inline

On 12/08/2016 10:22 AM, Lennart Lund wrote:
>   osaf/services/saf/smfsv/README                    |   34 +-
>   osaf/services/saf/smfsv/smfd/Makefile.am          |   13 +-
>   osaf/services/saf/smfsv/smfd/SmfCampaign.cc       |    5 +-
>   osaf/services/saf/smfsv/smfd/SmfCampaignInit.cc   |    6 -
>   osaf/services/saf/smfsv/smfd/SmfCampaignThread.cc |   13 +-
>   osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.cc  |  726 
> ++++++++++++++++++++++
>   osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.hh  |  113 +++
>   osaf/services/saf/smfsv/smfd/SmfImmOperation.cc   |   15 +-
>   osaf/services/saf/smfsv/smfd/SmfLongDnApplier.cc  |  441 +++++++++++++
>   osaf/services/saf/smfsv/smfd/SmfLongDnApplier.hh  |   84 ++
>   osaf/services/saf/smfsv/smfd/SmfUtils.cc          |   83 +--
>   osaf/services/saf/smfsv/smfd/SmfUtils.hh          |    7 -
>   osaf/services/saf/smfsv/smfd/smfd.h               |    2 +-
>   osaf/services/saf/smfsv/smfd/smfd_amf.c           |   20 +-
>   osaf/services/saf/smfsv/smfd/smfd_campaign_oi.cc  |   18 -
>   osaf/services/saf/smfsv/smfd/smfd_cb.h            |    3 +-
>   osaf/services/saf/smfsv/smfd/smfd_evt.h           |    7 +
>   osaf/services/saf/smfsv/smfd/smfd_long_dn.hh      |   58 +
>   osaf/services/saf/smfsv/smfd/smfd_main.c          |   13 +-
>   19 files changed, 1530 insertions(+), 131 deletions(-)
>
>
> Keep track of long DN setting using an IMM applier instead of reading
> the long DN setting in many places
>
> diff --git a/osaf/services/saf/smfsv/README b/osaf/services/saf/smfsv/README
> --- a/osaf/services/saf/smfsv/README
> +++ b/osaf/services/saf/smfsv/README
> @@ -251,6 +251,38 @@ directory "samples/smfsv"
>   CONTRIBUTORS/MAINTAINERS
>   ========================
>   Bertil Engelholm <[email protected]>
> -Ingvar Bergstr?m <[email protected]>
> +Ingvar Bergstr???m <[email protected]>
>   
>   The SMF service was originally cloned from the immsv and log services.
> +
> +MAINTAINER NOTES
> +================
> +
> +Applier for monitoring long Dn allowed setting
> +----------------------------------------------
> +SMF is dependent on knowing the longDnsAllowed setting in the IMM 
> configuration
> +object. This setting may change at any time and to monitor changes an IMM
> +applier is used.
> +
> +SmfImmApplierHdl:
> +Contains a wrapper for the IMM APIs and callback functions used with an 
> applier.
> +A C++ class is used to create an interface for handling an applier e.g. 
> create,
> +start (initialize and set), stop (clear), get value etc.
> +See SmfImmApplierHdl.hh for more information.
> +
> +SmfLongDnApplier:
> +Runs an applier in a thread using the SmfImmApplierHdl.
> +A C++ class is used to create an interface for running an applier.
> +See SmfLongDnApplier.hh for more information.
> +
> +Installation in SMF:
> +
> +In smfd_main.cc the applier is constructed and created. A pointer to the 
> applier
> +object is stored in a global variable. The applier is started and stopped in 
> the
> +same place as the SMF object implementer when SMF gets a CSI set callback, 
> see
> +smfd_amf.cc. In previous versions of SMF a global variable in the smfd_cb 
> struct
> +, maxDnLength, was used to store the maximum allowed length of a Dn 
> depending on
> +the IMM config long Dn setting. This length information is used in many 
> places
> +in the SMF code. The global variable is replaced by a function call to
> +GetSmfMaxDnLength() which returns the same length information. This function
> +can be found in smfd_long_dn.hh
> diff --git a/osaf/services/saf/smfsv/smfd/Makefile.am 
> b/osaf/services/saf/smfsv/smfd/Makefile.am
> --- a/osaf/services/saf/smfsv/smfd/Makefile.am
> +++ b/osaf/services/saf/smfsv/smfd/Makefile.am
> @@ -51,7 +51,10 @@ noinst_HEADERS = \
>       SmfCallback.hh \
>       SmfCbkUtil.hh \
>       SmfExecControl.h \
> -     SmfExecControlHdl.h
> +     SmfExecControlHdl.h \
> +     SmfLongDnApplier.hh \
> +     SmfImmApplierHdl.hh \
> +     smfd_long_dn.hh
>   
>   osafsmfd_CXXFLAGS = $(AM_CXXFLAGS) @XML2_CFLAGS@
>   
> @@ -63,9 +66,9 @@ osafsmfd_CPPFLAGS = \
>       -I$(top_srcdir)/osaf/tools/saflog/include
>   
>   osafsmfd_SOURCES = \
> -     smfd_amf.c \
> +     smfd_amf.cc \
>       smfd_evt.c \
> -     smfd_main.c \
> +     smfd_main.cc \
>       smfd_smfnd.c \
>       smfd_mds.c \
>       SmfCampaignThread.cc \
> @@ -91,7 +94,9 @@ osafsmfd_SOURCES = \
>       SmfCallback.cc \
>       SmfCbkUtil.cc \
>       SmfExecControl.cc \
> -     SmfExecControlHdl.cc
> +     SmfExecControlHdl.cc \
> +     SmfLongDnApplier.cc \
> +     SmfImmApplierHdl.cc
>   
>   osafsmfd_LDFLAGS = \
>       $(AM_LDFLAGS) \
> diff --git a/osaf/services/saf/smfsv/smfd/SmfCampaign.cc 
> b/osaf/services/saf/smfsv/smfd/SmfCampaign.cc
> --- a/osaf/services/saf/smfsv/smfd/SmfCampaign.cc
> +++ b/osaf/services/saf/smfsv/smfd/SmfCampaign.cc
> @@ -34,6 +34,7 @@
>   #include "SmfUpgradeAction.hh"
>   #include "SmfUtils.hh"
>   #include "SmfExecControl.h"
> +#include "smfd_long_dn.hh"
>   
>   #include "saAis.h"
>   #include <saSmf.h>
> @@ -713,10 +714,10 @@ SmfCampaign::startProcedureThreads()
>                   while (iter != procedures.end()) {
>                           //Set the DN of the procedure
>                           std::string dn = (*iter)->getProcName() + "," + 
> SmfCampaignThread::instance()->campaign()->getDn();
> -                        if (dn.length() > 
> static_cast<size_t>(smfd_cb->maxDnLength - OSAF_STEP_ACT_LENGTH)) {
> +                        if (dn.length() > 
> static_cast<size_t>(GetSmfMaxDnLength() - OSAF_STEP_ACT_LENGTH)) {
>                                   std::string error = "Procedure dn too long 
> " + dn;
>                                   LOG_ER("Procedure dn too long (max %zu) %s",
> -                                       
> static_cast<size_t>(smfd_cb->maxDnLength - OSAF_STEP_ACT_LENGTH),
> +                                       
> static_cast<size_t>(GetSmfMaxDnLength() - OSAF_STEP_ACT_LENGTH),
>                                          dn.c_str());
>                                   
> SmfCampaignThread::instance()->campaign()->setError(error);
>                                   delete p_uc; // To terminate and remove any 
> previously started procedure threads
> diff --git a/osaf/services/saf/smfsv/smfd/SmfCampaignInit.cc 
> b/osaf/services/saf/smfsv/smfd/SmfCampaignInit.cc
> --- a/osaf/services/saf/smfsv/smfd/SmfCampaignInit.cc
> +++ b/osaf/services/saf/smfsv/smfd/SmfCampaignInit.cc
> @@ -228,12 +228,6 @@ SmfCampaignInit::execute()
>       std::list < SmfUpgradeAction * >::iterator upActiter;
>       upActiter = m_campInitAction.begin();
>       while (upActiter != m_campInitAction.end()) {
> -             TRACE("3. %s: 
> read_IMM_long_DN_config_and_set_control_block()",__FUNCTION__);
> -             if 
> (!immUtil.read_IMM_long_DN_config_and_set_control_block(smfd_cb)) {
> -                     LOG_ER("SmfCampaignInit: reading long DN config from 
> IMM FAILED");
> -                     TRACE_LEAVE();
> -                     return false;
> -             }
>               SaAisErrorT rc = 
> (*upActiter)->execute(SmfCampaignThread::instance()->getImmHandle(),
>                               &initRollbackDn);
>               if (rc != SA_AIS_OK) {
> diff --git a/osaf/services/saf/smfsv/smfd/SmfCampaignThread.cc 
> b/osaf/services/saf/smfsv/smfd/SmfCampaignThread.cc
> --- a/osaf/services/saf/smfsv/smfd/SmfCampaignThread.cc
> +++ b/osaf/services/saf/smfsv/smfd/SmfCampaignThread.cc
> @@ -37,6 +37,7 @@
>   #include "SmfUpgradeCampaign.hh"
>   #include "SmfUpgradeProcedure.hh"
>   #include "SmfUtils.hh"
> +#include "smfd_long_dn.hh"
>   
>   SmfCampaignThread *SmfCampaignThread::s_instance = NULL;
>   
> @@ -492,10 +493,10 @@ int SmfCampaignThread::sendStateNotifica
>   
>       /* Notifying object */
>       size_t length = sizeof(SMF_NOTIFYING_OBJECT);
> -     if (length > static_cast<size_t>(smfd_cb->maxDnLength)) {
> +     if (length > static_cast<size_t>(GetSmfMaxDnLength())) {
>               TRACE("notifyingObject length was %zu, truncated to %zu",
> -                length, static_cast<size_t>(smfd_cb->maxDnLength));
> -             length = smfd_cb->maxDnLength;
> +                length, static_cast<size_t>(GetSmfMaxDnLength()));
> +             length = GetSmfMaxDnLength();
>       }
>           char* value = (char*) malloc(length + 1);
>       if (value == NULL) {
> @@ -509,10 +510,10 @@ int SmfCampaignThread::sendStateNotifica
>   
>       /* Notification object */
>       length = dn.length();
> -     if (length > static_cast<size_t>(smfd_cb->maxDnLength)) {
> +     if (length > static_cast<size_t>(GetSmfMaxDnLength())) {
>               TRACE("notificationHeader length was %zu, truncated to %zu",
> -                length, static_cast<size_t>(smfd_cb->maxDnLength));
> -             length = smfd_cb->maxDnLength;
> +                length, static_cast<size_t>(GetSmfMaxDnLength()));
> +             length = GetSmfMaxDnLength();
>       }
>           value = (char*) malloc(length + 1);
>       if (value == NULL) {
> diff --git a/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.cc 
> b/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.cc
> @@ -0,0 +1,726 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "SmfImmApplierHdl.hh"
> +#include <string>
> +#include <atomic>
> +// TODO(Lennart): Replace with base::mutex when available
> +#include <mutex>
> +
> +#include "smfd.h"
> +#include "SmfUtils.hh"
> +
> +#include "saf_error.h"
> +#include "logtrace.h"
> +#include "osaf_utility.h"
> +#include "saImmOi.h"
> +#include "immutil.h"
> +#include "base/time.h"
> +#include "osaf_poll.h"
> +#include "osaf_extended_name.h"
> +
> +/**
> + * Locals not needed outside of this file
> + */
> +// Must be delclared here since it is used both in C callback functions and 
> in
> +// SmfImmApplierHdl class
> +static std::string object_name_ = "";
> +static std::string attribute_name_ = "";
> +static std::string attribute_value_ = "";
> +static bool attribute_value_is_valid_ = false;
> +
> +// Used to abort ongoing handler activity in case of Stop command
> +// For example ongoing TRY_AGAIN handling in IMM APIs must be terminated
> +static std::atomic<bool> is_cancel {false};
> +
> +// Mutex protecting attribute value
> +// TODO: Replace std::mutex with base::mutex when base::mutex is available
> +std::mutex attribute_value_lock;
> +
> +/**
> + * Local functions containing IMM operations needed here
> + **/
> +
> +/**
> + * Update the monitored value protected
> + * Note: Is not a method in SmfImmApplierHdl class since used by both
> + * C functions and in SmfImmApplierHdl class
> + */
> +static void SetAttributeValue(const std::string& value) {
> +  attribute_value_lock.lock();
> +  attribute_value_ = value;
> +  attribute_value_lock.unlock();
> +}
> +
> +/**
> + * Read the value of the object and attribute
> + * Note1: This function uses an SMF specific IMM wrapper
> + * Note2: This may be replaced with a generic IMM wrapper when one has
> + * been implemented.
> + * Note3: This function can only read one attribute of type SaUint32T
> + *
> + */
> +static std::string GetAttributeValueFromImm(const std::string& i_object_name,
> +                                        const std::string& i_attribute_name) 
> {
> +  SaImmAttrValuesT_2 **attributes;
> +  SmfImmUtils ImmCfg;
> +
> +  TRACE_ENTER();
> +  if (i_object_name == "" || i_attribute_name == "") {
> +    TRACE_LEAVE2("No object or attribute");
> +    return "";
> +  }
> +
> +  if (ImmCfg.getObject(i_object_name, &attributes) == false) {
> +    LOG_WA("%s: Could not read IMM config object from IMM %s",
> +           __FUNCTION__, IMM_CONFIG_OBJECT_DN);
> +  }
> +
> +  const SaUint32T *attribute_value = immutil_getUint32Attr(
> +                            (const SaImmAttrValuesT_2 **) attributes,
> +                            i_attribute_name.c_str(), 0);
> +
> +  std::string long_dn_setting_as_string = "";
> +  if (attribute_value != nullptr) {
> +    long_dn_setting_as_string = std::to_string(*attribute_value);
> +  } else {
> +    LOG_NO("%s: Fail longDnsAllowed has no value", __FUNCTION__);
> +  }
> +
> +  TRACE_LEAVE();
> +  return long_dn_setting_as_string;
> +}
> +
> +/**
> + * IMM API wrapper functions used instead of immutil.c
> + * All return false if Fail and log errors
> + * Note: To initialize IMM OI may take up to 60 seconds in a TRY AGAIN loop.
> + *       In this loop the is_cancel flag is checked and if true the TRY AGAIN
> + *       loop is canceled meaning that the applier is still not initialized
> + *
> + * TODO Replace with generic functions when implemented
> + */
> +
> +static bool InitializeImmOi(SaImmOiHandleT *o_immOiHandle,
> +                         const SaImmOiCallbacksT_2 *i_immOiCallbacks,
> +                         const SaVersionT *i_version) {
> +  // It may take up to one minute to initialize if IMM is synchronizing
> +  base::Timer adminOpTimer(60000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +
> +  SaVersionT version = *i_version;
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiInitialize_2(o_immOiHandle, i_immOiCallbacks, &version);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +        base::Sleep(base::kFiveHundredMilliseconds);
[rafael] too large indentation
> +      if (is_cancel) {
> +        is_cancel = false;
> +        rc = false;
> +        break;
> +      } else {
> +        continue;
[rafael] unnecessary continue.

[rafael] The try again code is repeated for each API call. Consider the 
decorator pattern where the try again logic is decorated onto the API calls.
> +      }
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiInitialize_2() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiInitialize_2() timeout Fail '%s'", __FUNCTION__,
> +           saf_error(ais_rc));
> +  }
> +
> +  return rc;
> +}
> +
> +static bool FinalizeImmOi(SaImmOiHandleT i_immOiHandle) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +
> +  if (i_immOiHandle != 0) {
> +    // Only if there is anything to finalize
> +    while (adminOpTimer.is_timeout() == false) {
> +      ais_rc = saImmOiFinalize(i_immOiHandle);
> +      if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +        base::Sleep(base::kFiveHundredMilliseconds);
> +        continue;
> +      } else if (ais_rc != SA_AIS_OK) {
> +        LOG_WA("%s: saImmOiFinalize() Fail '%s'", __FUNCTION__,
> +               saf_error(ais_rc));
> +        rc = false;
> +        break;
> +      } else {
> +        // Done
> +        break;
> +      }
> +    }
> +    if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiFinalize() timeout Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +    }
> +  }
> +
> +  return rc;
> +}
> +
> +static bool GetImmOiSelectionObject(SaImmOiHandleT i_immOiHandle,
> +                                    SaSelectionObjectT *selectionObject) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +  TRACE_ENTER();
> +
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiSelectionObjectGet(i_immOiHandle, selectionObject);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiSelectionObjectGet() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiSelectionObjectGet() timeout Fail '%s'",
> +        __FUNCTION__, saf_error(ais_rc));
[rafael] tabs and spaces
> +  }
> +
> +  TRACE_LEAVE();
> +  return rc;
> +}
> +
> +static bool ImmOiSet(SaImmOiHandleT i_immOiHandle,
> +                     const std::string& i_implementerName) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +  SaImmOiImplementerNameT implementerName =
> +      const_cast<SaImmOiImplementerNameT>(i_implementerName.c_str());
> +  TRACE_ENTER();
> +
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiImplementerSet(i_immOiHandle, implementerName);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiImplementerSet() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiImplementerSet() timeout Fail '%s'",
> +           __FUNCTION__, saf_error(ais_rc));
> +  }
> +
> +  TRACE_LEAVE();
> +  return rc;
> +}
> +
> +static bool ImmOiClear(SaImmOiHandleT i_immOiHandle) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiImplementerClear(i_immOiHandle);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiImplementerClear() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiImplementerClear() timeout Fail '%s'", __FUNCTION__,
> +           saf_error(ais_rc));
> +  }
> +
> +  return rc;
> +}
> +
> +/**
> + * Become applier for the given object. This starts the applier
> + */
> +static bool SetImmOiForObject(SaImmOiHandleT i_immOiHandle,
> +                              const std::string& i_objectName,
> +                              SaImmScopeT i_scope) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +  SaNameT object_name;
> +  osaf_extended_name_lend(i_objectName.c_str(), &object_name);
> +
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiObjectImplementerSet(i_immOiHandle, &object_name, 
> i_scope);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiObjectImplementerSet() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiObjectImplementerSet() timeout Fail '%s'", 
> __FUNCTION__,
> +           saf_error(ais_rc));
> +  }
> +
> +  return rc;
> +}
> +
> +/**
> + * Release the applier for the given object. This stops the applier
> + */
> +static bool ReleaseImmOiForObject(SaImmOiHandleT i_immOiHandle,
> +                              const std::string& i_objectName,
> +                              SaImmScopeT i_scope) {
> +  base::Timer adminOpTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  bool rc = true;
> +  SaNameT object_name;
> +  osaf_extended_name_lend(i_objectName.c_str(), &object_name);
> +
> +  while (adminOpTimer.is_timeout() == false) {
> +    ais_rc = saImmOiObjectImplementerRelease(i_immOiHandle, &object_name,
> +                                             i_scope);
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiObjectImplementerRelease() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      rc = false;
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (adminOpTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiObjectImplementerRelease() timeout Fail '%s'",
> +           __FUNCTION__, saf_error(ais_rc));
> +  }
> +
> +  return rc;
> +}
> +
> +static SaAisErrorT DispatchOiCallback(SaImmOiHandleT i_immOiHandle,
> +                                      SaDispatchFlagsT i_dispatchFlags) {
> +  base::Timer dispatchTimer(20000);
> +  SaAisErrorT ais_rc = SA_AIS_OK;
> +  TRACE_ENTER();
> +
> +  while (dispatchTimer.is_timeout() == false) {
> +    ais_rc = saImmOiDispatch(i_immOiHandle, i_dispatchFlags);
> +
> +    if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
> +      base::Sleep(base::kFiveHundredMilliseconds);
> +      continue;
> +    } else if (ais_rc != SA_AIS_OK) {
> +      LOG_WA("%s: saImmOiDispatch() Fail '%s'", __FUNCTION__,
> +             saf_error(ais_rc));
> +      break;
> +    } else {
> +      // Done
> +      break;
> +    }
> +  }
> +  if (dispatchTimer.is_timeout() == true && ais_rc != SA_AIS_OK) {
> +    LOG_WA("%s: saImmOiDispatch() timeout Fail '%s'", __FUNCTION__,
> +           saf_error(ais_rc));
> +  }
> +  TRACE_LEAVE();
> +  return ais_rc;
> +}
> +
> +/**
> + * The applier callback functions
> + * These are C functions as specified by IMM AIS SaImmOiCallbacksT_2
> + * Note: CCB is "collected" using existing list handling in immutil.c
> + **/
> +
> +/**
> + * Save ccb info if OpensafConfig object is modified
> + *
> + */
> +static SaAisErrorT CcbObjectModifyCallback(SaImmOiHandleT immOiHandle,
> +                                    SaImmOiCcbIdT ccbId,
> +                                    const SaNameT *objectName,
> +                                    const SaImmAttrModificationT_2 
> **attrMods) {
> +  SaAisErrorT rc = SA_AIS_OK;
> +  struct CcbUtilCcbData *ccbUtilCcbData;
> +
> +  TRACE_ENTER();
> +
> +  if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) == nullptr) {
> +    if ((ccbUtilCcbData = ccbutil_getCcbData(ccbId)) == nullptr) {
> +      TRACE("%s: Failed to get CCB object for %llu", __FUNCTION__, ccbId);
> +      rc = SA_AIS_ERR_NO_MEMORY;
> +      goto done;
> +    }
> +  }
> +
> +  ccbutil_ccbAddModifyOperation(ccbUtilCcbData, objectName, attrMods);
> +
> +done:
> +  TRACE_LEAVE();
> +  return rc;
> +}
> +
> +/**
> + * Get the new value of the attribute
> + * Note: This function is limited to handle one attribute in one object and
> + * the type of the attribute must be SaUint32T
> + */
> +static void CcbApplyCallback(SaImmOiHandleT immOiHandle, SaImmOiCcbIdT 
> ccbId) {
> +  struct CcbUtilCcbData *ccbUtilCcbData;
> +  struct CcbUtilOperationData *opdata;
> +  const SaImmAttrModificationT_2 *attrMod;
> +  SaConstStringT objName;
> +  SaImmAttrValuesT_2 attribute;
> +
> +  // Note: Only one value of type SaUint32T can be handled
> +  SaUint32T *value = nullptr;
> +
> +  TRACE_ENTER();
> +
> +  /* Verify the ccb */
> +  if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) == nullptr) {
> +    LOG_NO("%s: Failed to find CCB object for id %llu", __FUNCTION__, ccbId);
> +    goto done;
> +  }
> +
> +  /* We don't need to loop since the only possible operation is MODIFY
> +   * and only one object is monitored
> +   */
> +  opdata = ccbUtilCcbData->operationListHead;
> +  if (opdata->operationType != CCBUTIL_MODIFY) {
> +    TRACE("%s: Not a modify operation", __FUNCTION__);
> +    goto done;
> +  }
> +
> +  objName = osaf_extended_name_borrow(&opdata->objectName);
> +  if (object_name_.compare(objName) != 0) {
> +    TRACE("%s: Object \"%s\" not an OpensafConfig object",
> +          __FUNCTION__, objName);
> +    goto done;
> +  }
> +
> +  /* Read value in opensafNetworkName
> +   * Note: This is implemented as a loop in case more attributes are
> +   *       added in the class in the future. For now the only
> +   *       attribute of interest here is opensafNetworkName
> +   */
> +  TRACE("%s: Read value in attributes", __FUNCTION__);
> +  attrMod = opdata->param.modify.attrMods[0];
> +  attribute = attrMod->modAttr;
> +
> +  for (int i = 1; attrMod != nullptr; i++) {
> +    /* Get the value */
> +    if (attribute_name_.compare(attribute.attrName) != 0) {
> +      // Not found
> +      attrMod = opdata->param.modify.attrMods[i];
> +      continue;
> +    }
> +
> +    // Attribute found
> +    value = static_cast<SaUint32T*> (attribute.attrValues[0]);
> +    break;
> +  }
> +
> +  if (value == nullptr) {
> +    TRACE("%s: Value is nullptr", __FUNCTION__);
> +    SetAttributeValue("");
> +    attribute_value_is_valid_ = false;
> +  } else {
> +    SetAttributeValue(std::to_string(*value));
> +    attribute_value_is_valid_ = true;
> +  }
> +
> +done:
> +  if (ccbUtilCcbData != nullptr)
> +    ccbutil_deleteCcbData(ccbUtilCcbData);
> +
> +  TRACE_LEAVE();
> +}
> +
> +/**
> + * Cleanup by deleting saved ccb info if aborted
> + *
> + */
> +static void CcbAbortCallback(SaImmOiHandleT immOiHandle, SaImmOiCcbIdT 
> ccbId) {
> +  struct CcbUtilCcbData *ccbUtilCcbData;
> +
> +  TRACE_ENTER2("CCB ID %llu", ccbId);
> +
> +  if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) != nullptr)
> +    ccbutil_deleteCcbData(ccbUtilCcbData);
> +  else
> +    TRACE("%s: Failed to find CCB object for %llu", __FUNCTION__, ccbId);
> +
> +  TRACE_LEAVE();
> +}
> +
> +/**
> + * An object of OpensafConfig class is created. We don't have to do anything
> + * Cannot be replaced by nullptr pointer in callback list
> + */
> +static SaAisErrorT CcbCreateCallback(SaImmOiHandleT immOiHandle,
> +                                     SaImmOiCcbIdT ccbId,
> +                                     const SaImmClassNameT className,
> +                                     const SaNameT *parentName,
> +                                     const SaImmAttrValuesT_2 **attr) {
> +  TRACE_ENTER();
> +  TRACE_LEAVE();
> +  return SA_AIS_OK;
> +}
> +
> +/**
> + * An object of OpensafConfig class is deleted. We don't have to do anything
> + * Cannot be replaced by nullptr pointer in callback list
> + */
> +static SaAisErrorT CcbDeleteCallback(SaImmOiHandleT immOiHandle,
> +                                     SaImmOiCcbIdT ccbId,
> +                                     const SaNameT *objectName) {
> +  TRACE_ENTER();
> +  TRACE_LEAVE();
> +  return SA_AIS_OK;
> +}
> +
> +/* Callback function list given to IMM when OI is initialized
> + * We need:
> + * Modify for saving modify ccb
> + * Apply for knowing that the modification has been applied
> + * Abort for removing saved ccb in case of an abortion of ccb
> + */
> +static const SaImmOiCallbacksT_2 callbacks = {
> +  .saImmOiAdminOperationCallback = nullptr,
> +  .saImmOiCcbAbortCallback = CcbAbortCallback,
> +  .saImmOiCcbApplyCallback = CcbApplyCallback,
> +  .saImmOiCcbCompletedCallback = nullptr,
> +  .saImmOiCcbObjectCreateCallback = CcbCreateCallback,
> +  .saImmOiCcbObjectDeleteCallback = CcbDeleteCallback,
> +  .saImmOiCcbObjectModifyCallback = CcbObjectModifyCallback,
> +  .saImmOiRtAttrUpdateCallback = nullptr
> +};
> +
> +// =====================================
> +// SmfImmApplierHdl Class implementation
> +// =====================================
> +// Make next_instance_number_ thread safe
> +std::atomic<unsigned int> SmfImmApplierHdl::instance_number_{1};
> +SmfImmApplierHdl::SmfImmApplierHdl() :
> +    isCreated_ {false},
> +    imm_appl_hdl_ {0},
> +    imm_appl_selobj_ {0} {
> +  applier_name_ = "@safSmf_applier"+std::to_string(instance_number_++);
> +}
> +
> +SmfImmApplierHdl::~SmfImmApplierHdl() {
> +  TRACE_ENTER();
> +  Remove();
> +  TRACE_LEAVE();
> +}
> +
> +void SmfImmApplierHdl::Remove() {
> +  // Release all resources, give up applier, remove applier name and 
> finalize OI
> +  if (Stop() == false) {
> +    LOG_NO("%s: ReleaseImmOiForObject Fail", __FUNCTION__);
> +  }
> +  if (ImmOiClear(imm_appl_hdl_) == false) {
> +    LOG_NO("%s: ImmOiClear() Fail", __FUNCTION__);
> +  }
> +  if (FinalizeImmOi(imm_appl_hdl_) == false) {
> +    LOG_NO("%s: FinalizeImmOi() Fail", __FUNCTION__);
> +  }
> +}
> +
> +bool SmfImmApplierHdl::Create(const ApplierSetupInfo& setup_info) {
> +  bool do_continue = true;
> +  TRACE_ENTER();
> +
> +  is_cancel = false;
> +  if (imm_appl_hdl_ == 0) {
> +    // If initialize is needed
> +    TRACE("%s: Do create", __FUNCTION__);
> +    object_name_ = setup_info.object_name;
> +    attribute_name_ = setup_info.attribute_name;
> +    attribute_value_is_valid_ = false;
> +
> +    // Initialize
> +    do_continue = InitializeImmOi(&imm_appl_hdl_, &callbacks, &kImmVersion);
> +    TRACE("%s: InitializeImmOi() = %s", __FUNCTION__,
> +          do_continue? "true": "false");
> +
> +    // Get selection object
> +    if (do_continue) {
> +      do_continue = GetImmOiSelectionObject(imm_appl_hdl_, 
> &imm_appl_selobj_);
> +      TRACE("%s: GetImmOiSelectionObject() = %s", __FUNCTION__,
> +            do_continue? "true": "false");
> +    }
> +  }
> +
> +  TRACE_LEAVE();
> +  return do_continue;
> +}
> +
> +bool SmfImmApplierHdl::Start() {
> +  std::string value;
> +  bool do_continue = true;
> +
> +  TRACE_ENTER();
> +  is_cancel = false;
> +
> +  // OI Set
> +  // Note: If the applier name already exist it is because SMF on another
> +  // node has created an applier with the same name. This not ok for an
> +  // object implementer but is ok for an applier.
> +  // Create a new name and try again. Limit number of retries
> +  for (int i = 0; i < 3; i++) {
> +    do_continue = ImmOiSet(imm_appl_hdl_, applier_name_);
> +
> +    if (do_continue) {
> +      break;
> +    } else {
> +      // Create a new name and try again
> +      applier_name_ = "@safSmf_applier"+std::to_string(instance_number_++);
> +      LOG_NO("%s: A new applier name is created '%s'",
> +          __FUNCTION__, applier_name_.c_str());
> +    }
> +  }
> +
> +  // Set which object to monitor
> +  if (do_continue) {
> +    do_continue = SetImmOiForObject(imm_appl_hdl_, object_name_, SA_IMM_ONE);
> +    TRACE("%s: SetImmOiForObject() = %s", __FUNCTION__,
> +       do_continue? "true": "false");
> +
> +    if (do_continue) {
> +      if (attribute_value_is_valid_ == false) {
> +        // Get the current value from IMM
> +        value = GetAttributeValueFromImm(object_name_, attribute_name_);
> +        TRACE("%s: GetAttributeValueFromImm() = '%s'",
> +              __FUNCTION__, value.c_str());
> +      }
> +      if (value != "") {
> +        attribute_value_is_valid_ = true;
> +      }
> +      SetAttributeValue(value);
> +      TRACE("%s: SetAttributeValue(%s), "
> +            "attribute_value_is_valid_ = %s", __FUNCTION__, value.c_str(),
> +            attribute_value_is_valid_? "true": "false");
> +    }
> +  }
> +
> +  if (do_continue == false) {
> +    LOG_WA("%s: Applier could not be started", __FUNCTION__);
> +  }
> +
> +  TRACE_LEAVE();
> +  return do_continue;
> +}
> +
> +bool SmfImmApplierHdl::Stop() {
> +  bool rc = true;
> +
> +  TRACE_ENTER();
> +
> +  is_cancel = true;
> +  attribute_value_is_valid_ = false;
> +  SetAttributeValue("");
> +
> +  if (imm_appl_hdl_ != 0) {
> +    rc = ReleaseImmOiForObject(imm_appl_hdl_, object_name_, SA_IMM_ONE);
> +    if (rc == false) {
> +      LOG_NO("%s: ReleaseImmOiForObject() Fail", __FUNCTION__);
> +    }
> +
> +    rc = ImmOiClear(imm_appl_hdl_);
> +    if (rc == false) {
> +      LOG_NO("%s: ImmOiClear Fail", __FUNCTION__);
> +    }
> +  }
> +  TRACE_LEAVE2("rc = %s", rc? "true": "false");
> +  return rc;
> +}
> +
> +void SmfImmApplierHdl::CancelCreate() {
> +  is_cancel = true;
> +}
> +
> +std::string SmfImmApplierHdl::get_value() {
> +  attribute_value_lock.lock();
> +  std::string value = attribute_value_;
> +  attribute_value_lock.unlock();
> +  return value;
> +}
> +
> +ExecuteImmCallbackReply SmfImmApplierHdl::ExecuteImmCallback() {
> +  ExecuteImmCallbackReply method_rc = ExecuteImmCallbackReply::kOk;
> +
> +  TRACE_ENTER();
> +  SaAisErrorT ais_rc = DispatchOiCallback(imm_appl_hdl_, SA_DISPATCH_ALL);
> +
> +  if (ais_rc == SA_AIS_OK) {
> +    method_rc = ExecuteImmCallbackReply::kOk;
> +  } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
> +    struct ApplierSetupInfo setup;
> +    setup.object_name = object_name_;
> +    setup.attribute_name = attribute_name_;
> +    imm_appl_hdl_ = 0;
> +    bool is_ok = Create(setup);
> +    if (is_ok) {
> +      method_rc = ExecuteImmCallbackReply::kGetNewSelctionObject;
> +    } else {
> +      method_rc = ExecuteImmCallbackReply::kError;
> +    }
> +  } else {
> +    method_rc = ExecuteImmCallbackReply::kError;
> +  }
> +
> +  TRACE_LEAVE();
> +  return method_rc;
> +}
> diff --git a/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.hh 
> b/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.hh
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/smfsv/smfd/SmfImmApplierHdl.hh
> @@ -0,0 +1,113 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <string>
> +#include <atomic>
> +
> +#include "base/macros.h"
> +#include "saImmOi.h"
> +
> +#ifndef SMFIMMAPPLIERHDL_HH
> +#define SMFIMMAPPLIERHDL_HH
> +
> +/**
> + * This class creates and handle an IMM applier
> + * The handler must be used in an "outer" thread that implements a poll loop
> + * The thread shall get a selection object (poll fd) and call the
> + * ExecuteImmCallback() method when released
> + *
> + * Note/Warning:
> + * The IMM object applier handle may be set to invalid by IMM. This will be
> + * detected and handled in the ExecuteImmCallback() method. This method will
> + * not return until the applier is restored or timed out which may take up to
> + * one minute.
> + * Do not use this handler in a thread that cannot handle this!
> + *
> + * In this version the following limitations apply:
> + * - Only one IMM object can be monitored
> + * - Only modifications of one attribute can be handled
> + * - All values are given as a std::string. The user has to convert to other
> + *   type if needed
> + */
> +
> +// In-parameter for SmfImmApplierHdl Create())
> +struct ApplierSetupInfo {
> +  std::string object_name;
> +  std::string attribute_name;
> +  //SaImmOiCcbApplyCallbackT ApplyCallbackFunction;
> +};
> +
> +enum class ExecuteImmCallbackReply {
> +  kOk = 0,
> +  kGetNewSelctionObject,
> +  kError
> +};
> +
> +class SmfImmApplierHdl {
> + public:
> +  SmfImmApplierHdl(void);
> +  ~SmfImmApplierHdl(void);
> +
> +  // Create an applier for monitoring changes of one attribute in one object
> +  // The applier is not started. To start use Start() method
> +  // Note: Create() must be called before Start() and Stop() can be used
> +  // Return false if Fail
> +  bool Create(const ApplierSetupInfo& setup_info);
> +
> +  // Cancel an ongoing create operation that may take a long time.
> +  // The saImmOiInitialize_2() (see IMM documentation) must have a TRY AGAIN
> +  // loop that may take up to one minute.
> +  // This method can be used by an applier that uses a thread for IMM 
> handling
> +  // from outside the thread to cancel an ongoing create operation that may
> +  // hang the thread
> +  void CancelCreate(void);
> +
> +  // Start the applier
> +  // Return false if Fail
> +  bool Start(void);
> +
> +  // Finalize all resources used by the applier
> +  // Return false if Fail
> +  bool Stop(void);
> +
> +  // Remove the applier by freeing all IMM resources
> +  void Remove(void);
> +
> +  // Get the monitored value
> +  // If there is no valid value an empty string is returned
> +  std::string get_value(void);
> +
> +  // Used with poll loop (fd)
> +  SaSelectionObjectT get_selection_object(void) { return imm_appl_selobj_; }
> +
> +  // Uses saImmOiDispatch to call the appropriate callback function
> +  // Shall be called when the selection object releases the poll loop
> +  // If return code is kGetNewSelctionObject the applier has been restored 
> and
> +  // the selection object has to be updated
> +  ExecuteImmCallbackReply ExecuteImmCallback(void);
> +
> + private:
> +  const SaVersionT kImmVersion = { 'A', 2, 11 };
> +  static std::atomic<unsigned int> instance_number_;
> +  bool isCreated_;
> +  std::string applier_name_;
> +  SaImmOiHandleT imm_appl_hdl_;
> +  SaSelectionObjectT imm_appl_selobj_;
> +};
> +
> +#endif /* SMFIMMAPPLIERHDL_HH */
> diff --git a/osaf/services/saf/smfsv/smfd/SmfImmOperation.cc 
> b/osaf/services/saf/smfsv/smfd/SmfImmOperation.cc
> --- a/osaf/services/saf/smfsv/smfd/SmfImmOperation.cc
> +++ b/osaf/services/saf/smfsv/smfd/SmfImmOperation.cc
> @@ -34,6 +34,7 @@
>   #include <saImm.h>
>   #include <saf_error.h>
>   #include "osaf_extended_name.h"
> +#include "smfd_long_dn.hh"
>   
>   /* ========================================================================
>    *   DEFINITIONS
> @@ -391,9 +392,9 @@ SmfImmCreateOperation::execute(SmfRollba
>   
>       const char *className = m_className.c_str();
>   
> -     if (m_parentDn.length() > smfd_cb->maxDnLength) {
> +     if (m_parentDn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("Object create op failed, parent name too long [%zu] 
> max=[%zu], parent=[%s]",
> -                        m_parentDn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength),
> +                        m_parentDn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()),
>                           m_parentDn.c_str());
>               TRACE_LEAVE();
>               return SA_AIS_ERR_NAME_TOO_LONG;
> @@ -629,7 +630,7 @@ SmfImmDeleteOperation::execute(SmfRollba
>               return SA_AIS_ERR_UNAVAILABLE;
>       }
>   
> -     if (m_dn.length() > smfd_cb->maxDnLength) {
> +     if (m_dn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("SmfImmDeleteOperation::execute: failed Too long dn %zu",
>                      m_dn.length());
>                   TRACE_LEAVE();
> @@ -1005,7 +1006,7 @@ SmfImmModifyOperation::execute(SmfRollba
>               return SA_AIS_ERR_UNAVAILABLE;
>       }
>   
> -     if (m_dn.length() > smfd_cb->maxDnLength) {
> +     if (m_dn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("SmfImmModifOperation::execute: failed Too long dn %zu",
>                      m_dn.length());
>                   TRACE_LEAVE();
> @@ -1290,7 +1291,7 @@ SmfImmRTCreateOperation::execute()
>   
>       const char *className = m_className.c_str();
>   
> -     if (m_parentDn.length() > smfd_cb->maxDnLength) {
> +     if (m_parentDn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("SmfImmRTCreateOperation::execute, createObject failed 
> Too long parent name %zu",
>                      m_parentDn.length());
>                   TRACE_LEAVE();
> @@ -1483,9 +1484,9 @@ SmfImmRTUpdateOperation::execute()
>               goto exit;
>       }
>   
> -     if (m_dn.length() > smfd_cb->maxDnLength) {
> +     if (m_dn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("SmfImmRTUpdateOperation::execute, too long DN [%zu], 
> max=[%zu], dn=[%s]",
> -                 m_dn.length(), static_cast<size_t>(smfd_cb->maxDnLength), 
> m_dn.c_str());
> +                 m_dn.length(), static_cast<size_t>(GetSmfMaxDnLength()), 
> m_dn.c_str());
>               result = SA_AIS_ERR_NAME_TOO_LONG;
>               goto exit;
>       }
> diff --git a/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.cc 
> b/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.cc
> @@ -0,0 +1,441 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <thread>
> +#include <atomic>
> +#include <memory>
> +
> +#include "SmfLongDnApplier.hh"
> +#include "SmfImmApplierHdl.hh"
> +#include "smfd.h"
> +#include "SmfUtils.hh"
> +
> +#include "saf_error.h"
> +#include "logtrace.h"
> +#include "osaf_utility.h"
> +#include "osaf_time.h"
> +#include "osaf_poll.h"
> +#include "base/time.h"
> +
> +/**
> + * Local definitions not needed outside of this file
> + */
> +
> +/* Inter thread communication (via socket pair) */
> +static const char* CMD_STOP = "s";
> +static const char* CMD_START = "a";
> +static const char* CMD_REMOVE = "r";
> +static const size_t CMD_SIZE = 2;
> +
> +static int socket_fd_thread = 0;  // Socket for thread to read commands
> +static int socket_fd_command = 0; // Socket for commands to thread
> +
> +/* States for the applier thread. Stopping and starting the applier is 
> handled
> + * differently dependent on the thread state
> + */
> +enum class th_state{
> +  /* Thread not started */
> +  TH_NOT_CREATED = 0,
> +  /* Thread is started but has not yet entered the event handling poll loop 
> */
> +  TH_CREATING,
> +  /* Thread is fully started and running as applier */
> +  TH_IS_APPLIER,
> +  /* Thread is fully started but is not running as applier. In this state
> +   * it can service commands e.g. start applier command but has never
> +   * become an applier or have given up the applier role
> +   */
> +  TH_IDLE,
> +  /* Thread is terminating */
> +  TH_TERMINATING
> +};
> +
> +static std::atomic<th_state> th_state_info {th_state::TH_NOT_CREATED};
> +
> +/**
> + * These functions should be here so that also TRACEes can be made in the 
> future
> + * that prints the thread command and states as strings for better 
> readability
> + */
> +// cppcheck-suppress unusedFunction
> +const char *th_statestr(th_state state) {
> +  switch (state) {
> +    case th_state::TH_CREATING: return "CREATING";
> +    case th_state::TH_IDLE: return "IDLE";
> +    case th_state::TH_IS_APPLIER: return "IS APPLIER";
> +    case th_state::TH_NOT_CREATED: return "NOT_CREATED";
> +    case th_state::TH_TERMINATING: return "TERMINATING";
> +    default: return "UNKNOWN STATE";
> +  }
> +}
> +
> +// cppcheck-suppress unusedFunction
> +const char *th_cmdstr(th_cmd cmd) {
> +  switch (cmd) {
> +    case th_cmd::AP_REMOVE: return "REMOVE";
> +    case th_cmd::AP_START: return "START";
> +    case th_cmd::AP_STOP: return "STOP";
> +    default: return "UNKNOWN CMD";
> +  }
> +}
> +
> +// The thread function
> +// This is the thread where the applier is running.
> +// For communication with the thread a socket pair is used. Input
> +// command_socket shall contain the fd to be used in the thread
> +// Thread can be stopped if CMD_REMOVE command or if applier error.
> +// If the thread is stopped the applier handler is removed and thread state 
> is
> +// set to TH_NOT_STARTED
> +// Note:
> +// This function is started as a thread using C++11 thread(). Parameters 
> cannot
> +// be passed as reference in the "normal" way. Also this function is used 
> once
> +//
> +// cppcheck-suppress passedByValue
> +static void ApplierThread(const std::string object_name,
> +// cppcheck-suppress passedByValue
> +                          const std::string attribute_name,
> +                          SmfImmApplierHdl *ApplierHdl,
> +                          const int command_socket) {
> +  /* Event handling
> +   * Note:
> +   * IMM selection object can only be part of polling when IMM OI is
> +   * initialized. If IMM is finalized the selection object is not valid.
> +   * This is handled by placing IMM selection fd as last element in fds
> +   * vector and decrease and decrease nfds when IMM is finalized.
> +   */
> +  enum {
> +    FDA_COM = 0,    /* Communication events */
> +    FDA_IMM,        /* IMM events */
> +    NUM_FDA
> +  };
> +
> +  thread_local struct pollfd fds[NUM_FDA];
> +  ExecuteImmCallbackReply execute_rc = ExecuteImmCallbackReply::kOk;
> +
> +  TRACE("%s: %s, %s, %d", __FUNCTION__, object_name.c_str(),
> +        attribute_name.c_str(), command_socket);
> +
> +  th_state_info = th_state::TH_CREATING;
> +
> +  // Create the applier
> +  ApplierSetupInfo setup_info {object_name, attribute_name};
> +  bool create_rc = ApplierHdl->Create(setup_info);
> +  if (create_rc == false) {
> +    LOG_WA("%s: Creation of long DN applier Fail", __FUNCTION__);
> +    th_state_info = th_state::TH_NOT_CREATED;
> +    return; // Terminate the thread
> +  }
> +
> +  // Setup event handling
> +  fds[FDA_IMM].fd = ApplierHdl->get_selection_object();
> +  fds[FDA_IMM].events = POLLIN;
> +  fds[FDA_COM].fd = command_socket;
> +  fds[FDA_COM].events = POLLIN;
> +  thread_local nfds_t nfds = NUM_FDA;
> +
> +  th_state_info = th_state::TH_IDLE;
> +
> +  TRACE("%s: Applier is created, th_state_info = %s",
> +     __FUNCTION__, th_statestr(th_state_info));
> +
> +  while(1) {
> +    (void) osaf_poll(fds, nfds, -1);
> +
> +    // Handle IMM callback
> +    if (fds[FDA_IMM].revents & POLLIN) {
> +      TRACE("%s: IMM event", __FUNCTION__);
> +
> +      // Note: ExecuteImmCallback can "hang" for up to one minute if IMM
> +      // has "invalidated" the OI handle and ExecuteImmCallback has to 
> restore
> +      // the applier. Such a restore can be canceled and that must be done
> +      // before sending a stop command to this thread
> +      execute_rc = ApplierHdl->ExecuteImmCallback();
> +      if (execute_rc == ExecuteImmCallbackReply::kGetNewSelctionObject) {
> +        fds[FDA_IMM].fd = ApplierHdl->get_selection_object();
> +      } else if (execute_rc == ExecuteImmCallbackReply::kError) {
> +        LOG_WA("%s: ExecuteImmCallback Error", __FUNCTION__);
> +        th_state_info = th_state::TH_NOT_CREATED;
> +        break; // Thread exit
> +      }
> +    }
> +
> +    // Handle commands
> +    if (fds[FDA_COM].revents & POLLIN) {
> +      TRACE("%s: COM event", __FUNCTION__);
> +
> +      char cmd_str[256] = {0};
> +      int read_rc = 0;
> +      while (1) {
> +        read_rc = read(command_socket, cmd_str, 256);
> +        if ((read_rc == -1) && (errno == EINTR)) {
> +          /* Try again */
> +          continue;
> +        } else break;
> +      }
> +
> +      if (read_rc == -1) {
> +        LOG_WA("%s: Read socket Fail %s", __FUNCTION__, strerror(errno));
> +        break; // Terminate thread
> +      }
> +
> +      TRACE("%s: Command is: '%s'", __FUNCTION__, cmd_str);
> +
> +      if (strcmp(cmd_str, CMD_STOP) == 0) {
> +        TRACE("%s: STOP received", __FUNCTION__);
> +        if (ApplierHdl->Stop() == false) {
> +          LOG_WA("%s: Applier.Stop() Fail", __FUNCTION__);
> +          th_state_info = th_state::TH_NOT_CREATED;
> +          ApplierHdl->Remove();
> +          break; // Terminate thread
> +        } else {
> +          th_state_info = th_state::TH_IDLE;
> +        }
> +      } else if (strcmp(cmd_str, CMD_START) == 0) {
> +        TRACE("%s: START received", __FUNCTION__);
> +        if (ApplierHdl->Start() == false) {
> +          LOG_NO("%s: Applier.Start() Fail", __FUNCTION__);
> +          th_state_info = th_state::TH_TERMINATING;
> +          ApplierHdl->Remove();
> +          break; // Terminate thread
> +        } else {
> +          th_state_info = th_state::TH_IS_APPLIER;
> +        }
> +      } else if (strcmp(cmd_str, CMD_REMOVE) == 0) {
> +        TRACE("%s: EXIT received", __FUNCTION__);
> +        th_state_info = th_state::TH_TERMINATING;
> +        ApplierHdl->Remove();
> +        break; // Thread exit
> +      }
> +    }
> +  } /* END Event handling loop */
> +  LOG_NO("%s: Thread is terminated", __FUNCTION__);
> +  th_state_info = th_state::TH_NOT_CREATED;
> +}
> +
> +// ===================
> +// SmLongDnApplier class
> +// ===================
> +SmfLongDnApplier::SmfLongDnApplier(const std::string& object_name,
> +                                const std::string& attribute_name) :
> +    object_name_{object_name},
> +    attribute_name_{attribute_name} {
> +  TRACE_ENTER();
> +  ApplierHdl_ = new SmfImmApplierHdl();
> +  TRACE_LEAVE();
> +}
> +
> +SmfLongDnApplier::~SmfLongDnApplier() {
> +  // Stop/Finalize the applier including thread termination
> +  TRACE_ENTER2();
> +  Remove();
> +  delete ApplierHdl_;
> +  TRACE_LEAVE2();
> +}
> +
> +void SmfLongDnApplier::Start() {
> +  TRACE_ENTER();
> +  if ((th_state_info == th_state::TH_IDLE) ||
> +      (th_state_info == th_state::TH_CREATING)){
> +    TRACE("%s: Sending START to thread", __FUNCTION__);
> +    SendCommandToThread(th_cmd::AP_START);
> +  } else {
> +    LOG_WA("%s: Trying to start an applier that is not created",
> +        __FUNCTION__);
> +    // Try to recover by creating and start again. We may end up in this
> +    // situation if creation or IMM bad handle recovery was canceled by a
> +    // stop request
> +    Create();
> +    if ((th_state_info == th_state::TH_IDLE) ||
> +     (th_state_info == th_state::TH_CREATING)){
> +      TRACE("%s: Re-sending START to thread", __FUNCTION__);
> +      SendCommandToThread(th_cmd::AP_START);
> +    } else {
> +      LOG_ER("%s: Cannot create and start "
> +             "the long dn monitoring applier", __FUNCTION__);
> +    }
> +  }
> +  TRACE_LEAVE();
> +}
> +
> +void SmfLongDnApplier::Stop() {
> +  TRACE_ENTER();
> +  // Try to stop applier only if an applier is running
> +  if (th_state_info == th_state::TH_IS_APPLIER) {
> +    TRACE("%s: Sending STOP to thread", __FUNCTION__);
> +    // If there is an ongoing IMM initialization TRY AGAIN loop it must be
> +    // canceled so that the stop command can be executed immediately
> +    ApplierHdl_->CancelCreate();
> +    SendCommandToThread(th_cmd::AP_STOP);
> +
> +    // Wait until thread is in idle state before returning
> +    // This guarantees that the applier is stopped and can be started
> +    // on another node.
> +    base::Timer applier_stop_timer (1000); // ms
> +    while (applier_stop_timer.is_timeout() == false) {
> +      if (th_state_info != th_state::TH_IS_APPLIER)
> +        break; // Is stopped
> +      base::Sleep(base::kTenMilliseconds);
> +    }
> +    if (th_state_info == th_state::TH_IS_APPLIER) {
> +      // Timeout: This should never happen
> +      LOG_ER("%s: Applier cold not be stopped within 1 sec",
> +          __FUNCTION__);
> +    }
> +    TRACE("%s: STOP done. Thread state is %s", __FUNCTION__,
> +          th_statestr(th_state_info));
> +  } else {
> +    LOG_WA("%s: Trying to stop an applier that is not running",
> +        __FUNCTION__);
> +  }
> +  TRACE_LEAVE();
> +}
> +
> +void SmfLongDnApplier::Create() {
> +  TRACE_ENTER();
> +  // Do not try to create if already created is creating or is terminating
> +  if (th_state_info == th_state::TH_NOT_CREATED) {
> +    // Create socket pair for communication with applier thread
> +    // Note: Non block is used. This makes it possible to handle EAGAIN as an
> +    // error. Commands shall not be queued so the buffer should never be full
> +    int sock_fd[2] = {0};
> +    int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fd);
> +    if (rc == -1) {
> +      LOG_ER("%s: socketpair() Fail %s", __FUNCTION__, strerror(errno));
> +      osaf_abort(0);
> +    }
> +
> +    fcntl(sock_fd[0], F_SETFL, O_NONBLOCK);
> +    fcntl(sock_fd[1], F_SETFL, O_NONBLOCK);
> +    socket_fd_thread = sock_fd[0];
> +    socket_fd_command = sock_fd[1];
> +
> +    // Start the thread
> +    std::thread t1 {ApplierThread, object_name_, attribute_name_,
> +                   ApplierHdl_, socket_fd_thread};
> +    t1.detach();
> +    TRACE("%s: Thread is started", __FUNCTION__);
> +
> +    // For synchronization, Wait for thread to enter CREATING state
> +    // Note: Thread shall enter CREATING state immediately after it has been
> +    // started
> +    int i = 0;
> +    for (i = 0; i < 10; i++) {
> +      if (th_state_info != th_state::TH_NOT_CREATED) break;
> +      base::Sleep(base::kTenMilliseconds);
> +    }
> +    if (th_state_info == th_state::TH_NOT_CREATED) {
> +      LOG_WA("%s: Applier thread has not started within 100 ms",
> +          __FUNCTION__);
> +    }
> +  } else {
> +    LOG_WA("%s: Trying to create an already created applier",
> +           __FUNCTION__);
> +  }
> +  TRACE_LEAVE();
> +}
> +
> +// --------------------
> +// The private method's
> +// --------------------
> +
> +// Terminates the applier by sending a remove command to the thread
> +// The thread will remove the applier and terminate
> +void SmfLongDnApplier::Remove() {
> +  TRACE_ENTER();
> +  // First check if there is any applier to terminate
> +  if (th_state_info == th_state::TH_NOT_CREATED) {
> +    LOG_NO("%s: Trying to remove an applier that is not created",
> +           __FUNCTION__);
> +    return;
> +  }
> +
> +  // Finalize the applier and terminate the thread
> +  ApplierHdl_->CancelCreate();
> +  SendCommandToThread(th_cmd::AP_REMOVE);
> +
> +  TRACE("%s: REMOVE command sent. Waiting for termination of thread",
> +        __FUNCTION__);
> +  // Wait for thread to terminate. For synchronizing
> +  base::Timer terminate_timeout(10000); // ms
> +  while (terminate_timeout.is_timeout() == false) {
> +    if (th_state_info == th_state::TH_NOT_CREATED)
> +      break; // Thread has terminated
> +    base::Sleep(base::kOneHundredMilliseconds);
> +  }
> +  if (th_state_info != th_state::TH_NOT_CREATED) {
> +    // Should not be possible
> +    LOG_ER("%s: Applier thread termination Failed. Thread state is '%s'",
> +           __FUNCTION__, th_statestr(th_state_info));
> +    osaf_abort(0);
> +  }
> +  TRACE("%s: Thread has terminated thread state is %s", __FUNCTION__,
> +        th_statestr(th_state_info));
> +
> +  CloseSockets();
> +  TRACE_LEAVE();
> +}
> +
> +void SmfLongDnApplier::CloseSockets() {
> +  TRACE_ENTER();
> +  if (socket_fd_thread != 0) {
> +    close(socket_fd_thread);
> +    socket_fd_thread = 0;
> +  }
> +
> +  if (socket_fd_command != 0) {
> +    close(socket_fd_command);
> +    socket_fd_command = 0;
> +  }
> +  TRACE_LEAVE();
> +}
> +
> +void SmfLongDnApplier::SendCommandToThread(th_cmd command) {
> +  const char *cmd_str = nullptr;
> +  int rc = 0;
> +
> +  TRACE_ENTER2("Command %s", th_cmdstr(command));
> +
> +  switch (command) {
> +    case th_cmd::AP_START:
> +      cmd_str = CMD_START;
> +      break;
> +    case th_cmd::AP_STOP:
> +      cmd_str = CMD_STOP;
> +      break;
> +    case th_cmd::AP_REMOVE:
> +      cmd_str = CMD_REMOVE;
> +      break;
> +    default:
> +      LOG_ER("%s: Unknown command %d", __FUNCTION__, command);
> +      osaf_abort(0);
> +  }
> +
> +  while (1) {
> +    rc = write(socket_fd_command, cmd_str, CMD_SIZE);
> +    if ((rc == -1) && (errno == EINTR))
> +      /* Try again */
> +      continue;
> +    else
> +      break;
> +  }
> +
> +  if (rc == -1) {
> +    LOG_ER("%s: Write Fail %s", __FUNCTION__, strerror(errno));
> +    osaf_abort(0);
> +  }
> +
> +  TRACE_LEAVE();
> +}
> +
> diff --git a/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.hh 
> b/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.hh
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/smfsv/smfd/SmfLongDnApplier.hh
> @@ -0,0 +1,84 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <string>
> +#include <memory>
> +
> +#include "base/macros.h"
> +#include "SmfImmApplierHdl.hh"
> +
> +#ifndef SMFIMMAPPLIER_HH
> +#define SMFIMMAPPLIER_HH
> +
> +// Commands that can be used with thread
> +enum class th_cmd {
> +  AP_START,
> +  AP_STOP,
> +  AP_REMOVE
> +};
> +
> +/**
> + * This class implements an IMM applier for monitoring long Dn setting
> + * The applier is running in a separate thread.
> + * The thread implements a poll loop handling IMM callback and start/stop
> + * commands using the SmfImmApplierHdl class
> + * For communicating commands to the thread a socket pair is used
> + */
> +class SmfLongDnApplier {
> +   public:
> +  SmfLongDnApplier(const std::string& object_name,
> +                   const std::string& attribute_name);
> +
> +  ~SmfLongDnApplier(void);
> +
> +  // Creates the applier thread
> +  // The thread will create but not start the applier
> +  void Create(void);
> +
> +  // Start an applier (in a separate thread).
> +  void Start(void);
> +
> +  // Stop the applier.
> +  // Wait until the applier is stopped
> +  void Stop(void);
> +
> +  // Return true if long-dn is allowed based on setting in IMM configuration
> +  // object
> +  bool getValue(void) {
> +    std::string value_str = ApplierHdl_->get_value();
> +    if (value_str != "") {
> +      return std::stoul(value_str, nullptr, 0) != 0? true: false;
> +    } else {
> +      return false;
> +    }
> +  }
> +
> + private:
> +  void Remove(void);
> +  void CloseSockets(void);
> +  void SendCommandToThread(th_cmd);
> +
> +  std::string object_name_;
> +  std::string attribute_name_;
> +  SmfImmApplierHdl *ApplierHdl_;
> +
> +  DELETE_COPY_AND_MOVE_OPERATORS(SmfLongDnApplier);
> +};
> +
> +#endif /* SMFIMMAPPLIER_HH */
> +
> diff --git a/osaf/services/saf/smfsv/smfd/SmfUtils.cc 
> b/osaf/services/saf/smfsv/smfd/SmfUtils.cc
> --- a/osaf/services/saf/smfsv/smfd/SmfUtils.cc
> +++ b/osaf/services/saf/smfsv/smfd/SmfUtils.cc
> @@ -35,6 +35,7 @@
>   #include <algorithm>
>   
>   #include "osaf_extended_name.h"
> +#include "smfd_long_dn.hh"
>   #include "osaf_time.h"
>   #include "logtrace.h"
>   #include "SmfUtils.hh"
> @@ -337,9 +338,9 @@ SmfImmUtils::getObject(const std::string
>       SaAisErrorT rc = SA_AIS_OK;
>       SaNameT objectName;
>   
> -        if (i_dn.length() > smfd_cb->maxDnLength) {
> +        if (i_dn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("getObject error, dn too long (%zu), max %zu",
> -                        i_dn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                        i_dn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()));
>               return false;
>           }
>   
> @@ -364,9 +365,9 @@ SmfImmUtils::getObjectAisRC(const std::s
>       SaAisErrorT rc = SA_AIS_OK;
>       SaNameT objectName;
>   
> -        if (i_dn.length() > smfd_cb->maxDnLength) {
> +        if (i_dn.length() > GetSmfMaxDnLength()) {
>               LOG_NO("getObjectAisRC error, dn too long (%zu), max %zu",
> -                        i_dn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                        i_dn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()));
>               return SA_AIS_ERR_NAME_TOO_LONG;
>           }
>   
> @@ -406,9 +407,9 @@ SmfImmUtils::getChildren(const std::stri
>       TRACE_ENTER();
>   
>       if (i_dn.size() > 0) {
> -                if (i_dn.length() > smfd_cb->maxDnLength) {
> +                if (i_dn.length() > GetSmfMaxDnLength()) {
>                           LOG_NO("getChildren error, dn too long (%zu), max 
> %zu",
> -                                i_dn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                                i_dn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()));
>                           return false;
>                   }
>   
> @@ -490,9 +491,9 @@ SmfImmUtils::getChildrenAndAttrBySearchH
>       TRACE_ENTER();
>   
>       if (i_dn.size() > 0) {
> -                if (i_dn.length() > smfd_cb->maxDnLength) {
> +                if (i_dn.length() > GetSmfMaxDnLength()) {
>                           LOG_NO("getChildren error, dn too long (%zu), max 
> %zu",
> -                                i_dn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                                i_dn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()));
>                       rc =  false;
>                       goto done;
>                   }
> @@ -556,9 +557,9 @@ SmfImmUtils::callAdminOperation(const st
>       SaNameT objectName;
>       int retry          = 100;
>   
> -        if (i_dn.length() > smfd_cb->maxDnLength) {
> +        if (i_dn.length() > GetSmfMaxDnLength()) {
>                   LOG_NO("callAdminOperation error, dn too long (%zu), max 
> %zu",
> -                        i_dn.length(), 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                        i_dn.length(), 
> static_cast<size_t>(GetSmfMaxDnLength()));
>                   return SA_AIS_ERR_NAME_TOO_LONG;
>           }
>   
> @@ -739,64 +740,6 @@ SmfImmUtils::nodeToClmNode(const std::st
>   
>           return true;
>   }
> -//------------------------------------------------------------------------------
> -// Reads IMM configuration data for long DNs and sets cb data structure
> -//------------------------------------------------------------------------------
> -bool
> -SmfImmUtils::read_IMM_long_DN_config_and_set_control_block(smfd_cb_t * cb)
> -{
> -     TRACE_ENTER();
> -
> -     //here is the only place where "kOsafMaxDnLength" constant is directly 
> used
> -     uint32_t maxDnLength = kOsafMaxDnLength;
> -
> -     /* First check if long DNs already enabled.
> -      * If enabled then there is no need to check it again,
> -      * since once it is enabled, is never turned off again.
> -      */
> -     if(cb->maxDnLength == maxDnLength) {
> -             TRACE("read_IMM_long_DN_config_and_set_control_block(): "
> -                 "Long DNs already enabled");
> -             TRACE_LEAVE();
> -             return true;
> -     }
> -
> -     /* Set the default value first,
> -      * to make sure that a value is set,
> -      * even if this function fails to get the config from IMM.
> -      */
> -     //cb->maxDnLength = DEFAULT_MAX_DN_LENGTH;
> -     cb->maxDnLength = SA_MAX_UNEXTENDED_NAME_LENGTH - 1;
> -
> -     SaImmAttrValuesT_2 **attributes;
> -
> -     if(getObject(IMM_CONFIG_OBJECT_DN, &attributes) == false) {
> -                LOG_ER("Could not get IMM config object from IMM %s",
> -                    IMM_CONFIG_OBJECT_DN);
> -                TRACE_LEAVE();
> -                return false;
> -     }
> -
> -     const SaUint32T *longDnsAllowed = immutil_getUint32Attr(
> -             (const SaImmAttrValuesT_2 **)attributes,
> -             IMM_LONG_DN_CONFIG_ATTRIBUTE_NAME, 0);
> -     if(longDnsAllowed) {
> -             TRACE("%s=%u", IMM_LONG_DN_CONFIG_ATTRIBUTE_NAME, 
> *longDnsAllowed);
> -             if(*longDnsAllowed == 0) {
> -                     cb->maxDnLength = SA_MAX_UNEXTENDED_NAME_LENGTH - 1;
> -             }
> -             else {
> -                     cb->maxDnLength = maxDnLength;
> -             }
> -     } else {
> -             LOG_NO("Could not get long DN config [%s %s], "
> -                 "use default DN length",
> -                     IMM_LONG_DN_CONFIG_ATTRIBUTE_NAME, 
> IMM_CONFIG_OBJECT_DN);
> -     }
> -
> -     TRACE_LEAVE();
> -     return true;
> -}
>   
>   // 
> ------------------------------------------------------------------------------
>   // smf_stringToImmType()
> @@ -952,9 +895,9 @@ smf_stringToValue(SaImmValueTypeT i_type
>           case SA_IMM_ATTR_SANAMET:
>                   len = strlen(i_str);
>   
> -                if (len > smfd_cb->maxDnLength) {
> +                if (len > GetSmfMaxDnLength()) {
>                           LOG_NO("smf_stringToValue error, SaNameT value too 
> long (%zu), max %zu",
> -                                len, 
> static_cast<size_t>(smfd_cb->maxDnLength));
> +                                len, 
> static_cast<size_t>(GetSmfMaxDnLength()));
>                           return false;
>                   }
>   
> diff --git a/osaf/services/saf/smfsv/smfd/SmfUtils.hh 
> b/osaf/services/saf/smfsv/smfd/SmfUtils.hh
> --- a/osaf/services/saf/smfsv/smfd/SmfUtils.hh
> +++ b/osaf/services/saf/smfsv/smfd/SmfUtils.hh
> @@ -194,13 +194,6 @@ class SmfImmUtils {
>   /// @return  True if successful, otherwise false
>   ///
>     bool nodeToClmNode(const std::string& i_node, std::string& o_clmNode);
> -
> -///
> -/// Purpose: Read long DN information from IMM
> -/// @param   cb is the SMF control block
> -/// @return  True if successful, otherwise false
> -///
> -  bool read_IMM_long_DN_config_and_set_control_block(smfd_cb_t * cb);
>   
>    private:
>       bool initialize(void);
> diff --git a/osaf/services/saf/smfsv/smfd/smfd.h 
> b/osaf/services/saf/smfsv/smfd/smfd.h
> --- a/osaf/services/saf/smfsv/smfd/smfd.h
> +++ b/osaf/services/saf/smfsv/smfd/smfd.h
> @@ -76,7 +76,7 @@ extern "C" {
>       extern const SaNameT *smfApplDN;
>       extern uint32_t initialize_for_assignment(smfd_cb_t *cb,
>               SaAmfHAStateT ha_state);
> -     extern uint32_t smfd_amf_init(smfd_cb_t *);
> +     extern SaAisErrorT smfd_amf_init(smfd_cb_t *cb);
>       extern uint32_t smfd_mds_init(smfd_cb_t *);
>       extern uint32_t smfd_mds_finalize(smfd_cb_t *);
>       extern uint32_t smfd_mds_change_role(smfd_cb_t *);
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_amf.c 
> b/osaf/services/saf/smfsv/smfd/smfd_amf.cc
> rename from osaf/services/saf/smfsv/smfd/smfd_amf.c
> rename to osaf/services/saf/smfsv/smfd/smfd_amf.cc
> --- a/osaf/services/saf/smfsv/smfd/smfd_amf.c
> +++ b/osaf/services/saf/smfsv/smfd/smfd_amf.cc
> @@ -20,6 +20,7 @@
>    */
>   
>   #include "smfd.h"
> +#include "smfd_long_dn.hh"
>   
>   
> /****************************************************************************
>    * Name          : amf_active_state_handler
> @@ -59,6 +60,10 @@ static SaAisErrorT amf_active_state_hand
>               rc = SA_AIS_ERR_FAILED_OPERATION;
>       }
>   
> +        // Start the long Dn monotoring applier
> +     TRACE("%s: SmfLongDnInfo->Start()", __FUNCTION__);
> +     SmfLongDnInfo->Start();
> +
>       TRACE_LEAVE();
>       return rc;
>   }
> @@ -130,22 +135,27 @@ static SaAisErrorT amf_quiesced_state_ha
>   {
>       TRACE_ENTER();
>       V_DEST_RL mds_role;
> -     SaAisErrorT rc = SA_AIS_OK;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +        uint32_t ncscc_rc = NCSCC_RC_SUCCESS;
>   
>       /* Terminate threads and finalize the OI handle */
>       if (campaign_oi_deactivate(cb) != NCSCC_RC_SUCCESS) {
>               LOG_NO("amf_quiesced_state_handler oi deactivate FAILED, 
> continue");
>       }
>   
> +     // Stop the long Dn monitoring applier
> +     TRACE("%s: SmfLongDnInfo->Stop()", __FUNCTION__);
> +     SmfLongDnInfo->Stop();
> +
>       /*
>        ** Change the MDS VDSET role to Quiesced. Wait for MDS callback with 
> type
>        ** MDS_CALLBACK_QUIESCED_ACK. Don't change cb->ha_state now.
>        */
>       mds_role = cb->mds_role;
>       cb->mds_role = V_DEST_RL_QUIESCED;
> -     if ((rc = smfd_mds_change_role(cb)) != NCSCC_RC_SUCCESS) {
> +     if ((ncscc_rc = smfd_mds_change_role(cb)) != NCSCC_RC_SUCCESS) {
>               LOG_ER("smfd_mds_change_role [V_DEST_RL_QUIESCED] FAILED");
> -             rc = SA_AIS_ERR_FAILED_OPERATION;
> +             ais_rc = SA_AIS_ERR_FAILED_OPERATION;
>               cb->mds_role = mds_role;
>               goto done;
>       }
> @@ -154,7 +164,7 @@ static SaAisErrorT amf_quiesced_state_ha
>       cb->is_quiesced_set = true;
>   done:
>       TRACE_LEAVE();
> -     return rc;
> +     return ais_rc;
>   }
>   
>   
> /****************************************************************************
> @@ -405,7 +415,7 @@ static SaAisErrorT amf_healthcheck_start
>              SA_AIS_ERR_* - failure
>   
>   **************************************************************************/
> -SaAisErrorT smfd_amf_init(smfd_cb_t * cb)
> +SaAisErrorT smfd_amf_init(smfd_cb_t *cb)
>   {
>       SaAmfCallbacksT amfCallbacks;
>       SaVersionT amf_version;
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_campaign_oi.cc 
> b/osaf/services/saf/smfsv/smfd/smfd_campaign_oi.cc
> --- a/osaf/services/saf/smfsv/smfd/smfd_campaign_oi.cc
> +++ b/osaf/services/saf/smfsv/smfd/smfd_campaign_oi.cc
> @@ -84,16 +84,6 @@ static void saImmOiAdminOperationCallbac
>               goto done;
>       }
>   
> -       //Read IMM configuration for long DNs and set cb data structure
> -       //There is chance that long DN is configured in IMM not in SMF config 
> object
> -        TRACE("2. %s: 
> read_IMM_long_DN_config_and_set_control_block()",__FUNCTION__);
> -        if (!immutil.read_IMM_long_DN_config_and_set_control_block(smfd_cb)) 
> {
> -                LOG_ER("read_IMM_long_DN_config_and_set_control_block FAIL");
> -             (void)immutil_saImmOiAdminOperationResult(immOiHandle, 
> invocation, SA_AIS_ERR_INVALID_PARAM);
> -             goto done;
> -        }
> -
> -
>       /* Call admin operation and return result */
>       rc = campaign->adminOperation(opId, params);
>   
> @@ -907,14 +897,6 @@ uint32_t read_config_and_set_control_blo
>       SmfImmUtils immutil;
>       SaImmAttrValuesT_2 **attributes;
>   
> -     //Read IMM configuration for long DNs and set cb data structure
> -        //The long DN info is configured in IMM not in SMF config object
> -        TRACE("1. %s: 
> read_IMM_long_DN_config_and_set_control_block()",__FUNCTION__);
> -     if (!immutil.read_IMM_long_DN_config_and_set_control_block(cb)) {
> -             LOG_ER("read_IMM_long_DN_config_and_set_control_block FAIL");
> -             return NCSCC_RC_FAILURE;
> -     }
> -
>       if (immutil.getObject(SMF_CONFIG_OBJECT_DN, &attributes) == false) {
>               LOG_ER("Could not get SMF config object from IMM %s", 
> SMF_CONFIG_OBJECT_DN);
>               return NCSCC_RC_FAILURE;
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_cb.h 
> b/osaf/services/saf/smfsv/smfd/smfd_cb.h
> --- a/osaf/services/saf/smfsv/smfd/smfd_cb.h
> +++ b/osaf/services/saf/smfsv/smfd/smfd_cb.h
> @@ -69,8 +69,7 @@ typedef struct smfd_cb {
>       uint32_t no_of_smfnd;
>       pthread_mutex_t lock;                     /* Used by smfd_cb_t 
> lock/unlock functions */
>       pthread_mutex_t imm_lock;                 /* Used when IMM OI handle is 
> shared between campaign thread and main thread*/
> -     uint32_t maxDnLength;                     /* Max DN length */
> -        bool long_dn_allowed;
> +
>   } smfd_cb_t;
>   
>   #ifdef __cplusplus
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_evt.h 
> b/osaf/services/saf/smfsv/smfd/smfd_evt.h
> --- a/osaf/services/saf/smfsv/smfd/smfd_evt.h
> +++ b/osaf/services/saf/smfsv/smfd/smfd_evt.h
> @@ -18,6 +18,13 @@
>   #ifndef SMFD_EVT_H
>   #define SMFD_EVT_H
>   
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
>   void smfd_process_mbx(SYSF_MBX * mbx);
>   
> +#ifdef __cplusplus
> +}
> +#endif
>   #endif                              /* SMFD_EVT_H */
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_long_dn.hh 
> b/osaf/services/saf/smfsv/smfd/smfd_long_dn.hh
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/smfsv/smfd/smfd_long_dn.hh
> @@ -0,0 +1,58 @@
> +/*       OpenSAF
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "SmfLongDnApplier.hh"
> +#include "osaf_extended_name.h"
> +
> +#ifndef SMFD_LONG_DN_HH
> +#define SMFD_LONG_DN_HH
> +
> +     /* Store for SmfLongDnApplier. Must live as long as the process lives
> +      * See smfd_main.cc
> +      */
> +     extern SmfLongDnApplier *SmfLongDnInfo;
> +
> +        /* This inline function replaces the maxDnLength variable in the
> +         * smfd_cb structure that was updated in some places in the code by
> +         * specifically reading the long dn setting in the IMM config object.
> +         * This function will instead return a value corresponding to
> +         * maxDnLength based on the same long dn setting but that is 
> monitored
> +         * using an IMM applier
> +         * NOTE:
> +         * I there is no applier or applier is not working, SmfMaxDnLength 
> will
> +         * return the length corresponding to that long dn is not allowed.
> +         */
> +        static inline uint32_t GetSmfMaxDnLength(void) {
> +          // here is the only place where "kOsafMaxDnLength" constant is
> +          // directly used
> +          uint32_t maxDnLength_long = kOsafMaxDnLength;
> +          uint32_t maxDnLength_short = SA_MAX_UNEXTENDED_NAME_LENGTH - 1;
> +
> +          if (SmfLongDnInfo == nullptr) {
> +            return maxDnLength_short;
> +          }
> +
> +          if (SmfLongDnInfo->getValue() == true) {
> +            return maxDnLength_long;
> +          } else {
> +            return maxDnLength_short;
> +          }
> +        }
> +
> +
> +#endif /* SMFD_LONG_DN_HH */
> +
> diff --git a/osaf/services/saf/smfsv/smfd/smfd_main.c 
> b/osaf/services/saf/smfsv/smfd/smfd_main.cc
> rename from osaf/services/saf/smfsv/smfd/smfd_main.c
> rename to osaf/services/saf/smfsv/smfd/smfd_main.cc
> --- a/osaf/services/saf/smfsv/smfd/smfd_main.c
> +++ b/osaf/services/saf/smfsv/smfd/smfd_main.cc
> @@ -23,7 +23,7 @@
>   
>   #include <configmake.h>
>   
> -#define _GNU_SOURCE
> +//#define _GNU_SOURCE
>   #include <string.h>
>   #include <stdio.h>
>   #include <stdlib.h>
> @@ -43,6 +43,7 @@
>   #include "smfd.h"
>   #include "smfsv_defs.h"
>   #include "smfd_evt.h"
> +#include "smfd_long_dn.hh"
>   
>   /* ========================================================================
>    *   DEFINITIONS
> @@ -63,6 +64,9 @@ extern struct ImmutilWrapperProfile immu
>   static smfd_cb_t smfd_cb_instance;
>   smfd_cb_t *smfd_cb = &smfd_cb_instance;
>   
> +/* Store for Long Dn monitoring applier object */
> +SmfLongDnApplier *SmfLongDnInfo;
> +
>   static SaNameT smfApplDN_instance;
>   
>   static void smfApplDN_instance_constructor(void) __attribute__ 
> ((constructor));
> @@ -284,6 +288,12 @@ static uint32_t initialize_smfd(void)
>               goto done;
>       }
>   
> +        /* Create a long dn monitoring applier */
> +        SmfLongDnInfo = new SmfLongDnApplier(IMM_CONFIG_OBJECT_DN,
> +                                             
> IMM_LONG_DN_CONFIG_ATTRIBUTE_NAME);
> +        TRACE("%s: Create applier for long Dn setting", __FUNCTION__);
> +        SmfLongDnInfo->Create();
> +
>    done:
>       TRACE_LEAVE();
>       return (rc);
> @@ -360,7 +370,6 @@ static void main_process(void)
>       fds[SMFD_COI_FD].events = POLLIN;
>   
>       while (1) {
> -
>               if (smfd_cb->campaignOiHandle != 0) {
>                       fds[SMFD_COI_FD].fd = smfd_cb->campaignSelectionObject;
>                       fds[SMFD_COI_FD].events = POLLIN;


------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today.http://sdm.link/xeonphi
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to