Hi Mahesh, As we did parallel implementations for two separated ticket #2146 & #2258, and pushing the codes independently, it is inconvenience or cannot use same MBCSV version for both.
Regards, Vu > -----Original Message----- > From: A V Mahesh [mailto:[email protected]] > Sent: Friday, February 24, 2017 1:41 PM > To: Vu Minh Nguyen <[email protected]>; > [email protected]; [email protected] > Cc: [email protected] > Subject: Re: [PATCH 1 of 2] log: add alternative destinations of log records > [#2258] > > Hi Vu/Lennart, > > On 2/24/2017 7:38 AM, Vu Minh Nguyen wrote: > > #define LGS_MBCSV_VERSION_6 6 > > +#define LGS_MBCSV_VERSION_7 7 > > In one release 5.2 and 2 enhancement #2146 & #2258, why they are > using two different > LGS_MBCSV_VERSION = 6 & LGS_MBCSV_VERSION = 7 , #2146 & #2258 > both > can use sing LGS_MBCSV_VERSION = 6 > > -AVM > > > On 2/24/2017 7:38 AM, Vu Minh Nguyen wrote: > > src/log/Makefile.am | 14 +- > > src/log/config/logsv_classes.xml | 7 +- > > src/log/logd/lgs_common.h | 81 +++++++ > > src/log/logd/lgs_config.cc | 173 ++++++++++++++- > > src/log/logd/lgs_config.h | 3 +- > > src/log/logd/lgs_dest.cc | 409 > ++++++++++++++++++++++++++++++++++++++ > > src/log/logd/lgs_dest.h | 294 +++++++++++++++++++++++++++ > > src/log/logd/lgs_evt.cc | 32 ++ > > src/log/logd/lgs_imm.cc | 211 ++++++++++++++++--- > > src/log/logd/lgs_main.cc | 11 +- > > src/log/logd/lgs_mbcsv.cc | 230 +++++++++++++++++---- > > src/log/logd/lgs_mbcsv.h | 5 +- > > src/log/logd/lgs_mbcsv_v5.cc | 10 + > > src/log/logd/lgs_mbcsv_v7.cc | 177 ++++++++++++++++ > > src/log/logd/lgs_mbcsv_v7.h | 66 ++++++ > > src/log/logd/lgs_nildest.cc | 153 ++++++++++++++ > > src/log/logd/lgs_nildest.h | 72 ++++++ > > src/log/logd/lgs_stream.cc | 62 +++++- > > src/log/logd/lgs_stream.h | 16 + > > src/log/logd/lgs_unixsock_dest.cc | 343 > +++++++++++++++++++++++++++++++ > > src/log/logd/lgs_unixsock_dest.h | 245 ++++++++++++++++++++++ > > src/log/logd/lgs_util.cc | 34 +++ > > src/log/logd/lgs_util.h | 11 +- > > 23 files changed, 2550 insertions(+), 109 deletions(-) > > > > > > Here are major info, detailed info will be added to PR doc soon. > > 1) Add attribute "saLogRecordDestination" to log stream. > > 2) Add Local socket destintion handler > > 3) Add NILDEST destination type > > 4) Integrate into first increment made by Lennart > > > > diff --git a/src/log/Makefile.am b/src/log/Makefile.am > > --- a/src/log/Makefile.am > > +++ b/src/log/Makefile.am > > @@ -73,9 +73,15 @@ noinst_HEADERS += \ > > src/log/logd/lgs_mbcsv_v3.h \ > > src/log/logd/lgs_mbcsv_v5.h \ > > src/log/logd/lgs_mbcsv_v6.h \ > > + src/log/logd/lgs_mbcsv_v7.h \ > > src/log/logd/lgs_recov.h \ > > src/log/logd/lgs_stream.h \ > > - src/log/logd/lgs_util.h > > + src/log/logd/lgs_util.h \ > > + src/log/logd/lgs_dest.h \ > > + src/log/logd/lgs_nildest.h \ > > + src/log/logd/lgs_unixsock_dest.h \ > > + src/log/logd/lgs_common.h > > + > > > > bin_PROGRAMS += bin/saflogger > > osaf_execbin_PROGRAMS += bin/osaflogd > > @@ -120,10 +126,14 @@ bin_osaflogd_SOURCES = \ > > src/log/logd/lgs_mbcsv_v3.cc \ > > src/log/logd/lgs_mbcsv_v5.cc \ > > src/log/logd/lgs_mbcsv_v6.cc \ > > + src/log/logd/lgs_mbcsv_v7.cc \ > > src/log/logd/lgs_mds.cc \ > > src/log/logd/lgs_recov.cc \ > > src/log/logd/lgs_stream.cc \ > > - src/log/logd/lgs_util.cc > > + src/log/logd/lgs_util.cc \ > > + src/log/logd/lgs_dest.cc \ > > + src/log/logd/lgs_nildest.cc \ > > + src/log/logd/lgs_unixsock_dest.cc > > > > bin_osaflogd_LDADD = \ > > lib/libosaf_common.la \ > > diff --git a/src/log/config/logsv_classes.xml > b/src/log/config/logsv_classes.xml > > --- a/src/log/config/logsv_classes.xml > > +++ b/src/log/config/logsv_classes.xml > > @@ -147,12 +147,13 @@ > > <category>SA_CONFIG</category> > > <flag>SA_WRITABLE</flag> > > </attr> > > - <attr> > > + <attr> > > <name>saLogRecordDestination</name> > > - <type>SA_UINT32_T</type> > > + <type>SA_STRING_T</type> > > <category>SA_CONFIG</category> > > <flag>SA_WRITABLE</flag> > > - <flag>SA_MULTI_VALUE</flag> > > + <flag>SA_MULTI_VALUE</flag> > > + <flag>SA_NO_DUPLICATES</flag> > > </attr> > > <attr> > > <name>saLogStreamCreationTimestamp</name> > > diff --git a/src/log/logd/lgs_common.h b/src/log/logd/lgs_common.h > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_common.h > > @@ -0,0 +1,81 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 > > + * > > + */ > > + > > +#ifndef SRC_LOG_LOGD_LGS_COMMON_H_ > > +#define SRC_LOG_LOGD_LGS_COMMON_H_ > > + > > +#include <string> > > +#include <vector> > > + > > +// Status of connection to destination > > +enum DestinationStatus { > > + // Destination is configured and is being connected to > > + kActive = 0, > > + // Destination is configured but not able to connected to > > + // or not given any configuration value. > > + kFailed = 1, > > +}; > > + > > +// This error code is introduced in alternative destination ticket #2258. > > +// and for now, only be used internally in lgs_dest files. > > +enum ErrCode { > > + // No error happens > > + kOk = 0, > > + // Error happens in general > > + kErr, > > + // Passing invalid parameters > > + kInvalid, > > + // Not able to serve the request as the requester is being busy > > + kBusy, > > + // The request is timeout > > + kTimeOut, > > + // No memory > > + kNoMem, > > + // The request/msg is drop as the precondition is not met > > + kDrop > > +}; > > + > > +// Type of modification on multiple attribute values. > > +// Introduce this own enum as (xvunguy) don't want to > > +// have dependent to IMM header file just because we need IMM > modification type. > > +// Their meanings are equivelent to `SaImmAttrModificationTypeT` > > +enum ModifyType { kAdd = 1, kDelete = 2, kReplace = 3 }; > > + > > +//> > > +// Define the "token" possition in destination configuration. > > +// Each destination configiration has format "name;type;value". > > +// After parsing, the output will put to the vector of strings > > +// with format {"name", "type", "value"}. > > +// kName : use this index to get "name" > > +// kType : use this index to get "type" > > +// kValue: use this index to get "value" > > +// kSize : this is the maximum size of the dest configuration vector. > > +//< > > +enum { kName = 0, kType, kValue, kSize }; > > + > > > +//============================================================ > ================== > > +// Two interfaces are published to outside world > > > +//============================================================ > ================== > > + > > +// Typedef for shorten declaration > > +// This type could be used to hold set of strings with formats > > +// 1) {"name;type;value", etc.} > > +// 2) {"name", "type", "value"} > > +// 3) etc. > > +using VectorString = std::vector<std::string>; > > + > > +#endif // SRC_LOG_LOGD_LGS_COMMON_H_ > > diff --git a/src/log/logd/lgs_config.cc b/src/log/logd/lgs_config.cc > > --- a/src/log/logd/lgs_config.cc > > +++ b/src/log/logd/lgs_config.cc > > @@ -709,36 +709,168 @@ static int lgs_cfg_verify_log_filesys_co > > return rc; > > } > > > > +//> > > +// Utility functions to validate destination configuration format > > +//< > > +// Typedef for shorten declaration > > +// This type could be used to hold set of strings with formats > > +// 1) {"name;type;value", etc.} > > +// 2) {"name", "type", "value"} > > +// 3) etc. > > +using VectorString = std::vector<std::string>; > > +//> > > +// Define the "token" possition in destination configuration. > > +// kName : use this index to get "name" token > > +// kType : use this index to get "type" token > > +// kValue: use this index to get "value" token > > +// kSize : this is the maximum size of the dest configuration vector. > > +//< > > +enum { kName = 0, kType, kValue, kSize }; > > +// Tokens seperator > > +const char kSemicolon[] = ";"; > > + > > + > > +// The format of destination must be one of followings: > > +// 1) "name;type;" > > +// 2) "name;type;value" > > +// So, in destination configuration, must have 02 semiconlons > > +// no more, no less. > > +// > > +bool is_right_destination_fmt(const VectorString& vdest) { > > + int nl_cnt = 0; > > + // Check each single destination > > + for (const auto& it : vdest) { > > + nl_cnt = std::count(it.begin(), it.end(), ';'); > > + if (nl_cnt != 2) { > > + TRACE("%s wrong destination format", __func__); > > + return false; > > + } > > + } > > + return true; > > +} > > + > > +// Return false if "name" token is invalid > > +bool is_name_valid(const VectorString& vdest) { > > + // Check each single destination > > + for (const auto& it : vdest) { > > + const VectorString sdes = logutil::Parser(it, kSemicolon); > > + if (sdes[kName].length() == 0) { > > + TRACE("%s wrong name format (name is empty value)", __func__); > > + return false; > > + } > > + // invalid name if having special characters in > > + if (logutil::isValidName(sdes[kName]) == false) { > > + TRACE("%s wrong name format (has special chars in)", __func__); > > + return false; > > + } > > + > > + if (sdes[kName].length() > 255) { > > + TRACE("%s too long name", __func__); > > + return false; > > + } > > + } > > + return true; > > +} > > + > > +// Return false if "type" token is invalid > > +bool is_type_valid(const VectorString& vdest) { > > + // Check each single destination > > + for (const auto& it : vdest) { > > + const VectorString sdes = logutil::Parser(it, kSemicolon); > > + if (sdes[kType].length() == 0) { > > + TRACE("%s wrong type format (type is empty value)", __func__); > > + return false; > > + } > > + // Only support type = "UNIX_SOCKET" > > + if (sdes[kType] != "UNIX_SOCKET" && sdes[kType] != "NILDEST") { > > + TRACE("%s wrong type format. Only UNIX_SOCKET and NILDEST > supported", > > + __func__); > > + return false; > > + } > > + } > > + return true; > > +} > > + > > +// Return true if no dulicated info, otherwise false. > > +bool is_no_config_duplicated(const VectorString& vdest, > > + const VectorString& vdes2) { > > + // Compare values of each pair of destinations. > > + for (const auto& it : vdest) { > > + const VectorString sdes = logutil::Parser(it, kSemicolon); > > + for (const auto& it2 : vdes2) { > > + if (it == it2) continue; > > + const VectorString sdes2 = logutil::Parser(it2, kSemicolon); > > + // Duplicate name > > + if (sdes2[kName] == sdes[kName]) { > > + TRACE("%s name is duplicated", __func__); > > + return false; > > + } > > + // Ignore nildest > > + if ((sdes[kValue].length() == 0) || (sdes2[kValue].length() == 0)) > > + continue; > > + // Duplicate "value" > > + if (sdes2[kValue] == sdes[kValue]) { > > + TRACE("%s value is duplicated", __func__); > > + return false; > > + } > > + } > > + } > > + return true; > > +} > > + > > +// Check whether there is duplicated "name" or "value" > > +// in provided @vdest and existing destinations > > +bool check_configuration_duplicated(const VectorString& vdest, > > + SaImmAttrModificationTypeT type) { > > + if (type == SA_IMM_ATTR_VALUES_DELETE) return true; > > + // No checking duplicated if replacing to one value > > + if (type == SA_IMM_ATTR_VALUES_REPLACE && vdest.size() < 2) return > true; > > + // Check in all replace values if any duplicated name/value > > + if (type == SA_IMM_ATTR_VALUES_REPLACE) { > > + // Check whethere there is duplicated "name" or "value" > > + // in list of provided destination configurations. > > + return is_no_config_duplicated(vdest, vdest); > > + } else { > > + bool isNoDuplicated = true; > > + // Check whethere there is duplicated "name" or "value" > > + // in adding destination configurations and existing ones. > > + // Firstly, check if any duplicate in added items. > > + if (vdest.size() > 1) { > > + isNoDuplicated = is_no_config_duplicated(vdest, vdest); > > + if (isNoDuplicated == false) return false; > > + } > > + // Secondly, check if any duplicate in added items with existing list. > > + return is_no_config_duplicated( > > + vdest, lgs_conf.logRecordDestinationConfiguration); > > + } > > +} > > + > > /** > > * Verify all values of log_record_destination_configuration > > * Rules: > > * - Empty string is Ok else > > - * - String shall have at least three fields separated by '\n' > > - * - First and second field cannot be empty > > + * - The destination configiration must be in right format > > + * - "name" token must be valid > > + * - "type" token must be valid > > + * - Must no duplicated info > > * > > * @param log_record_destination_configuration[in] > > * @return -1 on error > > */ > > int lgs_cfg_verify_log_record_destination_configuration( > > - std::vector<std::string>& log_record_destination_configuration) { > > - int rc = 0; > > - TRACE_ENTER(); > > - > > - int nl_cnt = 0; > > - for (auto& config : log_record_destination_configuration) { > > - // Verify that the string contains at least 2 ';' > > - nl_cnt = std::count(config.begin(), config.end(), ';'); > > - if (nl_cnt < 2) { > > - rc = -1; > > - break; > > - } > > - } > > - > > - TRACE_LEAVE2("rc = %s", rc == -1? "Fail": "Pass"); > > - return rc; > > + std::vector<std::string>& vdest, > > + SaImmAttrModificationTypeT type) { > > + // Allow deleting all destinations. > > + if (vdest.size() == 0) return true; > > + // It is important to keep the check in order > > + bool result = (is_right_destination_fmt(vdest) && > > + is_name_valid(vdest) && > > + is_type_valid(vdest) && > > + check_configuration_duplicated(vdest, type) > > + ); > > + return (result == true) ? (0) : (-1); > > } > > > > - > > /** > > * Verify logRootDirectory; path to be used as log root directory > > * Rules: > > @@ -846,7 +978,8 @@ static int verify_all_init() { > > } > > > > if (lgs_cfg_verify_log_record_destination_configuration( > > - lgs_conf.logRecordDestinationConfiguration) == -1) { > > + lgs_conf.logRecordDestinationConfiguration, > > + SA_IMM_ATTR_VALUES_ADD) == -1) { > > lgs_conf.logRecordDestinationConfiguration.clear(); > > lgs_conf.logRecordDestinationConfiguration_cnfflag = LGS_CNF_DEF; > > rc = -1; > > diff --git a/src/log/logd/lgs_config.h b/src/log/logd/lgs_config.h > > --- a/src/log/logd/lgs_config.h > > +++ b/src/log/logd/lgs_config.h > > @@ -304,7 +304,8 @@ int lgs_cfg_verify_mbox_limit(uint32_t h > > int lgs_cfg_verify_max_application_streams(uint32_t max_app_streams); > > int lgs_cfg_verify_file_io_timeout(uint32_t log_file_io_timeout); > > int lgs_cfg_verify_log_record_destination_configuration( > > - std::vector<std::string>& log_record_destination_configuration); > > + std::vector<std::string>& vdest, > > + SaImmAttrModificationTypeT type); > > /* > > * Functions for updating some parameters. Used to support check-point > before > > * version 5 > > diff --git a/src/log/logd/lgs_dest.cc b/src/log/logd/lgs_dest.cc > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_dest.cc > > @@ -0,0 +1,409 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 "log/logd/lgs_dest.h" > > + > > +#include <algorithm> > > + > > +#include "log/logd/lgs_util.h" > > +#include "log/logd/lgs_config.h" > > +#include "log/logd/lgs_nildest.h" > > +#include "log/logd/lgs_unixsock_dest.h" > > +#include "base/logtrace.h" > > +#include "base/hash.h" > > + > > +static const char kDelimeter[] = ";"; > > + > > > +//============================================================ > ================== > > +// DestinationHandler class > > > +//============================================================ > ================== > > +DestinationHandler DestinationHandler::me_; > > + > > +// Only support "kUnix" and "kNilDest" so far > > +DestinationHandler::DestType DestinationHandler::GetDestType( > > + const std::string& type) { > > + if (type == UnixSocketType::Type()) { > > + return DestType::kUnix; > > + } else if (type == NilDestType::Type()) { > > + return DestType::kNilDest; > > + } else { > > + LOG_NO("Unknown destination type %s", type.c_str()); > > + return DestType::kUnknown; > > + } > > +} > > + > > +std::string DestinationHandler::GenerateMsgId( > > + const std::string& dn, bool isRtStream) { > > + const std::string parent = ",safApp=safLogService"; > > + std::string msgid{""}; > > + size_t posa = 0, posb = 0; > > + > > + // Extract stream name from stream DN. > > + posa = dn.find('='); > > + if ((posb = dn.find(',')) == std::string::npos) { > > + posb = dn.length(); > > + } > > + std::string sname = dn.substr(posa + 1, posb - posa - 1); > > + > > + //> > > + // Rules to generate msgid string: > > + // 1) Use stream name (e.g: saLogSystem) + 'C'/'R' if it is not over 31 > chars > > + // and the stream DN contains the @parent ",safApp=safLogService"; > > + // Note: 'C' means configuration stream, 'R' means runtime stream. > > + // Why 31? It is due to MSGID field length limitation > > + // (max is 32 chars length). > > + // 2) Otherwise, generate a hash number from stream DN > > + // if stream name is over 31 chars. > > + //< > > + if (sname.length() < 32 && dn.find(parent) != std::string::npos) { > > + msgid = ((isRtStream == true) ? std::string{sname + 'R'} : > > + std::string{sname + 'C'}); > > + } else { > > + msgid = base::Hash(dn); > > + } > > + > > + return msgid; > > +} > > + > > +DestinationHandler::DestType DestinationHandler::ToDestType( > > + const std::string& name) { > > + if (nametype_map_.find(name) == nametype_map_.end()) > > + return DestType::kUnknown; > > + return nametype_map_[name]; > > +} > > + > > +void DestinationHandler::UpdateDestTypeDb( > > + const DestinationHandler::HandleMsg& msg) { > > + MsgType mtype = msg.type; > > + > > + switch (mtype) { > > + case MsgType::kCfgDest: { > > + const CfgDestMsg& cdest = msg.info.cfg; > > + TRACE("%s kCfgDest (%s)", __func__, cdest.name); > > + nametype_map_[std::string{cdest.name}] = > > + GetDestType(std::string{cdest.type}); > > + break; > > + } > > + > > + case MsgType::kDelDest: { > > + const DelDestMsg& deldest = msg.info.del; > > + TRACE("%s kDelDest (%s)", __func__, deldest.name); > > + nametype_map_.erase(std::string{deldest.name}); > > + break; > > + } > > + > > + case MsgType::kNoDest: { > > + TRACE("%s kNoDest", __func__); > > + for (auto& it : nametype_map_) nametype_map_.erase(it.first); > > + break; > > + } > > + > > + default: > > + LOG_WA("Unknown Dispatch message type (%d)", > static_cast<int>(mtype)); > > + break; > > + } > > +} > > + > > +ErrCode DestinationHandler::DispatchTo( > > + const DestinationHandler::HandleMsg& msg, > > + const std::string& name) { > > + ErrCode rc = ErrCode::kOk; > > + MsgType mtype = msg.type; > > + // All destinations has been deleted. Don't care of destination types. > > + // Delete all existing connections of all types. > > + if (mtype == MsgType::kNoDest) { > > + NilDestType::Instance().ProcessMsg(msg); > > + rc = UnixSocketType::Instance().ProcessMsg(msg); > > + // Update the destination names from @DestTypeDb > > + UpdateDestTypeDb(msg); > > + UpdateRtDestStatus(); > > + return rc; > > + } > > + > > + // Update the @DestTypeDb first before processing the > DestinationHandler msg. > > + // Otherwise, finding destination @type will result nothing. > > + // Then, the msg will be drop as no destination type found. > > + // But with @MsgType::kDelDest, updating should be last > > + // after fowarding the msg to @UnixSocketType. > > + // Otherwise, resource might be leaked (e.g: connection is not closed) > > + if (mtype == MsgType::kCfgDest) { > > + UpdateDestTypeDb(msg); > > + } > > + > > + DestType destType = ToDestType(name); > > + switch (destType) { > > + // Pass the DestinationHandler msg to Local Unix Domain > > + // socket destination type for further processing. > > + case DestType::kUnix: > > + rc = UnixSocketType::Instance().ProcessMsg(msg); > > + break; > > + > > + case DestType::kNilDest: > > + rc = NilDestType::Instance().ProcessMsg(msg); > > + break; > > + > > + default: > > + LOG_ER("Not support this destination type(%d), or no dest > configured!", > > + static_cast<int>(destType)); > > + rc = ErrCode::kDrop; > > + break; > > + } > > + > > + // Delete destination names from @DestTypeDb > > + if (mtype == MsgType::kDelDest) { > > + UpdateDestTypeDb(msg); > > + } > > + > > + UpdateRtDestStatus(); > > + return rc; > > +} > > + > > +// Update the `logRecordDestinationStatus` here whenever > > +// getting CfgDestination or WriteToDestination (?) > > +void DestinationHandler::UpdateRtDestStatus() { > > + VectorString vstatus = GetDestinationStatus(); > > + lgs_config_chg_t config_data = {NULL, 0}; > > + lgs_cfgupd_mutival_replace(LOG_RECORD_DESTINATION_STATUS, > > + vstatus, &config_data); > > + // Update configuration data store, no need to checkpoint the status to > stb. > > + int ret = lgs_cfg_update(&config_data); > > + if (ret == -1) { > > + LOG_WA("%s lgs_cfg_update Fail", __func__); > > + } > > +} > > + > > +void DestinationHandler::FormCfgDestMsg( > > + const std::string& dest, CfgDestMsg* msg) { > > + osafassert(msg != nullptr); > > + const VectorString tmp = logutil::Parser(dest, kDelimeter); > > + strncpy(msg->name, tmp[kName].c_str(), kMaxChar); > > + if (tmp.size() > 1) { > > + strncpy(msg->type, tmp[kType].c_str(), kMaxChar); > > + } > > + if (tmp.size() == kSize) > > + strncpy(msg->value, tmp[kValue].c_str(), kMaxChar); > > +} > > + > > +void DestinationHandler::FormDelDestMsg( > > + const std::string& dest, DelDestMsg* msg) { > > + osafassert(msg != nullptr); > > + const VectorString tmp = logutil::Parser(dest, kDelimeter); > > + strncpy(msg->name, tmp[kName].c_str(), kMaxChar); > > +} > > + > > +bool DestinationHandler::VectorFind( > > + const VectorString& vec, const std::string name) { > > + return std::find(vec.begin(), vec.end(), name) != vec.end(); > > +} > > + > > +ErrCode DestinationHandler::AddDestConfig(const VectorString& vdest) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + CfgDestMsg cmsg; > > + // Go thought all destinations and configure one by one > > + for (unsigned i = 0; i < vdest.size(); i++) { > > + HandleMsg msg{}; > > + FormCfgDestMsg(vdest[i], &cmsg); > > + msg.type = MsgType::kCfgDest; > > + memcpy(&msg.info.cfg, &cmsg, sizeof(cmsg)); > > + ret = DispatchTo(msg, cmsg.name); > > + allcfgdests_map_.push_back(vdest[i]); > > + } > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode DestinationHandler::DelDestConfig(const VectorString& vdest) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + DelDestMsg dmsg; > > + // Go thought all destinations and configure one by one > > + for (unsigned i = 0; i < vdest.size(); i++) { > > + if (VectorFind(allcfgdests_map_, vdest[i]) == false) { > > + LOG_NO("Not have such dest configuration (%s)", vdest[i].c_str()); > > + ret = ErrCode::kDrop; > > + continue; > > + } > > + > > + HandleMsg msg{}; > > + FormDelDestMsg(vdest[i], &dmsg); > > + msg.type = MsgType::kDelDest; > > + memcpy(&msg.info.del, &dmsg, sizeof(dmsg)); > > + ret = DispatchTo(msg, dmsg.name); > > + // Remove deleted destination from internal database > > + allcfgdests_map_.erase(std::remove(allcfgdests_map_.begin(), > > + allcfgdests_map_.end(), vdest[i]), > > + allcfgdests_map_.end()); > > + } > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode DestinationHandler::DelAllCfgDest() { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + // Don't care destination name > > + const std::string name{""}; > > + HandleMsg msg{}; > > + msg.type = MsgType::kNoDest; > > + ret = DispatchTo(msg, name); > > + allcfgdests_map_.clear(); > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode DestinationHandler::ProcessCfgChange( > > + const VectorString& vdest, ModifyType type) { > > + ErrCode ret = ErrCode::kOk; > > + TRACE_ENTER(); > > + > > + // Case #1: perform all destination delete, but no existing at all. > > + if ((vdest.size() == 0) && (allcfgdests_map_.size() == 0)) { > > + return ErrCode::kOk; > > + } > > + > > + // Case #2: Delete all existing destinations > > + if ((vdest.size() == 0) && (allcfgdests_map_.size() != 0)) { > > + return DelAllCfgDest(); > > + } > > + > > + // Case #3: Delete destination configurations while no dest cfg yet > > + if ((type == ModifyType::kDelete) && > > + (vdest.size() != 0) && > > + (allcfgdests_map_.size() == 0)) { > > + return ErrCode::kDrop; > > + } > > + > > + // Case #4: Delete all destination configurations > > + if ((type == ModifyType::kDelete) && > > + (vdest.size() == 0) && > > + (allcfgdests_map_.size() != 0)) { > > + return DelAllCfgDest(); > > + } > > + > > + // Case #5: Delete all destinations but no one existing. > > + if ((type == ModifyType::kDelete) && > > + (vdest.size() == 0) && > > + (allcfgdests_map_.size() == 0)) { > > + return ErrCode::kDrop; > > + } > > + > > + switch (type) { > > + case ModifyType::kAdd: > > + // Add new destinations to existing destinations. > > + ret = AddDestConfig(vdest); > > + break; > > + > > + case ModifyType::kReplace: > > + // Step #1: Delete all existing destinations if any. > > + if (nametype_map_.size() != 0) { > > + DelAllCfgDest(); > > + } > > + // Step #2: Create new destinations > > + ret = AddDestConfig(vdest); > > + break; > > + > > + case ModifyType::kDelete: > > + ret = DelDestConfig(vdest); > > + break; > > + > > + default: > > + LOG_ER("Unknown modify type (%d)", static_cast<int>(type)); > > + ret = ErrCode::kErr; > > + break; > > + } > > + > > + TRACE_LEAVE2("ret = %d", static_cast<int>(ret)); > > + return ret; > > +} > > + > > +ErrCode DestinationHandler::ProcessWriteReq( > > + const RecordInfo& info, > > + const std::string& name) { > > + HandleMsg msg{}; > > + RecordMsg record; > > + > > + msg.type = MsgType::kSendRecord; > > + strncpy(record.name, name.c_str(), kMaxChar); > > + memcpy(&record.rec, &info, sizeof(RecordInfo)); > > + memcpy(&msg.info.rec, &record, sizeof(RecordMsg)); > > + return DispatchTo(msg, name); > > +} > > + > > +VectorString DestinationHandler::GetDestinationStatus() { > > + VectorString unixsock_type{}; > > + VectorString nildest_type{}; > > + // Go thought all 02 supported destination types > > + unixsock_type = UnixSocketType::Instance().GetAllDestStatus(); > > + nildest_type = NilDestType::Instance().GetAllDestStatus(); > > + unixsock_type.insert(unixsock_type.end(), nildest_type.begin(), > > + nildest_type.end()); > > + > > + return unixsock_type; > > +} > > + > > > +//============================================================ > ================== > > +// Exposed interfaces to outer world > > > +//============================================================ > ================== > > +bool CfgDestination(const VectorString& vdest, ModifyType type) { > > + return (DestinationHandler::Instance().ProcessCfgChange(vdest, type) == > > + ErrCode::kOk); > > +} > > + > > +bool WriteToDestination(const RecordData& data, > > + const VectorString& destnames) { > > + osafassert(data.name != nullptr && data.logrec != nullptr); > > + osafassert(data.hostname != nullptr && data.networkname != nullptr); > > + > > + if (destnames.size() == 0) { > > + TRACE("%s No destination goes with this stream (%s)", __func__, > data.name); > > + return true; > > + } > > + > > + bool ret = true; > > + DestinationHandler::RecordInfo info; > > + std::string networkname = (std::string{data.networkname}.length() > 0) ? > > + ("." + std::string {data.networkname}) : ""; > > + > > + // Origin is FQDN = <hostname>[.<networkname>] > > + // hostname = where the log record comes from (not active node) > > + const std::string origin = std::string {data.hostname} + networkname; > > + const std::string msgid = DestinationHandler::Instance().GenerateMsgId( > > + data.name, data.isRtStream); > > + > > + info.msgid = msgid.c_str(); > > + info.log_record = data.logrec; > > + info.record_id = data.recordId; > > + info.stream_dn = data.name; > > + info.app_name = data.appname; > > + info.severity = data.sev; > > + info.time = data.time; > > + info.origin = origin.c_str(); > > + > > + // Go thought all destination names and send to the destination > > + // that go with that destination name > > + for (const auto& destname : destnames) { > > + ret = (DestinationHandler::Instance().ProcessWriteReq(info, destname) > > + == ErrCode::kOk); > > + } > > + > > + return ret; > > +} > > + > > +VectorString GetDestinationStatus() { > > + return DestinationHandler::Instance().GetDestinationStatus(); > > +} > > diff --git a/src/log/logd/lgs_dest.h b/src/log/logd/lgs_dest.h > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_dest.h > > @@ -0,0 +1,294 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 > > + * > > + */ > > + > > +#ifndef SRC_LOG_LOGD_LGS_DEST_H_ > > +#define SRC_LOG_LOGD_LGS_DEST_H_ > > + > > +#include <string> > > +#include <map> > > + > > +#include "log/logd/lgs_common.h" > > +#include "base/time.h" > > + > > +//> > > +// @CfgDestination - Configure Destinations. > > +// @input vdest: a vector of destination configurations. > > +// @input type : modification type on destination configuration attribute. > > +// It has equivalent value to @SaImmAttrModificationTypeT. > > +// @return: true if everything is OK, otherwise false. > > +// > > +// Call this function in CCB modified apply callback context, > > +// when changes on configuration destination has been verified. > > +// @type could be ModifyType::kAdd, ModifyType::kReplace, or > ModifyType::kDelete > > +// > > +// E.g: > > +// 1) Case #1: create 02 new destinations (@type = ModifyType::kAdd) > > +// Then, @vdest should contain data {"a;b;c", "d;e;f"} > > +// 2) Case #2: modify one destinations. E.g: dest name @d -> @d1 > > +// Then, @type = ModifyType::kReplace and @vdest contains data > {"d1;e;f"} > > +// 3) Case #3: delete one destination. Eg: dest name @a > > +// Then, @type = ModifyType::kDelete and @vdest should contains > {"a;b;c"} > > +// 4) Case #4: delete all destinations > > +// Then, @type = ModifyType::kDelete and @vdest contains empty > vector {} > > +// > > +// The function will parse the provided data @vdest, getting > > +// destination @name, destination @type, @destination value if any. > > +// Then form the right handle msg, and forward it to right destination. > > +// > > +// This function is blocking. The caller will be blocked until > > +// the request is done. > > +//< > > +bool CfgDestination(const VectorString& vdest, ModifyType type); > > + > > +//> > > +// Carry necessary information to form RFC5424 syslog message. > > +// Aim to reduce number of parameter passing to @WriteToDestination > > +// @name : log stream distinguish name > > +// @logrec : log record that written to local log file > > +// @hostname : log record originator > > +// @networkname: network name > > +// @recordId : record id of @logrec > > +// @sev : severity of log record @logrec > > +// @time : Same timestamp as in the log record @logrec > > +//< > > +struct RecordData { > > + const char* name; > > + const char* logrec; > > + const char* hostname; > > + const char* networkname; > > + const char* appname; > > + bool isRtStream; > > + uint32_t recordId; > > + uint16_t sev; > > + timespec time; > > + > > + RecordData() : name{nullptr}, logrec{nullptr} > > + , hostname{nullptr} > > + , networkname{nullptr} > > + , appname{nullptr} > > + , isRtStream{false} > > + , recordId{0} > > + , sev{0} { > > + time = base::ReadRealtimeClock(); > > + } > > +}; > > + > > +//> > > +// @WriteToDestination - Write @data To Destinations > > +// @input: > > +// @data : Carry necessary infos including log record. > > +// @destnames: Destination names wants to send log record to. > > +// @return: true if successfully write to destinations. Oherwise, false. > > +// > > +// This function is blocking. The caller will be blocked until > > +// the request is done. > > +//< > > +bool WriteToDestination(const RecordData& data, > > + const VectorString& destnames); > > + > > +//> > > +// @GetDestinationStatus - Get all destination status > > +// @input : none > > +// @output: vector of destination status with format > > +// {"name,status", "name1,status", etc.} > > +//< > > +VectorString GetDestinationStatus(); > > + > > +//> > > +// @DestinationHandler class: Dispatch msg to right destination > > +// All msgs, if want to come to destination handlers, > > +// must go though the DestinationHandler via > > +// the interface DestinationHandler::DispachTo() > > +// > > +// Three kind of DestinationHandler messages supported. > > +// 1) Msg contains destination configurations such as > > +// destination name, destination type and info (local socket path). > > +// > > +// 2) Msg contains log record which is going to write to destination. > > +// Beside log record, msg may contain other info such as > > +// the stream name(DN) it writting to, log record severity, > > +// log record originator, log record id, or timestamp. > > +// > > +// 3) Msg contains destinations that is going to be deleted. > > +// This message may have list of deleted destination names. > > +// > > +// The proper order of DestinationHandler messages should be: > > +// (1) -> (2) -> (3) or (1) -> (3). > > +// > > +// So, if msg contains log record comes(2) to the DestinationHandler first > > +// somehow (this probably due to an coding hole, that does not > > +// have a good check before sending msg to Dispacher) before > > +// the configurating destination msg(1), the DestinationHandler will drop > > +// the message, and log info to syslog. > > +// The same to the case if deleting destination msg(3) comes first > > +// before configuring destination(1), that msg(3) will be drop > > +// and log info to syslog. > > +// > > +// According to information in that messages, the DestinationHandler > > +// will do its jobs: interpret the msg, take the right destination > > +// and transfer that the msg to the destination type for futher processing. > > +//< > > +class DestinationHandler { > > + public: > > + enum { kMaxChar = 255 }; > > + enum class DestType { kUnix = 0, kNilDest, kUnknown }; > > + //> > > + // Handle message types > > + // kSendRecord: for writing log record to destination(s). > > + // kCfgDest : for configuring destination(s). > > + // kDelDest : for deleting destination(s). > > + // kNoDest : for deleting all destination(s). > > + //< > > + enum class MsgType { kSendRecord = 0, kCfgDest, kDelDest, kNoDest }; > > + > > + //> > > + // RecordMsg hold necessary information to forming RFC5424 protocol. > > + // @severity : log severity of sent log record. > > + // @record_id : record id attached to sent log record. > > + // @hash : hash number generated from log stream name (DN) > > + // @time : time attached to log record. Using realtime if no set. > > + // @origin : node originator of the log record (host & network name). > > + // @log_record: the log record that writting to local file. > > + // @stream_dn : log stream name(DN). > > + //< > > + struct RecordInfo { > > + const char* stream_dn; > > + const char* msgid; > > + const char* origin; > > + const char* log_record; > > + const char* app_name; > > + uint16_t severity; > > + uint32_t record_id; > > + struct timespec time; > > + > > + // Set default value > > + RecordInfo() : stream_dn{nullptr} > > + , msgid{nullptr} > > + , origin{nullptr} > > + , log_record{nullptr} > > + , app_name{nullptr} > > + , severity{0} > > + , record_id{0} { > > + time = base::ReadRealtimeClock(); > > + } > > + }; > > + > > + //> > > + // @RecordMsg - send record @rec to destination name @name > > + // @name: destination name > > + // @rec : record message > > + //> > > + struct RecordMsg { > > + char name[kMaxChar]; > > + RecordInfo rec; > > + RecordMsg() : name{0}, rec{} {} > > + }; > > + > > + //> > > + // CfgDestMsg - holds information for one destination. > > + // @name : name of destination. > > + // @type : type of destination. > > + // @value: destination configuration > > + //< > > + struct CfgDestMsg { > > + char name[kMaxChar]; > > + char type[kMaxChar]; > > + char value[kMaxChar]; > > + // Clear the values of all types > > + CfgDestMsg() : name{0}, type{0}, value{0} {} > > + }; > > + > > + //> > > + // DelDestMsg - hold information for one destintaion name > > + // @name: refer to the destination name that is going to delete. > > + //< > > + struct DelDestMsg { > > + char name[kMaxChar]; > > + DelDestMsg() : name{0} {} > > + }; > > + > > + //> > > + // @HandleMsg - Dispatch message format > > + // @type: the value depends on @info > > + // 1) kSendRecord if @info is RecordMsg > > + // 2) kCfgDest if @info is CfgDestMsg > > + // 3) kDelDest if @info is DelDestMsg > > + // 4) kNoDest if not above > > + //< > > + struct HandleMsg { > > + MsgType type; > > + union { > > + RecordMsg rec; > > + CfgDestMsg cfg; > > + DelDestMsg del; > > + } info; > > + }; > > + > > + // Unique object instance of @DestinationHandler class > > + static DestinationHandler& Instance() { return me_; } > > + // Extract the stream name from stream DN > > + static std::string GenerateMsgId(const std::string&, bool); > > + > > + // Do destination configuration basing on input @vdest and @type. > > + ErrCode ProcessCfgChange(const VectorString& vdest, ModifyType > type); > > + // Do write log record @info to destinations @name > > + ErrCode ProcessWriteReq(const RecordInfo& info, const std::string& > name); > > + // Get all destination status with format > > + // {"name,status", "name1,status1", etc.} > > + VectorString GetDestinationStatus(); > > + > > + private: > > + // typedef, aim for shorten declaration > > + using NameTypeMap = std::map<std::string, DestType>; > > + DestinationHandler() : nametype_map_{} {} > > + ~DestinationHandler() {} > > + > > + // Dispatch the @HandleMsg msg to destination @name. > > + // Based on the destination @name, the method will find the right > > + // destination @type, then forward the message to for futher > processing. > > + ErrCode DispatchTo(const HandleMsg& msg, const std::string& name); > > + // Pack @CfgDestMsg from the string @dest which have pure format > > + // "name;type;value". > > + void FormCfgDestMsg(const std::string& dest, CfgDestMsg* msg); > > + // Pack @DelDestMsg basing on pure destination format > > + // "name;type;value". > > + void FormDelDestMsg(const std::string& dest, DelDestMsg* msg); > > + // Form @CfgDestMsg and dispatch the msg. > > + ErrCode AddDestConfig(const VectorString& vdest); > > + // Form @DelDestMsg and dispatch the msg. > > + ErrCode DelDestConfig(const VectorString& vdest); > > + // Form @kNoDest dispatch msg > > + ErrCode DelAllCfgDest(); > > + // Find name @name from @vec > > + bool VectorFind(const VectorString& vec, const std::string name); > > + // Return @DestType based on the destination string @type > > + DestType GetDestType(const std::string& type); > > + DestType ToDestType(const std::string& name); > > + // Update the @nametype_map_ whenever getting > > + // destination configuration change. > > + void UpdateDestTypeDb(const DestinationHandler::HandleMsg&); > > + // Update the `logRecordDestinationStatus` > > + void UpdateRtDestStatus(); > > + > > + // The map between destination @name and destination @type > > + NameTypeMap nametype_map_; > > + // Hold all existing destinations with pure format {"a;b;c", etc} > > + VectorString allcfgdests_map_; > > + static DestinationHandler me_; > > +}; > > + > > +#endif // SRC_LOG_LOGD_LGS_DEST_H_ > > diff --git a/src/log/logd/lgs_evt.cc b/src/log/logd/lgs_evt.cc > > --- a/src/log/logd/lgs_evt.cc > > +++ b/src/log/logd/lgs_evt.cc > > @@ -29,6 +29,7 @@ > > #include "lgs_imm_gcfg.h" > > #include "base/osaf_extended_name.h" > > #include "lgs_clm.h" > > +#include "lgs_dest.h" > > > > static uint32_t process_api_evt(lgsv_lgs_evt_t *evt); > > static uint32_t proc_lga_updn_mds_msg(lgsv_lgs_evt_t *evt); > > @@ -1282,6 +1283,8 @@ static uint32_t proc_write_log_async_msg > > void *ckpt_ptr; > > uint32_t max_logrecsize = 0; > > char node_name[_POSIX_HOST_NAME_MAX]; > > + RecordData data; > > + timespec time; > > > > memset(node_name, 0, _POSIX_HOST_NAME_MAX); > > strncpy(node_name, evt->node_name, _POSIX_HOST_NAME_MAX); > > @@ -1341,6 +1344,35 @@ static uint32_t proc_write_log_async_msg > > goto done; > > } > > > > + //> > > + // Has successfully written log record to file. > > + // Now, send to destination if any destination name set. > > + //< > > + > > + // Streaming not support on alarm/notif streams. > > + if ((stream->name == SA_LOG_STREAM_ALARM) || > > + (stream->name == SA_LOG_STREAM_NOTIFICATION)) { > > + goto checkpoint; > > + } > > + > > + // Packing Record data that carry necessary information > > + // to form RFC5424 syslog msg, then send to destination name(s). > > + data.name = stream->name.c_str(); > > + data.logrec = logOutputString; > > + data.hostname = node_name; > > + data.networkname = lgs_get_networkname().c_str(); > > + data.appname = osaf_extended_name_borrow( > > + param->logRecord->logHeader.genericHdr.logSvcUsrName); > > + data.isRtStream = stream->isRtStream; > > + data.recordId = stream->logRecordId; > > + data.sev = param->logRecord->logHeader.genericHdr.logSeverity; > > + time.tv_sec = (param->logRecord->logTimeStamp / > (SaTimeT)SA_TIME_ONE_SECOND); > > + time.tv_nsec = (param->logRecord->logTimeStamp % > (SaTimeT)SA_TIME_ONE_SECOND); > > + data.time = time; > > + > > + WriteToDestination(data, stream->dest_names); > > + > > +checkpoint: > > /* TODO: send fail back if ack is wanted, Fix counter for application > stream!! */ > > if (cb->ha_state == SA_AMF_HA_ACTIVE) { > > if (lgs_is_peer_v2()) { > > diff --git a/src/log/logd/lgs_imm.cc b/src/log/logd/lgs_imm.cc > > --- a/src/log/logd/lgs_imm.cc > > +++ b/src/log/logd/lgs_imm.cc > > @@ -45,12 +45,14 @@ > > #include "log/logd/lgs_file.h" > > #include "log/logd/lgs_recov.h" > > #include "log/logd/lgs_config.h" > > +#include "log/logd/lgs_dest.h" > > #include "base/saf_error.h" > > > > #include "lgs_mbcsv_v1.h" > > #include "lgs_mbcsv_v2.h" > > #include "lgs_mbcsv_v3.h" > > #include "lgs_mbcsv_v5.h" > > +#include "lgs_mbcsv_v7.h" > > > > /* TYPE DEFINITIONS > > * ---------------- > > @@ -234,11 +236,33 @@ static uint32_t ckpt_stream_config(log_s > > uint32_t rc; > > lgsv_ckpt_msg_v1_t ckpt_v1; > > lgsv_ckpt_msg_v2_t ckpt_v2; > > + lgsv_ckpt_msg_v7_t ckpt_v3; > > + > > void *ckpt_ptr; > > > > TRACE_ENTER(); > > > > - if (lgs_is_peer_v2()) { > > + if (lgs_is_peer_v7()) { > > + memset(&ckpt_v3, 0, sizeof(ckpt_v3)); > > + ckpt_v3.header.ckpt_rec_type = LGS_CKPT_CFG_STREAM; > > + ckpt_v3.header.num_ckpt_records = 1; > > + ckpt_v3.header.data_len = 1; > > + > > + ckpt_v3.ckpt_rec.stream_cfg.name = const_cast<char *>(stream- > >name.c_str()); > > + ckpt_v3.ckpt_rec.stream_cfg.fileName = const_cast<char *>(stream- > >fileName.c_str()); > > + ckpt_v3.ckpt_rec.stream_cfg.pathName = const_cast<char *>(stream- > >pathName.c_str()); > > + ckpt_v3.ckpt_rec.stream_cfg.maxLogFileSize = stream- > >maxLogFileSize; > > + ckpt_v3.ckpt_rec.stream_cfg.fixedLogRecordSize = stream- > >fixedLogRecordSize; > > + ckpt_v3.ckpt_rec.stream_cfg.logFullAction = stream->logFullAction; > > + ckpt_v3.ckpt_rec.stream_cfg.logFullHaltThreshold = stream- > >logFullHaltThreshold; > > + ckpt_v3.ckpt_rec.stream_cfg.maxFilesRotated = stream- > >maxFilesRotated; > > + ckpt_v3.ckpt_rec.stream_cfg.logFileFormat = stream->logFileFormat; > > + ckpt_v3.ckpt_rec.stream_cfg.severityFilter = stream->severityFilter; > > + ckpt_v3.ckpt_rec.stream_cfg.logFileCurrent = const_cast<char > *>(stream->logFileCurrent.c_str()); > > + ckpt_v3.ckpt_rec.stream_cfg.dest_names = const_cast<char > *>(stream->stb_dest_names.c_str()); > > + ckpt_v3.ckpt_rec.stream_cfg.c_file_close_time_stamp = stream- > >act_last_close_timestamp; > > + ckpt_ptr = &ckpt_v3; > > + } else if (lgs_is_peer_v2()) { > > memset(&ckpt_v2, 0, sizeof(ckpt_v2)); > > ckpt_v2.header.ckpt_rec_type = LGS_CKPT_CFG_STREAM; > > ckpt_v2.header.num_ckpt_records = 1; > > @@ -856,13 +880,14 @@ static SaAisErrorT config_ccb_completed_ > > // Note: Multi value attribute > > TRACE("logRecordDestinationConfiguration. Values number = %d", > > attribute->attrValuesNumber); > > - std::vector<std::string> values_vector; > > + std::vector<std::string> values_vector{}; > > for (uint32_t i=0; i < attribute->attrValuesNumber; i++) { > > value = attribute->attrValues[i]; > > char *value_str = *(reinterpret_cast<char **>(value)); > > values_vector.push_back(value_str); > > } > > - rc = > lgs_cfg_verify_log_record_destination_configuration(values_vector); > > + rc = lgs_cfg_verify_log_record_destination_configuration( > > + values_vector, attrMod->modType); > > if (rc == -1) { > > report_oi_error(immOiHandle, opdata->ccbId, > > "%s value is NOT accepted", attribute->attrName); > > @@ -1270,6 +1295,29 @@ done: > > return rc; > > } > > > > +static bool is_valid_dest_names(const std::vector<std::string>& names) { > > + // Stream has no destination name > > + if (names.size() == 0) return true; > > + for (const auto& name : names) { > > + // Empty destination name is invalid > > + if (name.empty() == true || name.size() == 0) { > > + TRACE("%s name is empty", __func__); > > + return false; > > + } > > + // Contain special characters is not allowed > > + if (logutil::isValidName(name) == false) { > > + TRACE("%s name has special chars in", __func__); > > + return false; > > + } > > + // Name is too long > > + if (name.length() > 255) { > > + TRACE("%s too long name", __func__); > > + return false; > > + } > > + } > > + return true; > > +} > > + > > /** > > * Validate input parameters creation and modify of a persistent stream > > * i.e. a stream that has a configuration object. > > @@ -1368,12 +1416,16 @@ static SaAisErrorT check_attr_validity(S > > if (attribute->attrValuesNumber > 0) { > > value = attribute->attrValues[0]; > > } else if (opdata->operationType == CCBUTIL_MODIFY) { > > - /* An attribute without a value is never valid if modify */ > > - report_oi_error(immOiHandle, opdata->ccbId, > > - "Attribute %s has no value",attribute->attrName); > > - TRACE("Modify: Attribute %s has no value",attribute->attrName); > > - rc = SA_AIS_ERR_BAD_OPERATION; > > - goto done; > > + if (!strcmp(attribute->attrName, "saLogRecordDestination")) { > > + // do nothing > > + } else { > > + /* An attribute without a value is never valid if modify */ > > + report_oi_error(immOiHandle, opdata->ccbId, > > + "Attribute %s has no value",attribute->attrName); > > + TRACE("Modify: Attribute %s has no value",attribute->attrName); > > + rc = SA_AIS_ERR_BAD_OPERATION; > > + goto done; > > + } > > } else { > > /* If create all attributes will be present also the ones without > > * any value. > > @@ -1428,8 +1480,24 @@ static SaAisErrorT check_attr_validity(S > > i_severityFilter_mod = true; > > TRACE("Saved attribute \"%s\" = %d", attribute->attrName, > > i_severityFilter); > > + } else if (!strcmp(attribute->attrName,"saLogRecordDestination")) { > > + std::vector<std::string> vstring{}; > > + for (unsigned i = 0; i < attribute->attrValuesNumber; i++) { > > + value = attribute->attrValues[i]; > > + char *value_str = *(reinterpret_cast<char **>(value)); > > + vstring.push_back(value_str); > > + } > > + if (is_valid_dest_names(vstring) == false) { > > + /* Report failed if has special character in file name */ > > + rc = SA_AIS_ERR_BAD_OPERATION; > > + report_oi_error(immOiHandle, opdata->ccbId, > > + "Invalid saLogRecordDestination value"); > > + TRACE("Invalid saLogRecordDestination value"); > > + goto done; > > + } > > } > > > > + > > /* Get next attribute or detect no more attributes */ > > next: > > if (opdata->operationType == CCBUTIL_CREATE) { > > @@ -1976,6 +2044,41 @@ static void apply_conf_logDataGroupname( > > logDataGroupname_fileown(value_ptr); > > } > > > > +static void apply_config_destinations_change( > > + const std::vector<std::string>& vdestcfg, > > + SaImmAttrModificationTypeT type, > > + lgs_config_chg_t* config_data) { > > + switch (type) { > > + case SA_IMM_ATTR_VALUES_ADD: > > + // Configure destinations > > + CfgDestination(vdestcfg, ModifyType::kAdd); > > + > lgs_cfgupd_multival_add(LOG_RECORD_DESTINATION_CONFIGURATION, > > + vdestcfg, > > + config_data); > > + break; > > + > > + case SA_IMM_ATTR_VALUES_DELETE: > > + // Configure destinations > > + CfgDestination(vdestcfg, ModifyType::kDelete); > > + > lgs_cfgupd_multival_delete(LOG_RECORD_DESTINATION_CONFIGURATION, > > + vdestcfg, > > + config_data); > > + break; > > + > > + case SA_IMM_ATTR_VALUES_REPLACE: > > + CfgDestination(vdestcfg, ModifyType::kReplace); > > + > lgs_cfgupd_mutival_replace(LOG_RECORD_DESTINATION_CONFIGURATION > , > > + vdestcfg, > > + config_data); > > + break; > > + > > + default: > > + // Shall never happen > > + LOG_ER("%s: Unknown modType %d", __FUNCTION__, type); > > + osafassert(0); > > + }; > > +} > > + > > /** > > * Apply changes. Validation is not needed here since all validation is done > in > > * the complete callback > > @@ -2090,28 +2193,9 @@ static void config_ccb_apply_modify(cons > > char *value_str = *(reinterpret_cast<char **>(value)); > > values_vector.push_back(value_str); > > } > > - > > - switch (attrMod->modType) { > > - case SA_IMM_ATTR_VALUES_ADD: > > - > lgs_cfgupd_multival_add(LOG_RECORD_DESTINATION_CONFIGURATION, > > - values_vector, > > - &config_data); > > - break; > > - case SA_IMM_ATTR_VALUES_DELETE: > > - > lgs_cfgupd_multival_delete(LOG_RECORD_DESTINATION_CONFIGURATION, > > - values_vector, > > - &config_data); > > - break; > > - case SA_IMM_ATTR_VALUES_REPLACE: > > - > lgs_cfgupd_mutival_replace(LOG_RECORD_DESTINATION_CONFIGURATION > , > > - values_vector, > > - &config_data); > > - break; > > - default: > > - // Shall never happen > > - LOG_ER("%s: Unknown modType %d", __FUNCTION__, attrMod- > >modType); > > - osafassert(0); > > - }; > > + apply_config_destinations_change(values_vector, > > + attrMod->modType, > > + &config_data); > > } > > > > attrMod = opdata->param.modify.attrMods[i++]; > > @@ -2252,6 +2336,15 @@ static SaAisErrorT stream_create_and_con > > } else if (!strcmp(ccb->param.create.attrValues[i]->attrName, > "saLogStreamSeverityFilter")) { > > (*stream)->severityFilter = *((SaUint32T *) value); > > TRACE("severityFilter: %u", (*stream)->severityFilter); > > + } else if (!strcmp(ccb->param.create.attrValues[i]->attrName, > > + "saLogRecordDestination")) { > > + std::vector<std::string> vstring{}; > > + for (unsigned ii = 0; ii < ccb->param.create.attrValues[i]- > >attrValuesNumber; ii++) { > > + value = ccb->param.create.attrValues[i]->attrValues[ii]; > > + char *value_str = *(reinterpret_cast<char **>(value)); > > + vstring.push_back(value_str); > > + } > > + log_stream_add_dest_name(*stream, vstring); > > } > > } > > i++; > > @@ -2306,6 +2399,30 @@ static void stream_ccb_apply_create(cons > > TRACE_LEAVE(); > > } > > > > +static void apply_destination_names_change( > > + log_stream_t* stream, > > + const std::vector<std::string>& destname, > > + SaImmAttrModificationTypeT type) { > > + switch (type) { > > + case SA_IMM_ATTR_VALUES_ADD: > > + log_stream_add_dest_name(stream, destname); > > + break; > > + > > + case SA_IMM_ATTR_VALUES_DELETE: > > + log_stream_delete_dest_name(stream, destname); > > + break; > > + > > + case SA_IMM_ATTR_VALUES_REPLACE: > > + log_stream_replace_dest_name(stream, destname); > > + break; > > + > > + default: > > + // Shall never happen > > + LOG_ER("%s: Unknown modType %d", __FUNCTION__, type); > > + osafassert(0); > > + } > > +} > > + > > static void stream_ccb_apply_modify(const CcbUtilOperationData_t > *opdata) { > > const SaImmAttrModificationT_2 *attrMod; > > int i = 0; > > @@ -2325,12 +2442,21 @@ static void stream_ccb_apply_modify(cons > > > > attrMod = opdata->param.modify.attrMods[i++]; > > while (attrMod != NULL) { > > - void *value; > > + void *value = nullptr; > > const SaImmAttrValuesT_2 *attribute = &attrMod->modAttr; > > > > TRACE("attribute %s", attribute->attrName); > > - > > - value = attribute->attrValues[0]; > > + if (attribute->attrValuesNumber != 0) { > > + value = attribute->attrValues[0]; > > + } else { > > + if (!strcmp(attribute->attrName, "saLogRecordDestination")) { > > + const std::vector<std::string> dname{}; > > + LOG_NO("%s deleted", __func__); > > + log_stream_delete_dest_name(stream, dname); > > + attrMod = opdata->param.modify.attrMods[i++]; > > + continue; > > + } > > + } > > > > if (!strcmp(attribute->attrName, "saLogStreamFileName")) { > > fileName = *((char **)value); > > @@ -2369,6 +2495,14 @@ static void stream_ccb_apply_modify(cons > > if (stream->streamType != STREAM_TYPE_ALARM && > > stream->streamType != STREAM_TYPE_NOTIFICATION) > > lgs_send_severity_filter_to_clients(stream->streamId, severityFilter); > > + } else if (!strcmp(attribute->attrName, "saLogRecordDestination")) { > > + std::vector<std::string> vstring{}; > > + for (unsigned i = 0; i < attribute->attrValuesNumber; i++) { > > + value = attribute->attrValues[i]; > > + char *value_str = *(reinterpret_cast<char **>(value)); > > + vstring.push_back(value_str); > > + } > > + apply_destination_names_change(stream, vstring, attrMod- > >modType); > > } else { > > LOG_ER("Error: Unknown attribute name"); > > osafassert(0); > > @@ -2620,6 +2754,7 @@ static SaAisErrorT stream_create_and_con > > const_cast<char *>("saLogStreamLogFullHaltThreshold"), > > const_cast<char *>("saLogStreamMaxFilesRotated"), > > const_cast<char *>("saLogStreamLogFileFormat"), > > + const_cast<char *>("saLogRecordDestination"), > > const_cast<char *>("saLogStreamSeverityFilter"), > > const_cast<char *>("saLogStreamCreationTimestamp"), > > NULL > > @@ -2703,6 +2838,14 @@ static SaAisErrorT stream_create_and_con > > } else if (!strcmp(attribute->attrName, "saLogStreamSeverityFilter")) { > > stream->severityFilter = *((SaUint32T *)value); > > TRACE("severityFilter: %u", stream->severityFilter); > > + } else if (!strcmp(attribute->attrName, "saLogRecordDestination")) { > > + std::vector<std::string> vstring{}; > > + for (unsigned i = 0; i < attribute->attrValuesNumber; i++) { > > + value = attribute->attrValues[i]; > > + char *value_str = *(reinterpret_cast<char **>(value)); > > + vstring.push_back(value_str); > > + } > > + log_stream_add_dest_name(stream, vstring); > > } else if (!strcmp(attribute->attrName, > "saLogStreamCreationTimestamp")) { > > if (attribute->attrValuesNumber != 0) { > > /* Restore creation timestamp if exist > > diff --git a/src/log/logd/lgs_main.cc b/src/log/logd/lgs_main.cc > > --- a/src/log/logd/lgs_main.cc > > +++ b/src/log/logd/lgs_main.cc > > @@ -1,6 +1,7 @@ > > -/* -*- OpenSAF -*- > > + /* -*- OpenSAF -*- > > * > > * (C) Copyright 2008-2010 The OpenSAF Foundation > > + * Copyright Ericsson AB 2018, 2017 - All Rights Reserved. > > * > > * This program is distributed in the hope that it will be useful, but > > * WITHOUT ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY > > @@ -39,6 +40,7 @@ > > #include "lgs_recov.h" > > #include "osaf/immutil/immutil.h" > > #include "lgs_clm.h" > > +#include "log/logd/lgs_dest.h" > > > > /* > ============================================================== > ========== > > * DEFINITIONS > > @@ -371,6 +373,7 @@ done: > > uint32_t initialize_for_assignment(lgs_cb_t *cb, SaAmfHAStateT ha_state) > { > > const char *logsv_root_dir = NULL; > > const char *logsv_data_groupname = NULL; > > + const std::vector<std::string> *vdest = nullptr; > > TRACE_ENTER2("ha_state = %d", (int) ha_state); > > uint32_t rc = NCSCC_RC_SUCCESS; > > > > @@ -393,6 +396,12 @@ uint32_t initialize_for_assignment(lgs_c > > logsv_data_groupname = static_cast<const char > *>(lgs_cfg_get(LGS_IMM_DATA_GROUPNAME)); > > LOG_NO("LOG root directory is: \"%s\"", logsv_root_dir); > > LOG_NO("LOG data group is: \"%s\"", logsv_data_groupname); > > + vdest = reinterpret_cast<const std::vector<std::string>*>( > > + > lgs_cfg_get(LGS_IMM_LOG_RECORD_DESTINATION_CONFIGURATION)); > > + osafassert(vdest != nullptr); > > + if (vdest->size() > 0) { > > + CfgDestination(*vdest, ModifyType::kAdd); > > + } > > > > /* Initialize file handling thread > > * Configuration must have been initialized > > diff --git a/src/log/logd/lgs_mbcsv.cc b/src/log/logd/lgs_mbcsv.cc > > --- a/src/log/logd/lgs_mbcsv.cc > > +++ b/src/log/logd/lgs_mbcsv.cc > > @@ -21,6 +21,9 @@ > > #include "base/ncssysf_mem.h" > > #include "base/osaf_time.h" > > > > +#include "osaf/immutil/immutil.h" > > +#include "log/logd/lgs_dest.h" > > +#include "log/logd/lgs_mbcsv_v7.h" > > #include "lgs_mbcsv_v6.h" > > #include "lgs_mbcsv_v5.h" > > #include "lgs_mbcsv_v3.h" > > @@ -125,43 +128,84 @@ uint32_t edp_ed_open_stream_rec(EDU_HDL > > EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, EDU_ERR > *o_err) { > > uint32_t rc = NCSCC_RC_SUCCESS; > > lgs_ckpt_stream_open_t *ckpt_open_stream_msg_ptr = NULL, > **ckpt_open_stream_msg_dec_ptr; > > + if (lgs_is_peer_v7()) { > > + EDU_INST_SET ckpt_open_stream_rec_ed_rules[] = { > > + {EDU_START, edp_ed_open_stream_rec, 0, 0, 0, > sizeof(lgs_ckpt_stream_open_t), 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamId, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->clientId, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFile, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logPath, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileCurrent, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->dest_names, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFileSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxLogRecordSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileFullAction, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFilesRotated, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->fileFmt, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logStreamName, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->creationTimeStamp, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->numOpeners, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamType, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logRecordId, 0, NULL}, > > + {EDU_END, 0, 0, 0, 0, 0, 0, NULL}, > > + }; > > > > - EDU_INST_SET ckpt_open_stream_rec_ed_rules[] = { > > - {EDU_START, edp_ed_open_stream_rec, 0, 0, 0, > sizeof(lgs_ckpt_stream_open_t), 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamId, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->clientId, 0, NULL}, > > - {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFile, 0, NULL}, > > - {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logPath, 0, NULL}, > > - {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileCurrent, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFileSize, 0, NULL}, > > - {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxLogRecordSize, 0, NULL}, > > - {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileFullAction, 0, NULL}, > > - {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFilesRotated, 0, NULL}, > > - {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->fileFmt, 0, NULL}, > > - {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logStreamName, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->creationTimeStamp, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->numOpeners, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamType, 0, NULL}, > > - {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logRecordId, 0, NULL}, > > - {EDU_END, 0, 0, 0, 0, 0, 0, NULL}, > > - }; > > + if (op == EDP_OP_TYPE_ENC) { > > + ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > + } else if (op == EDP_OP_TYPE_DEC) { > > + ckpt_open_stream_msg_dec_ptr = > static_cast<lgs_ckpt_stream_open_t **>(ptr); > > + if (*ckpt_open_stream_msg_dec_ptr == NULL) { > > + *o_err = EDU_ERR_MEM_FAIL; > > + return NCSCC_RC_FAILURE; > > + } > > + memset(*ckpt_open_stream_msg_dec_ptr, '\0', > sizeof(lgs_ckpt_stream_open_t)); > > + ckpt_open_stream_msg_ptr = *ckpt_open_stream_msg_dec_ptr; > > + } else { > > + ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > + } > > > > - if (op == EDP_OP_TYPE_ENC) { > > - ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > - } else if (op == EDP_OP_TYPE_DEC) { > > - ckpt_open_stream_msg_dec_ptr = static_cast<lgs_ckpt_stream_open_t > **>(ptr); > > - if (*ckpt_open_stream_msg_dec_ptr == NULL) { > > - *o_err = EDU_ERR_MEM_FAIL; > > - return NCSCC_RC_FAILURE; > > + rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, > ckpt_open_stream_rec_ed_rules, ckpt_open_stream_msg_ptr, > > + ptr_data_len, buf_env, op, o_err); > > + > > + } else { > > + EDU_INST_SET ckpt_open_stream_rec_ed_rules[] = { > > + {EDU_START, edp_ed_open_stream_rec, 0, 0, 0, > sizeof(lgs_ckpt_stream_open_t), 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamId, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->clientId, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFile, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logPath, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileCurrent, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFileSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxLogRecordSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logFileFullAction, 0, NULL}, > > + {EDU_EXEC, ncs_edp_int32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->maxFilesRotated, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->fileFmt, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logStreamName, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->creationTimeStamp, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->numOpeners, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->streamType, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_open_t > *)0)->logRecordId, 0, NULL}, > > + {EDU_END, 0, 0, 0, 0, 0, 0, NULL}, > > + }; > > + > > + if (op == EDP_OP_TYPE_ENC) { > > + ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > + } else if (op == EDP_OP_TYPE_DEC) { > > + ckpt_open_stream_msg_dec_ptr = > static_cast<lgs_ckpt_stream_open_t **>(ptr); > > + if (*ckpt_open_stream_msg_dec_ptr == NULL) { > > + *o_err = EDU_ERR_MEM_FAIL; > > + return NCSCC_RC_FAILURE; > > + } > > + memset(*ckpt_open_stream_msg_dec_ptr, '\0', > sizeof(lgs_ckpt_stream_open_t)); > > + ckpt_open_stream_msg_ptr = *ckpt_open_stream_msg_dec_ptr; > > + } else { > > + ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > } > > - memset(*ckpt_open_stream_msg_dec_ptr, '\0', > sizeof(lgs_ckpt_stream_open_t)); > > - ckpt_open_stream_msg_ptr = *ckpt_open_stream_msg_dec_ptr; > > - } else { > > - ckpt_open_stream_msg_ptr = static_cast<lgs_ckpt_stream_open_t > *>(ptr); > > + > > + rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, > ckpt_open_stream_rec_ed_rules, ckpt_open_stream_msg_ptr, > > + ptr_data_len, buf_env, op, o_err); > > } > > > > - rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, > ckpt_open_stream_rec_ed_rules, ckpt_open_stream_msg_ptr, > > - ptr_data_len, buf_env, op, o_err); > > return rc; > > } /* End edp_ed_open_stream_rec */ > > /* End of EDU encode/decode functions */ > > @@ -373,6 +417,18 @@ bool lgs_is_peer_v6() { > > } > > > > /** > > + * Check if peer is version 7 (or later) > > + * @return bool > > + */ > > +bool lgs_is_peer_v7() { > > + if (lgs_cb->mbcsv_peer_version >= LGS_MBCSV_VERSION_7) { > > + return true; > > + } else { > > + return false; > > + } > > +} > > + > > +/** > > * Check if configured for split file system. > > * If other node is version 1 split file system mode is not applicable. > > * > > @@ -598,6 +654,7 @@ uint32_t lgs_ckpt_stream_open_set(log_st > > stream_open->logFileCurrent = const_cast<char *>(logStream- > >logFileCurrent.c_str()); > > stream_open->fileFmt = logStream->logFileFormat; > > stream_open->logStreamName = const_cast<char *>(logStream- > >name.c_str()); > > + stream_open->dest_names = const_cast<char *>(logStream- > >stb_dest_names.c_str()); > > stream_open->maxFileSize = logStream->maxLogFileSize; > > stream_open->maxLogRecordSize = logStream->fixedLogRecordSize; > > stream_open->logFileFullAction = logStream->logFullAction; > > @@ -767,6 +824,7 @@ static uint32_t edu_enc_reg_list(lgs_cb_ > > > ************************************************************** > **************/ > > > > static uint32_t ckpt_encode_async_update(lgs_cb_t *lgs_cb, EDU_HDL > edu_hdl, NCS_MBCSV_CB_ARG *cbk_arg) { > > + lgsv_ckpt_msg_v7_t *data_v7 = NULL; > > lgsv_ckpt_msg_v6_t *data_v6 = NULL; > > lgsv_ckpt_msg_v5_t *data_v5 = NULL; > > lgsv_ckpt_msg_v3_t *data_v3 = NULL; > > @@ -779,7 +837,12 @@ static uint32_t ckpt_encode_async_update > > > > TRACE_ENTER(); > > /* Set reo_hdl from callback arg to ckpt_rec */ > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + data_v7 = reinterpret_cast<lgsv_ckpt_msg_v7_t *>( > > + static_cast<long>(cbk_arg->info.encode.io_reo_hdl)); > > + vdata = data_v7; > > + edp_function = edp_ed_ckpt_msg_v7; > > + } else if (lgs_is_peer_v6()) { > > data_v6 = reinterpret_cast<lgsv_ckpt_msg_v6_t *>( > > static_cast<long>(cbk_arg->info.encode.io_reo_hdl)); > > vdata = data_v6; > > @@ -1070,7 +1133,11 @@ static uint32_t ckpt_decode_log_cfg_stre > > void *stream_cfg; > > EDU_PROG_HANDLER edp_function; > > > > - if (lgs_is_peer_v2()) { > > + if (lgs_is_peer_v7()) { > > + lgsv_ckpt_msg_v7_t *ckpt_msg_v7 = static_cast<lgsv_ckpt_msg_v7_t > *>(ckpt_msg); > > + stream_cfg = &ckpt_msg_v7->ckpt_rec.stream_cfg; > > + edp_function = edp_ed_cfg_stream_rec_v7; > > + } else if (lgs_is_peer_v2()) { > > lgsv_ckpt_msg_v2_t *ckpt_msg_v2 = static_cast<lgsv_ckpt_msg_v2_t > *>(ckpt_msg); > > stream_cfg = &ckpt_msg_v2->ckpt_rec.stream_cfg; > > edp_function = edp_ed_cfg_stream_rec_v2; > > @@ -1092,11 +1159,16 @@ static uint32_t ckpt_decode_log_cfg(lgs_ > > uint32_t rc = NCSCC_RC_SUCCESS; > > void *lgs_cfg = NULL; > > EDU_PROG_HANDLER edp_function = NULL; > > + lgsv_ckpt_msg_v7_t *ckpt_msg_v7; > > lgsv_ckpt_msg_v5_t *ckpt_msg_v5; > > lgsv_ckpt_msg_v3_t *ckpt_msg_v3; > > lgsv_ckpt_msg_v2_t *ckpt_msg_v2; > > > > - if (lgs_is_peer_v5()) { > > + if (lgs_is_peer_v7()) { > > + ckpt_msg_v7 = static_cast<lgsv_ckpt_msg_v7_t *>(ckpt_msg); > > + lgs_cfg = &ckpt_msg_v7->ckpt_rec.lgs_cfg; > > + edp_function = edp_ed_lgs_cfg_rec_v5; > > + } else if (lgs_is_peer_v5()) { > > ckpt_msg_v5 = static_cast<lgsv_ckpt_msg_v5_t *>(ckpt_msg); > > lgs_cfg = &ckpt_msg_v5->ckpt_rec.lgs_cfg; > > edp_function = edp_ed_lgs_cfg_rec_v5; > > @@ -1136,6 +1208,8 @@ static uint32_t ckpt_decode_async_update > > lgsv_ckpt_msg_v5_t *ckpt_msg_v5 = &msg_v5; > > lgsv_ckpt_msg_v6_t msg_v6; > > lgsv_ckpt_msg_v6_t *ckpt_msg_v6 = &msg_v6; > > + lgsv_ckpt_msg_v7_t msg_v7; > > + lgsv_ckpt_msg_v7_t *ckpt_msg_v7 = &msg_v7; > > void *ckpt_msg; > > lgsv_ckpt_header_t hdr, *hdr_ptr = &hdr; > > > > @@ -1156,10 +1230,13 @@ static uint32_t ckpt_decode_async_update > > > > TRACE_2("\tckpt_rec_type: %d ", (int)hdr_ptr->ckpt_rec_type); > > > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + ckpt_msg_v7->header = hdr; > > + ckpt_msg = ckpt_msg_v7; > > + } else if (lgs_is_peer_v6()) { > > ckpt_msg_v6->header = hdr; > > ckpt_msg = ckpt_msg_v6; > > - } else if (lgs_is_peer_v5()) { > > + } else if (lgs_is_peer_v5()) { > > ckpt_msg_v5->header = hdr; > > ckpt_msg = ckpt_msg_v5; > > } else if (lgs_is_peer_v4()) { > > @@ -1177,10 +1254,13 @@ static uint32_t ckpt_decode_async_update > > switch (hdr_ptr->ckpt_rec_type) { > > case LGS_CKPT_CLIENT_INITIALIZE: > > TRACE_2("\tINITIALIZE REC: UPDATE"); > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + reg_rec = &ckpt_msg_v7->ckpt_rec.initialize_client; > > + edp_function_reg = edp_ed_reg_rec_v6; > > + } else if (lgs_is_peer_v6()) { > > reg_rec = &ckpt_msg_v6->ckpt_rec.initialize_client; > > edp_function_reg = edp_ed_reg_rec_v6; > > - } else if (lgs_is_peer_v5()) { > > + } else if (lgs_is_peer_v5()) { > > reg_rec = &ckpt_msg_v5->ckpt_rec.initialize_client; > > edp_function_reg = edp_ed_reg_rec; > > } else if (lgs_is_peer_v4()) { > > @@ -1209,7 +1289,9 @@ static uint32_t ckpt_decode_async_update > > > > case LGS_CKPT_OPEN_STREAM: /* 4 */ > > TRACE_2("\tSTREAM OPEN: UPDATE"); > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + stream_open = &ckpt_msg_v7->ckpt_rec.stream_open; > > + } else if (lgs_is_peer_v6()) { > > stream_open = &ckpt_msg_v6->ckpt_rec.stream_open; > > } else if (lgs_is_peer_v5()) { > > stream_open = &ckpt_msg_v5->ckpt_rec.stream_open; > > @@ -1467,13 +1549,17 @@ static uint32_t process_ckpt_data(lgs_cb > > lgsv_ckpt_msg_v3_t *data_v3; > > lgsv_ckpt_msg_v5_t *data_v5; > > lgsv_ckpt_msg_v6_t *data_v6; > > + lgsv_ckpt_msg_v7_t *data_v7; > > > > if ((!cb) || (data == NULL)) { > > TRACE("%s - FAILED: (!cb) || (data == NULL)", __FUNCTION__); > > return (rc = NCSCC_RC_FAILURE); > > } > > > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + data_v7 = static_cast<lgsv_ckpt_msg_v7_t *>(data); > > + lgsv_ckpt_msg_type = data_v7->header.ckpt_rec_type; > > + } else if (lgs_is_peer_v6()) { > > data_v6 = static_cast<lgsv_ckpt_msg_v6_t *>(data); > > lgsv_ckpt_msg_type = data_v6->header.ckpt_rec_type; > > } else if (lgs_is_peer_v5()) { > > @@ -1906,10 +1992,14 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t > > lgs_ckpt_stream_open_t *param; > > log_stream_t *stream; > > int pos = 0, err = 0; > > + SaNameT objectName; > > > > TRACE_ENTER(); > > > > - if (lgs_is_peer_v2()) { > > + if (lgs_is_peer_v7()) { > > + lgsv_ckpt_msg_v7_t *data_v7 = static_cast<lgsv_ckpt_msg_v7_t > *>(data); > > + param = &data_v7->ckpt_rec.stream_open; > > + } else if (lgs_is_peer_v2()) { > > lgsv_ckpt_msg_v2_t *data_v2 = static_cast<lgsv_ckpt_msg_v2_t > *>(data); > > param = &data_v2->ckpt_rec.stream_open; > > } else { > > @@ -1974,7 +2064,27 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t > > stream->logFileCurrent = param->logFileCurrent; > > stream->stb_prev_actlogFileCurrent = param->logFileCurrent; > > stream->stb_logFileCurrent = param->logFileCurrent; > > - stream->isRtStream = SA_TRUE; > > + > > + osaf_extended_name_lend(param->logStreamName, &objectName); > > + SaImmClassNameT className = > immutil_get_className(&objectName); > > + if (className != nullptr && strcmp(className, "SaLogStreamConfig") > == 0) { > > + stream->isRtStream = SA_FALSE; > > + } else { > > + stream->isRtStream = SA_TRUE; > > + } > > + if (className != nullptr) free(className); > > + > > + // Only update destination names if peer is v7 or upper. > > + if (lgs_is_peer_v7()) { > > + if (param->dest_names != nullptr && strlen(param->dest_names) != 0) > { > > + TRACE("Dest_name %s", param->dest_names); > > + stream->stb_dest_names = std::string{param->dest_names}; > > + stream->dest_names = logutil::Parser(stream->stb_dest_names, ";"); > > + } else { > > + stream->stb_dest_names = ""; > > + stream->dest_names.clear(); > > + } > > + } > > } > > > > /* If configured for split file system files shall be opened on stand by > > @@ -2133,12 +2243,28 @@ static uint32_t ckpt_proc_cfg_stream(lgs > > SaUint32T logFullHaltThreshold; /* !app log stream */ > > SaUint32T maxFilesRotated; > > char *logFileFormat; > > + char *dest_names = nullptr; > > SaUint32T severityFilter; > > char *logFileCurrent; > > > > TRACE_ENTER(); > > > > - if (lgs_is_peer_v2()) { > > + if (lgs_is_peer_v7()) { > > + lgsv_ckpt_msg_v7_t *data_v7 = static_cast<lgsv_ckpt_msg_v7_t > *>(data); > > + name = data_v7->ckpt_rec.stream_cfg.name; > > + fileName = data_v7->ckpt_rec.stream_cfg.fileName; > > + pathName = data_v7->ckpt_rec.stream_cfg.pathName; > > + maxLogFileSize = data_v7->ckpt_rec.stream_cfg.maxLogFileSize; > > + fixedLogRecordSize = data_v7- > >ckpt_rec.stream_cfg.fixedLogRecordSize; > > + logFullAction = data_v7->ckpt_rec.stream_cfg.logFullAction; > > + logFullHaltThreshold = data_v7- > >ckpt_rec.stream_cfg.logFullHaltThreshold; > > + maxFilesRotated = data_v7->ckpt_rec.stream_cfg.maxFilesRotated; > > + logFileFormat = data_v7->ckpt_rec.stream_cfg.logFileFormat; > > + severityFilter = data_v7->ckpt_rec.stream_cfg.severityFilter; > > + logFileCurrent = data_v7->ckpt_rec.stream_cfg.logFileCurrent; > > + dest_names = data_v7->ckpt_rec.stream_cfg.dest_names; > > + closetime = data_v7->ckpt_rec.stream_cfg.c_file_close_time_stamp; > > + } else if (lgs_is_peer_v2()) { > > lgsv_ckpt_msg_v2_t *data_v2 = static_cast<lgsv_ckpt_msg_v2_t > *>(data); > > name = data_v2->ckpt_rec.stream_cfg.name; > > fileName = data_v2->ckpt_rec.stream_cfg.fileName; > > @@ -2191,6 +2317,17 @@ static uint32_t ckpt_proc_cfg_stream(lgs > > strcpy(stream->logFileFormat, logFileFormat); > > stream->severityFilter = severityFilter; > > stream->logFileCurrent = logFileCurrent; > > + // Only update destination name if peer is v7 or upper. > > + if (lgs_is_peer_v7()) { > > + if (dest_names != nullptr && strlen(dest_names) != 0) { > > + TRACE("dest_names: %s", dest_names); > > + stream->stb_dest_names = std::string{dest_names}; > > + stream->dest_names = logutil::Parser(stream->stb_dest_names, ";"); > > + } else { > > + stream->stb_dest_names = ""; > > + stream->dest_names.clear(); > > + } > > + } > > > > /* If split file mode, update standby files */ > > if (lgs_is_split_file_system()) { > > @@ -2250,7 +2387,10 @@ uint32_t lgs_ckpt_send_async(lgs_cb_t *c > > > > TRACE_ENTER(); > > > > - if (lgs_is_peer_v6()) { > > + if (lgs_is_peer_v7()) { > > + lgsv_ckpt_msg_v7_t *ckpt_rec_v7 = static_cast<lgsv_ckpt_msg_v7_t > *>(ckpt_rec); > > + ckpt_rec_type = ckpt_rec_v7->header.ckpt_rec_type; > > + } else if (lgs_is_peer_v6()) { > > lgsv_ckpt_msg_v6_t *ckpt_rec_v6 = static_cast<lgsv_ckpt_msg_v6_t > *>(ckpt_rec); > > ckpt_rec_type = ckpt_rec_v6->header.ckpt_rec_type; > > } else if (lgs_is_peer_v5()) { > > diff --git a/src/log/logd/lgs_mbcsv.h b/src/log/logd/lgs_mbcsv.h > > --- a/src/log/logd/lgs_mbcsv.h > > +++ b/src/log/logd/lgs_mbcsv.h > > @@ -40,9 +40,10 @@ > > #define LGS_MBCSV_VERSION_4 4 > > #define LGS_MBCSV_VERSION_5 5 > > #define LGS_MBCSV_VERSION_6 6 > > +#define LGS_MBCSV_VERSION_7 7 > > > > /* Current version */ > > -#define LGS_MBCSV_VERSION 6 > > +#define LGS_MBCSV_VERSION 7 > > #define LGS_MBCSV_VERSION_MIN 1 > > > > /* Checkpoint message types(Used as 'reotype' w.r.t mbcsv) */ > > @@ -98,6 +99,7 @@ typedef struct { > > uint64_t creationTimeStamp; > > uint32_t numOpeners; > > char *logFileCurrent; > > + char *dest_names; > > logStreamTypeT streamType; > > uint32_t logRecordId; /* log record identifier increased for each record > */ > > } lgs_ckpt_stream_open_t; > > @@ -109,6 +111,7 @@ bool lgs_is_peer_v3(); > > bool lgs_is_peer_v4(); > > bool lgs_is_peer_v5(); > > bool lgs_is_peer_v6(); > > +bool lgs_is_peer_v7(); > > bool lgs_is_split_file_system(); > > uint32_t lgs_mbcsv_dispatch(NCS_MBCSV_HDL mbcsv_hdl); > > void lgs_free_edu_mem(char *ptr); > > diff --git a/src/log/logd/lgs_mbcsv_v5.cc b/src/log/logd/lgs_mbcsv_v5.cc > > --- a/src/log/logd/lgs_mbcsv_v5.cc > > +++ b/src/log/logd/lgs_mbcsv_v5.cc > > @@ -1,6 +1,7 @@ > > /* -*- OpenSAF -*- > > * > > * (C) Copyright 2015 The OpenSAF Foundation > > + * Copyright Ericsson AB 2015, 2017 - All Rights Reserved. > > * File: lgs_mbcsv_v5.c > > * > > * This program is distributed in the hope that it will be useful, but > > @@ -22,6 +23,7 @@ > > */ > > > > #include "lgs_mbcsv_v5.h" > > +#include "log/logd/lgs_dest.h" > > > > > /************************************************************* > *************** > > * Name : ckpt_proc_lgs_cfg > > @@ -132,6 +134,14 @@ uint32_t ckpt_proc_lgs_cfg_v5(lgs_cb_t * > > TRACE("\tUpdating mailbox limits"); > > (void) lgs_configure_mailbox(); > > } > > + // Only support destination configuration since V7 > > + if (lgs_is_peer_v7()) { > > + const VectorString *vdest = nullptr; > > + vdest = reinterpret_cast<const VectorString*>( > > + > lgs_cfg_get(LGS_IMM_LOG_RECORD_DESTINATION_CONFIGURATION)); > > + osafassert(vdest != nullptr); > > + CfgDestination(*vdest, ModifyType::kReplace); > > + } > > > > /* Free buffer allocated by the EDU encoder */ > > if (param->buffer == NULL) { > > diff --git a/src/log/logd/lgs_mbcsv_v7.cc b/src/log/logd/lgs_mbcsv_v7.cc > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_mbcsv_v7.cc > > @@ -0,0 +1,177 @@ > > +/* -*- OpenSAF -*- > > + * > > + * (C) Copyright 2017 The OpenSAF Foundation > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 "log/logd/lgs_mbcsv_v7.h" > > + > > > +/************************************************************ > **************** > > + * Name : edp_ed_cfg_stream_rec > > + * > > + * Description : This function is an EDU program for encoding/decoding > > + * lgsv checkpoint cfg_update_stream log rec. > > + * > > + * Arguments : EDU_HDL - pointer to edu handle, > > + * EDU_TKN - internal edu token to help encode/decode, > > + * POINTER to the structure to encode/decode from/to, > > + * data length specifying number of structures, > > + * EDU_BUF_ENV - pointer to buffer for encoding/decoding. > > + * op - operation type being encode/decode. > > + * EDU_ERR - out param to indicate errors in processing. > > + * > > + * Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE > > + * > > + * Notes : None. > > + > ************************************************************** > ***************/ > > + > > +uint32_t edp_ed_cfg_stream_rec_v7(EDU_HDL *edu_hdl, EDU_TKN > *edu_tkn, > > + NCSCONTEXT ptr, uint32_t *ptr_data_len, > > + EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, EDU_ERR > *o_err) { > > + uint32_t rc = NCSCC_RC_SUCCESS; > > + lgs_ckpt_stream_cfg_v3_t *ckpt_stream_cfg_msg_ptr = NULL, > **ckpt_stream_cfg_msg_dec_ptr; > > + > > + EDU_INST_SET ckpt_stream_cfg_rec_ed_rules[] = { > > + {EDU_START, edp_ed_cfg_stream_rec_v7, 0, 0, 0, > sizeof(lgs_ckpt_stream_cfg_v3_t), 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->name, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->fileName, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->pathName, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->maxLogFileSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->fixedLogRecordSize, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->haProperty, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->logFullAction, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->logFullHaltThreshold, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->maxFilesRotated, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->logFileFormat, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns32, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->severityFilter, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->logFileCurrent, 0, NULL}, > > + {EDU_EXEC, ncs_edp_string, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->dest_names, 0, NULL}, > > + {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, (long)&((lgs_ckpt_stream_cfg_v3_t > *)0)->c_file_close_time_stamp, 0, NULL}, > > + {EDU_END, 0, 0, 0, 0, 0, 0, NULL}, > > + }; > > + > > + if (op == EDP_OP_TYPE_ENC) { > > + ckpt_stream_cfg_msg_ptr = static_cast<lgs_ckpt_stream_cfg_v3_t > *>(ptr); > > + } else if (op == EDP_OP_TYPE_DEC) { > > + ckpt_stream_cfg_msg_dec_ptr = static_cast<lgs_ckpt_stream_cfg_v3_t > **>(ptr); > > + if (*ckpt_stream_cfg_msg_dec_ptr == NULL) { > > + *o_err = EDU_ERR_MEM_FAIL; > > + return NCSCC_RC_FAILURE; > > + } > > + memset(*ckpt_stream_cfg_msg_dec_ptr, '\0', > sizeof(lgs_ckpt_stream_cfg_v3_t)); > > + ckpt_stream_cfg_msg_ptr = *ckpt_stream_cfg_msg_dec_ptr; > > + } else { > > + ckpt_stream_cfg_msg_ptr = static_cast<lgs_ckpt_stream_cfg_v3_t > *>(ptr); > > + } > > + > > + rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, > > + ckpt_stream_cfg_rec_ed_rules, > > + ckpt_stream_cfg_msg_ptr, > > + ptr_data_len, > > + buf_env, op, o_err); > > + return rc; > > +} > > + > > > +/************************************************************ > **************** > > + * Name : edp_ed_ckpt_msg_v7 > > + * > > + * Description : This function is an EDU program for encoding/decoding > > + * lgsv checkpoint messages. This program runs the > > + * edp_ed_hdr_rec program first to decide the > > + * checkpoint message type based on which it will call the > > + * appropriate EDU programs for the different checkpoint > > + * messages. > > + * > > + * Arguments : EDU_HDL - pointer to edu handle, > > + * EDU_TKN - internal edu token to help encode/decode, > > + * POINTER to the structure to encode/decode from/to, > > + * data length specifying number of structures, > > + * EDU_BUF_ENV - pointer to buffer for encoding/decoding. > > + * op - operation type being encode/decode. > > + * EDU_ERR - out param to indicate errors in processing. > > + * > > + * Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE > > + * > > + * Notes : None. > > + > ************************************************************** > ***************/ > > + > > +uint32_t edp_ed_ckpt_msg_v7(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn, > > + NCSCONTEXT ptr, uint32_t *ptr_data_len, EDU_BUF_ENV > *buf_env, > > + EDP_OP_TYPE op, EDU_ERR *o_err) { > > + uint32_t rc = NCSCC_RC_SUCCESS; > > + lgsv_ckpt_msg_v7_t *ckpt_msg_ptr = NULL, **ckpt_msg_dec_ptr; > > + > > + EDU_INST_SET ckpt_msg_ed_rules[] = { > > + {EDU_START, edp_ed_ckpt_msg_v7, 0, 0, 0, > sizeof(lgsv_ckpt_msg_v7_t), 0, NULL}, > > + {EDU_EXEC, edp_ed_header_rec, 0, 0, 0, (long)&((lgsv_ckpt_msg_v7_t > *)0)->header, 0, NULL}, > > + > > + {EDU_TEST, ncs_edp_uns32, 0, 0, 0, (long)&((lgsv_ckpt_msg_v7_t *)0)- > >header, 0, > > + (EDU_EXEC_RTINE)ckpt_msg_test_type}, > > + > > + /* Reg Record */ > > + {EDU_EXEC, edp_ed_reg_rec_v6, 0, 0, static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.initialize_client, 0, NULL}, > > + > > + /* Finalize record */ > > + {EDU_EXEC, edp_ed_finalize_rec_v2, 0, 0, static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.finalize_client, 0, NULL}, > > + > > + /* write log Record */ > > + {EDU_EXEC, edp_ed_write_rec_v2, 0, 0, static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.write_log, 0, NULL}, > > + > > + /* Open stream */ > > + {EDU_EXEC, edp_ed_open_stream_rec, 0, 0, > static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.stream_open, 0, NULL}, > > + > > + /* Close stream */ > > + {EDU_EXEC, edp_ed_close_stream_rec_v2, 0, 0, > static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.stream_close, 0, NULL}, > > + > > + /* Agent dest */ > > + {EDU_EXEC, edp_ed_agent_down_rec_v2, 0, 0, > static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.stream_cfg, 0, NULL}, > > + > > + /* Cfg stream */ > > + {EDU_EXEC, edp_ed_cfg_stream_rec_v7, 0, 0, > static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.stream_cfg, 0, NULL}, > > + > > + /* Lgs cfg */ > > + {EDU_EXEC, edp_ed_lgs_cfg_rec_v5, 0, 0, static_cast<int>(EDU_EXIT), > > + (long)&((lgsv_ckpt_msg_v7_t *)0)->ckpt_rec.lgs_cfg, 0, NULL}, > > + > > + {EDU_END, 0, 0, 0, 0, 0, 0, NULL}, > > + }; > > + > > + if (op == EDP_OP_TYPE_ENC) { > > + ckpt_msg_ptr = static_cast<lgsv_ckpt_msg_v7_t *>(ptr); > > + } else if (op == EDP_OP_TYPE_DEC) { > > + ckpt_msg_dec_ptr = static_cast<lgsv_ckpt_msg_v7_t **>(ptr); > > + if (*ckpt_msg_dec_ptr == NULL) { > > + *o_err = EDU_ERR_MEM_FAIL; > > + return NCSCC_RC_FAILURE; > > + } > > + memset(*ckpt_msg_dec_ptr, '\0', sizeof(lgsv_ckpt_msg_v7_t)); > > + ckpt_msg_ptr = *ckpt_msg_dec_ptr; > > + } else { > > + ckpt_msg_ptr = static_cast<lgsv_ckpt_msg_v7_t *>(ptr); > > + } > > + > > + rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, ckpt_msg_ed_rules, > > + ckpt_msg_ptr, ptr_data_len, buf_env, op, o_err); > > + > > + return rc; > > + > > +} > > diff --git a/src/log/logd/lgs_mbcsv_v7.h b/src/log/logd/lgs_mbcsv_v7.h > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_mbcsv_v7.h > > @@ -0,0 +1,66 @@ > > +/* -*- OpenSAF -*- > > + * > > + * (C) Copyright 2017 The OpenSAF Foundation > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 > > + * > > + */ > > + > > +#ifndef SRC_LOG_LOGD_LGS_MBCSV_V7_H_ > > +#define SRC_LOG_LOGD_LGS_MBCSV_V7_H_ > > + > > +#include "log/logd/lgs.h" > > +#include "log/logd/lgs_config.h" > > +#include "log/logd/lgs_mbcsv.h" > > +#include "log/logd/lgs_mbcsv_v2.h" > > +#include "log/logd/lgs_mbcsv_v5.h" > > +#include "log/logd/lgs_mbcsv_v6.h" > > + > > +typedef struct { > > + char *name; > > + char *fileName; > > + char *pathName; > > + SaUint64T maxLogFileSize; > > + SaUint32T fixedLogRecordSize; > > + SaBoolT haProperty; /* app log stream only */ > > + SaLogFileFullActionT logFullAction; > > + SaUint32T logFullHaltThreshold; /* !app log stream */ > > + SaUint32T maxFilesRotated; > > + char *logFileFormat; > > + SaUint32T severityFilter; > > + char *logFileCurrent; > > + char *dest_names; > > + uint64_t c_file_close_time_stamp; /* Time in sec for file rename on > Active */ > > +} lgs_ckpt_stream_cfg_v3_t; > > + > > +typedef struct { > > + lgsv_ckpt_header_t header; > > + union { > > + lgs_ckpt_initialize_msg_v6_t initialize_client; > > + lgs_ckpt_finalize_msg_v2_t finalize_client; > > + lgs_ckpt_write_log_v2_t write_log; > > + lgs_ckpt_agent_down_v2_t agent_down; > > + lgs_ckpt_stream_open_t stream_open; > > + lgs_ckpt_stream_close_v2_t stream_close; > > + lgs_ckpt_stream_cfg_v3_t stream_cfg; > > + lgs_ckpt_lgs_cfg_v5_t lgs_cfg; > > + } ckpt_rec; > > +} lgsv_ckpt_msg_v7_t; > > + > > +uint32_t edp_ed_cfg_stream_rec_v7(EDU_HDL *edu_hdl, EDU_TKN > *edu_tkn, > > + NCSCONTEXT ptr, uint32_t *ptr_data_len, > > + EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, EDU_ERR > *o_err); > > +uint32_t edp_ed_ckpt_msg_v7(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn, > > + NCSCONTEXT ptr, uint32_t *ptr_data_len, EDU_BUF_ENV > *buf_env, EDP_OP_TYPE op, EDU_ERR *o_err); > > + > > +#endif // SRC_LOG_LOGD_LGS_MBCSV_V7_H_ > > diff --git a/src/log/logd/lgs_nildest.cc b/src/log/logd/lgs_nildest.cc > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_nildest.cc > > @@ -0,0 +1,153 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 "log/logd/lgs_nildest.h" > > + > > +#include <algorithm> > > + > > +#include "base/logtrace.h" > > + > > +static const char kDelimeter[] = ";"; > > + > > + > > > +//============================================================ > ================== > > +// NilDestType class > > > +//============================================================ > ================== > > +NilDestType NilDestType::me_; > > +const char NilDestType::name_[] = "NILDEST"; > > + > > +NilDestType::NilDestType() {} > > + > > +NilDestType::~NilDestType() { > > +} > > + > > +const VectorString NilDestType::GetAllDestStatus() { > > + VectorString output{}; > > + if (me_.destnames_.size() == 0) return output; > > + for (const auto& it : me_.destnames_) { > > + std::string status = it + "," + "NOT_CONNECTED"; > > + TRACE("%s status = %s", __func__, status.c_str()); > > + output.push_back(status); > > + } > > + return output; > > +} > > + > > +bool NilDestType::FindName(const std::string& name) const { > > + return (std::find(destnames_.begin(), destnames_.end(), name) != > > + destnames_.end()); > > +} > > + > > +ErrCode NilDestType::HandleRecordMsg( > > + const DestinationHandler::RecordMsg& msg) { > > + ErrCode ret = ErrCode::kOk; > > + TRACE("Destination name(%s) is NILDEST. Drop msg!", msg.name); > > + ret = ErrCode::kDrop; > > + return ret; > > +} > > + > > +ErrCode NilDestType::HandleCfgMsg( > > + const DestinationHandler::CfgDestMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + const std::string name{msg.name}; > > + TRACE("%s Add NILDEST with name (%s)", __func__, msg.name); > > + destnames_.push_back(name); > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode NilDestType::HandleDelCfgMsg( > > + const DestinationHandler::DelDestMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + TRACE("%s remove NILDEST destination name (%s)", __func__, > msg.name); > > + const std::string name{msg.name}; > > + destnames_.erase(std::remove(destnames_.begin(), > > + destnames_.end(), > > + name) > > + , destnames_.end()); > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode NilDestType::ProcessMsg( > > + const DestinationHandler::HandleMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + static bool cfgsent = false; > > + // The proper sequence should be: > > + // 1) kCfgDest : for configure destination handlers > > + // 2) kSendRecord: write log record to destination > > + // 3) kDelDest : delete specific destinations > > + // 4) kNoDest : delete all destinations > > + // Msg could be drop if the sequence is not correct. > > + switch (msg.type) { > > + case DestinationHandler::MsgType::kSendRecord: { > > + // No destination yet configured. Drop the message. > > + TRACE("%s %s", __func__, "RecordMsg msg"); > > + const DestinationHandler::RecordMsg& rmsg = msg.info.rec; > > + > > + // No destination has been configured so far. > > + if (cfgsent == false) { > > + LOG_WA("Destination handler not yet initialized. Drop msg."); > > + ret = ErrCode::kDrop; > > + } else { > > + ret = HandleRecordMsg(rmsg); > > + } > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kCfgDest: { > > + const DestinationHandler::CfgDestMsg& cmsg = msg.info.cfg; > > + TRACE("%s %s", __func__, "CfgDestMsg msg"); > > + ret = HandleCfgMsg(cmsg); > > + // Notice there at leat one destination configured. > > + if (ret == ErrCode::kOk) cfgsent = true; > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kDelDest: { > > + const DestinationHandler::DelDestMsg& dmsg = msg.info.del; > > + TRACE("%s %s", __func__, "DelDestMsg msg"); > > + // No destination yet configured. Drop the message. > > + if (cfgsent == false) { > > + LOG_NO("No destination configured yet. Drop msg."); > > + return ErrCode::kDrop; > > + } > > + ret = HandleDelCfgMsg(dmsg); > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kNoDest: { > > + LOG_NO("%s %s", __func__, "DelAllCfgDest msg"); > > + if (cfgsent == false) { > > + LOG_NO("No destination configured yet"); > > + return ErrCode::kDrop; > > + } > > + destnames_.clear(); > > + cfgsent = false; > > + break; > > + } > > + > > + default: > > + LOG_ER("Unknown dispatch message type %d", > static_cast<int>(msg.type)); > > + ret = ErrCode::kInvalid; > > + } > > + > > + TRACE_LEAVE(); > > + return ret; > > +} > > diff --git a/src/log/logd/lgs_nildest.h b/src/log/logd/lgs_nildest.h > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_nildest.h > > @@ -0,0 +1,72 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 > > + * > > + */ > > + > > +#ifndef SRC_LOG_LOGD_LGS_NILDEST_H_ > > +#define SRC_LOG_LOGD_LGS_NILDEST_H_ > > + > > +#include <string> > > + > > +#include "log/logd/lgs_common.h" > > +#include "log/logd/lgs_dest.h" > > + > > +//> > > +// @NilDestType - represent NILDEST destination type > > +// > > +//< > > +class NilDestType { > > + public: > > + // @NilDestType class is dedicated to @DestinationHandler class. > > + // Outside world is not granted to access to this class resources > > + friend class DestinationHandler; > > + > > + // Get @type that represents for @NilDestType. This type must be > unique. > > + static const std::string Type() { return std::string{name_}; } > > + > > + private: > > + NilDestType(); > > + ~NilDestType(); > > + > > + // Find if any destination @name configured so far > > + bool FindName(const std::string&) const; > > + // Interpret the DestinationHandler msg and forward to right handle > > + ErrCode ProcessMsg(const DestinationHandler::HandleMsg&); > > + // The msg will be droped if sending to @NILDEST type > > + ErrCode HandleRecordMsg(const DestinationHandler::RecordMsg&); > > + // Put the destination name to @destnames_ for querying destination > status > > + ErrCode HandleCfgMsg(const DestinationHandler::CfgDestMsg&); > > + // Remove from @destnames_ > > + ErrCode HandleDelCfgMsg(const DestinationHandler::DelDestMsg&); > > + // Get all destination status for @NILDEST type > > + // @return a vector of status, with format > > + // {"name,NOT_CONNECTED", "name2,NOT_CONNECTED, etc."} > > + static const VectorString GetAllDestStatus(); > > + // Unique object instance for this @NilDestType class > > + static NilDestType& Instance() { return me_; } > > + // Unique instance for this class > > + static NilDestType me_; > > + // The type name of this @NilDestType (my identity). > > + // Must use this "type" name in destination configuration > > + // if want to destinate to @NilDestType > > + static const char name_[]; > > + > > + // Hold all destination names having @NILDEST type > > + VectorString destnames_; > > + > > + DELETE_COPY_AND_MOVE_OPERATORS(NilDestType); > > +}; > > + > > +#endif // SRC_LOG_LOGD_LGS_NILDEST_H_ > > diff --git a/src/log/logd/lgs_stream.cc b/src/log/logd/lgs_stream.cc > > --- a/src/log/logd/lgs_stream.cc > > +++ b/src/log/logd/lgs_stream.cc > > @@ -27,6 +27,9 @@ > > * Examples can be found in this file, e.g. function fileopen(...) below > > */ > > > > +#include "log/logd/lgs_stream.h" > > +#include <algorithm> > > + > > #include "log/logd/lgs.h" > > #include "lgs_config.h" > > #include "log/logd/lgs_file.h" > > @@ -376,6 +379,8 @@ void log_stream_print(log_stream_t *stre > > TRACE_2(" logRecordId: %u", stream->logRecordId); > > TRACE_2(" streamType: %u", stream->streamType); > > TRACE_2(" filtered: %llu", stream->filtered); > > + TRACE_2(" stb_dest_names: %s", stream->stb_dest_names.c_str()); > > + TRACE_2(" isRtStream: %d", stream->isRtStream); > > } > > > > /** > > @@ -480,7 +485,6 @@ int lgs_populate_log_stream( > > o_stream->logRecordId = logRecordId; > > o_stream->stb_logRecordId = 0; > > o_stream->isRtStream = SA_TRUE; > > - > > o_stream->logFileFormat = strdup(logFileFormat); > > if (o_stream->logFileFormat == NULL) { > > LOG_WA("Failed to allocate memory for logFileFormat"); > > @@ -654,6 +658,7 @@ log_stream_t *log_stream_new(const std:: > > stream->creationTimeStamp = lgs_get_SaTime(); > > stream->severityFilter = 0x7f; /* by default all levels are allowed */ > > stream->isRtStream = SA_FALSE; > > + stream->dest_names.clear(); > > > > /* Initiate local or shared stream file descriptor dependant on shared or > > * split file system > > @@ -1492,3 +1497,58 @@ bool check_max_stream() { > > return (numb_of_streams < stream_array_size ? false:true); > > } > > > > +void log_stream_add_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names) { > > + osafassert(stream != nullptr); > > + for (const auto& it : names) { > > + stream->dest_names.push_back(it); > > + } > > + > > + // Prepare stb_dest_names for checkingpoint to standby > > + log_stream_form_dest_names(stream); > > +} > > + > > +void log_stream_replace_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names) { > > + osafassert(stream != nullptr); > > + stream->dest_names = names; > > + // Prepare stb_dest_names for checkingpoint to standby > > + log_stream_form_dest_names(stream); > > +} > > + > > +void log_stream_delete_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names) { > > + osafassert(stream != nullptr); > > + if (names.size() != 0) { > > + for (const auto& it : names) { > > + // Remove deleted destination from internal database > > + stream->dest_names.erase(std::remove(stream->dest_names.begin(), > > + stream->dest_names.end(), it), > > + stream->dest_names.end()); > > + } > > + } else { > > + // Delete all destination names > > + stream->dest_names.clear(); > > + } > > + > > + // Prepare stb_dest_names for checkingpoint to standby > > + log_stream_form_dest_names(stream); > > +} > > + > > +void log_stream_form_dest_names(log_stream_t* stream) { > > + osafassert(stream != nullptr); > > + std::string output{""}; > > + bool addSemicolon = false; > > + // Form stb_dest_names before checking point to standby > > + // under format "name1;name2;etc". > > + for (const auto& it : stream->dest_names) { > > + output += it + ";"; > > + addSemicolon = true; > > + } > > + if (addSemicolon == true) { > > + osafassert(output.length() > 0); > > + // Remove last semicolon(;) > > + output[output.length() - 1] = '\0'; > > + } > > + stream->stb_dest_names = output; > > +} > > diff --git a/src/log/logd/lgs_stream.h b/src/log/logd/lgs_stream.h > > --- a/src/log/logd/lgs_stream.h > > +++ b/src/log/logd/lgs_stream.h > > @@ -1,6 +1,7 @@ > > /* -*- OpenSAF -*- > > * > > * (C) Copyright 2008 The OpenSAF Foundation > > + * Copyright Ericsson AB 2008, 2017 - All Rights Reserved. > > * > > * This program is distributed in the hope that it will be useful, but > > * WITHOUT ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY > > @@ -22,6 +23,7 @@ > > #include "base/ncspatricia.h" > > #include <time.h> > > #include <limits.h> > > +#include <vector> > > > > #include "lgs_fmt.h" > > #include "base/osaf_extended_name.h" > > @@ -83,6 +85,12 @@ typedef struct log_stream { > > std::string stb_logFileCurrent; /* Current file name used on standby */ > > std::string stb_prev_actlogFileCurrent; /* current file name on active > when previous record was written */ > > uint32_t stb_curFileSize; /* Bytes written to current log file */ > > + > > + // Hold vector of destname string {"name1", "name2", etc.} > > + std::vector<std::string> dest_names; > > + // Hold a list of strings separated by semicolon "name1;name2;etc" > > + // This data is used to checkpoint to standby > > + std::string stb_dest_names; > > } log_stream_t; > > > > extern uint32_t log_stream_init(); > > @@ -133,4 +141,12 @@ void log_free_stream_resources(log_strea > > log_stream_t *iterate_all_streams(SaBoolT &end, SaBoolT jstart); > > extern log_stream_t *log_stream_get_by_name(const std::string > &name); > > > > +void log_stream_add_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names); > > +void log_stream_replace_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names); > > +void log_stream_delete_dest_name(log_stream_t *stream, > > + const std::vector<std::string>& names); > > +void log_stream_form_dest_names(log_stream_t* stream); > > + > > #endif // LOG_LOGD_LGS_STREAM_H_ > > diff --git a/src/log/logd/lgs_unixsock_dest.cc > b/src/log/logd/lgs_unixsock_dest.cc > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_unixsock_dest.cc > > @@ -0,0 +1,343 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 "log/logd/lgs_unixsock_dest.h" > > + > > +#include <algorithm> > > + > > +#include "log/logd/lgs_util.h" > > +#include "log/logd/lgs_nildest.h" > > +#include "base/logtrace.h" > > + > > +// RFC5424 syslog msg format > > +// ========================= > > +// 1) HEADER > > +// PRI = 16*8 + SaLogSeverityT > > +// VERSION = 1 > > +// TIMESTAMP = When a log record was actually logged > > +// E.g: 2016-12-02T11:34:15.944364+01:00 > > +// HOSTNAME = FQDN > > +// APP-NAME = App name who generated log record > > +// PROCID = NILVALUE > > +// MSGID = A hash generated from log stream DN > > +// STRUCTURED-DATA = NILVALUE > > +// > > +// 2) MSG BODY > > +// MSG = The log record written to local file > > +// > > + > > +static const char kDelimeter[] = ";"; > > + > > > +//============================================================ > ================== > > +// UnixSocketHandler class > > > +//============================================================ > ================== > > +UnixSocketHandler::UnixSocketHandler(const char* socket_name) > > + : sock_path_{socket_name} > > + , sock_{socket_name} > > + , status_{DestinationStatus::kFailed} { > > + // Open the unix socket & and flush the destination status to @status_ > > + Open(); > > +}; > > + > > +void UnixSocketHandler::FlushStatus() { > > + if (sock_.fd() >= 0) { > > + status_ = DestinationStatus::kActive; > > + } else { > > + status_ = DestinationStatus::kFailed; > > + } > > +} > > + > > +DestinationStatus UnixSocketHandler::GetSockStatus() { > > + Open(); > > + return status_; > > +} > > + > > +void UnixSocketHandler::Open() { > > + FlushStatus(); > > +} > > + > > +void UnixSocketHandler::FormRfc5424( > > + const DestinationHandler::RecordInfo& msg, > > + RfcBuffer* buf) { > > + base::LogMessage::Severity sev{Sev(msg.severity)}; > > + base::LogMessage::HostName hostname{msg.origin}; > > + base::LogMessage::ProcId procid{""}; > > + base::LogMessage::AppName appname{msg.app_name}; > > + > > + base::LogMessage::Write(base::LogMessage::Facility::kLocal0, > > + sev, > > + msg.time, > > + hostname, > > + appname, > > + procid, > > + base::LogMessage::MsgId{msg.msgid}, > > + {}, > > + std::string{msg.log_record}, > > + buf); > > +} > > + > > +ErrCode UnixSocketHandler::Send(const DestinationHandler::RecordInfo& > msg) { > > + TRACE_ENTER(); > > + RfcBuffer buffer; > > + > > + FormRfc5424(msg, &buffer); > > + > > + ssize_t length = buffer.size(); > > + ssize_t len = sock_.Send(buffer.data(), length); > > + // Resend as probably receiver has just been restarted. > > + // Retry only once, if not succesfully, leave it to upper layer decision. > > + if (len != length) { > > + LOG_NO("Failed to send log record to socket destination. Resent."); > > + len = sock_.Send(buffer.data(), length); > > + } > > + > > + FlushStatus(); > > + > > + TRACE_LEAVE(); > > + return ((len != length) ? (ErrCode::kErr) : (ErrCode::kOk)); > > +} > > + > > +void UnixSocketHandler::Close() { > > + // Do nothing > > +} > > + > > +// Convert AIS sev @a sev to Severity class > > +base::LogMessage::Severity UnixSocketHandler::Sev(uint16_t sev) { > > + switch (sev) { > > + case SA_LOG_SEV_EMERGENCY: > > + return base::LogMessage::Severity::kEmerg; > > + case SA_LOG_SEV_ALERT: > > + return base::LogMessage::Severity::kAlert; > > + case SA_LOG_SEV_CRITICAL: > > + return base::LogMessage::Severity::kCrit; > > + case SA_LOG_SEV_ERROR: > > + return base::LogMessage::Severity::kErr; > > + case SA_LOG_SEV_WARNING: > > + return base::LogMessage::Severity::kWarning; > > + case SA_LOG_SEV_NOTICE: > > + return base::LogMessage::Severity::kNotice; > > + case SA_LOG_SEV_INFO: > > + return base::LogMessage::Severity::kInfo; > > + default: > > + LOG_ER("Unknown severity level (%d)", (int)sev); > > + return base::LogMessage::Severity::kErr; > > + } > > +} > > + > > +UnixSocketHandler::~UnixSocketHandler() { > > + // Destination is deleted > > + status_ = DestinationStatus::kFailed; > > + // The parent class will do closing the connection > > + // and other resources. > > +} > > + > > > +//============================================================ > ================== > > +// UnixSocketType class > > > +//============================================================ > ================== > > +UnixSocketType UnixSocketType::me_; > > +const char UnixSocketType::name_[] = "UNIX_SOCKET"; > > + > > +UnixSocketType::UnixSocketType() {} > > + > > +UnixSocketType::~UnixSocketType() { > > + // Close all connections & stop the thread > > +} > > + > > +const std::string UnixSocketType::DestStatusToStr(DestinationStatus > status) { > > + switch (status) { > > + // Destination configured and is being connected to destination > > + case DestinationStatus::kActive: return "CONNECTED"; > > + // Destination configured and is being disconnected to destination > > + case DestinationStatus::kFailed: return "FAILED"; > > + default: return "UNKNOWN"; > > + } > > +} > > + > > +const std::string UnixSocketType::GetDestinationStatus( > > + const std::string& name) { > > + if (FindName(name) == false) return std::string{"UNKNOWN"}; > > + const UnixSocketHandler* sk = name_sockethdlr_map_[name]; > > + if (sk == nullptr) return std::string{"FAILED"}; > > + return DestStatusToStr(name_sockethdlr_map_[name]- > >GetSockStatus()); > > +} > > + > > +const VectorString UnixSocketType::GetAllDestStatus() { > > + VectorString output{}; > > + if (me_.name_sockethdlr_map_.size() == 0) return output; > > + for (const auto& it : me_.name_sockethdlr_map_) { > > + std::string status = it.first + "," + me_.GetDestinationStatus(it.first); > > + TRACE("%s status = %s", __func__, status.c_str()); > > + output.push_back(status); > > + } > > + return output; > > +} > > + > > +bool UnixSocketType::FindName(const std::string& name) const { > > + return ((name_sockethdlr_map_.find(name) == > name_sockethdlr_map_.end()) ? > > + (false) : (true)); > > +} > > + > > +UnixSocketHandler* UnixSocketType::GetDestHandle(const std::string& > name) { > > + if (FindName(name) == false) return nullptr; > > + return name_sockethdlr_map_[name]; > > +} > > + > > +const char* UnixSocketType::GetCfgValue(const std::string& name) { > > + if (FindName(name) == false) return nullptr; > > + UnixSocketHandler* sk = name_sockethdlr_map_[name]; > > + return (sk == nullptr) ? (nullptr) : > > + (name_sockethdlr_map_[name]->sock_path_.c_str()); > > +} > > + > > +ErrCode UnixSocketType::HandleRecordMsg( > > + const DestinationHandler::RecordMsg& msg) { > > + ErrCode ret = ErrCode::kOk; > > + // No destination configuration with this destination name > > + if (FindName(std::string{msg.name}) == false) { > > + LOG_WA("No such destination name(%s) configured", msg.name); > > + ret = ErrCode::kDrop; > > + return ret; > > + } > > + > > + // NIL destination - only have "name" and "type", but no "value". > > + if (GetDestHandle(std::string{msg.name}) == nullptr) { > > + LOG_NO("The destination name(%s) not yet configured", msg.name); > > + ret = ErrCode::kDrop; > > + return ret; > > + } > > + > > + // Send to destination end. > > + osafassert(name_sockethdlr_map_[std::string{msg.name}] != nullptr); > > + return name_sockethdlr_map_[std::string{msg.name}]->Send(msg.rec); > > +} > > + > > +ErrCode UnixSocketType::HandleCfgMsg( > > + const DestinationHandler::CfgDestMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + const std::string name{msg.name}; > > + const char* newcfg = msg.value; > > + > > + // Close and free previous @LocakSkDestHanlde instance if existing. > > + if (GetDestHandle(name) != nullptr) { > > + TRACE("%s delete old destination value for name (%s)", __func__, > msg.name); > > + delete name_sockethdlr_map_[name]; > > + name_sockethdlr_map_[name] = nullptr; > > + } > > + > > + // Request to create destination handler > > + if ((newcfg != nullptr) && (strlen(newcfg) > 0)) { > > + TRACE("%s add new destination name (%s)", __func__, msg.name); > > + // Create a new destination handler @UnixSocketHandler for @name > > + name_sockethdlr_map_[name] = new UnixSocketHandler(newcfg); > > + ret = (name_sockethdlr_map_[name] == nullptr) ? ErrCode::kNoMem : > ret; > > + return ret; > > + } else { > > + TRACE("%s create nildest with destination name (%s)", __func__, > msg.name); > > + // nildest case with format "name;type;" > > + name_sockethdlr_map_[name] = nullptr; > > + } > > + > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode UnixSocketType::HandleDelCfgMsg( > > + const DestinationHandler::DelDestMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + TRACE("%s remove destination name (%s)", __func__, msg.name); > > + const std::string name{msg.name}; > > + // Close and free @LocakSkDestHanlde instance if existing. > > + if (GetDestHandle(name) != nullptr) delete > name_sockethdlr_map_[name]; > > + // Erase from the map > > + name_sockethdlr_map_.erase(name); > > + TRACE_LEAVE(); > > + return ret; > > +} > > + > > +ErrCode UnixSocketType::ProcessMsg( > > + const DestinationHandler::HandleMsg& msg) { > > + TRACE_ENTER(); > > + ErrCode ret = ErrCode::kOk; > > + static bool cfgsent = false; > > + // The proper sequence should be: > > + // 1) kCfgDest : for configure destination handlers > > + // 2) kSendRecord: write log record to destination > > + // 3) kDelDest : delete specific destinations > > + // 4) kNoDest : delete all destinations > > + // Msg could be drop if the sequence is not correct. > > + switch (msg.type) { > > + case DestinationHandler::MsgType::kSendRecord: { > > + // No destination yet configured. Drop the message. > > + TRACE("%s %s", __func__, "RecordMsg msg"); > > + const DestinationHandler::RecordMsg& rmsg = msg.info.rec; > > + > > + // No destination has been configured so far. > > + if (cfgsent == false) { > > + LOG_WA("Destination handler not yet initialized. Drop msg."); > > + ret = ErrCode::kDrop; > > + } else { > > + ret = HandleRecordMsg(rmsg); > > + } > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kCfgDest: { > > + const DestinationHandler::CfgDestMsg& cmsg = msg.info.cfg; > > + TRACE("%s %s", __func__, "CfgDestMsg msg"); > > + ret = HandleCfgMsg(cmsg); > > + // Notice there at leat one destination configured. > > + if (ret == ErrCode::kOk) cfgsent = true; > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kDelDest: { > > + const DestinationHandler::DelDestMsg& dmsg = msg.info.del; > > + TRACE("%s %s", __func__, "DelDestMsg msg"); > > + // No destination yet configured. Drop the message. > > + if (cfgsent == false) { > > + LOG_NO("No destination configured yet. Drop msg."); > > + return ErrCode::kDrop; > > + } > > + ret = HandleDelCfgMsg(dmsg); > > + break; > > + } > > + > > + case DestinationHandler::MsgType::kNoDest: { > > + LOG_NO("%s %s", __func__, "DelAllCfgDest msg"); > > + if (cfgsent == false) { > > + LOG_NO("No destination configured yet"); > > + return ErrCode::kDrop; > > + } > > + > > + for (auto& it : name_sockethdlr_map_) { > > + if (it.second != nullptr) delete it.second; > > + name_sockethdlr_map_.erase(it.first); > > + } > > + cfgsent = false; > > + break; > > + } > > + > > + default: > > + LOG_ER("Unknown dispatch message type %d", > static_cast<int>(msg.type)); > > + ret = ErrCode::kInvalid; > > + } > > + > > + TRACE_LEAVE(); > > + return ret; > > +} > > diff --git a/src/log/logd/lgs_unixsock_dest.h > b/src/log/logd/lgs_unixsock_dest.h > > new file mode 100644 > > --- /dev/null > > +++ b/src/log/logd/lgs_unixsock_dest.h > > @@ -0,0 +1,245 @@ > > +/* -*- OpenSAF -*- > > + * > > + * Copyright Ericsson AB 2017 - All Rights Reserved. > > + * > > + * 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 > > + * > > + */ > > + > > +#ifndef SRC_LOG_LOGD_LGS_UNIXSOCK_DEST_H_ > > +#define SRC_LOG_LOGD_LGS_UNIXSOCK_DEST_H_ > > + > > +#include <string> > > +#include <map> > > + > > +#include "base/log_message.h" > > +#include "base/time.h" > > +#include "base/unix_client_socket.h" > > +#include "log/logd/lgs_common.h" > > +#include "log/logd/lgs_dest.h" > > + > > +//> > > +// Represent connection to local Unix Domain socket > > +// @UnixSocketHandler = Local Socket Destination class > > +// > > +// Each destination name will have its own instance > > +// of this class. It represents the connection > > +// to the destination. So, it contains connection status, > > +// and the sequence message ID @msg_id_, showing how many logrecord > > +// has been written to the socket. This sequence number > > +// helps to detect if there is any msg lost so far. > > +// > > +// When getting a send log record request, this class > > +// will form message complying with RFC5424 protocol, putting > > +// the log record which has been writen to local file at MSG field, > > +// also do fill information to other fields in protocol header. > > +// > > +// The instance of this class is only deleted if destination info (@value) > > +// is deleted from Destination Configuration attribute. > > +// > > +// It would be wrong if more than one instance of this class > > +// pointed to same Domain Unix Socket (same local path name). > > +// > > +// Regarding connection status, the status will be flushed to > > +// latest one at points: > > +// 1) Creating new destination: > > +// The instance will open a connection to destination, > > +// then update its status based on the file descriptor. > > +// > > +// 2) Change destination to new one: > > +// The previous connection is closed and opened a new one > > +// toward the destination, then update the status > > +// based on the file descriptor. > > +// > > +// 3) When writing log record to destination: > > +// This class is not aware of the destination whether > > +// the destination is dead or restarted. > > +// If it gets failed to write to socket, the status will be updated. > > +// just do that to detect the receiver on destination is dead/restarted. > > +// > > +// 4) Delete the destination > > +// When deleing destination, the instance will be deleted. > > +// Then, the status will be updated accordingly. > > +// > > +// All methods provided by this class should grant access > > +// to @UnixSocketType only. No one else can directly > > +// invoke any method of this class. > > +// > > +// With @Send(), if the msg get failed to send to destination, > > +// will log info to syslog and return the error code to upper layer. > > +// > > +// The other information on this class is that, within @Send() > > +// method, creating a very big stack buffer - over 65*1024 bytes > > +// even the sent RFC msg is quite short (e.g: rfc header + 150 bytes). > > +//< > > +class UnixSocketHandler { > > + public: > > + // Set stack size of buffer to maximum size. > > + static const uint32_t kBufMaxSize = 65*1024 + 1024; > > + // typedef, aim to shorten declaration. > > + using RfcBuffer = base::Buffer<kBufMaxSize>; > > + > > + // This class is only dedicated to UnixSocketType. > > + friend class UnixSocketType; > > + // Open and connect to the socket > > + void Open(); > > + // @Close Do nothing > > + void Close(); > > + // Form RFC5424 and send to the socket > > + ErrCode Send(const DestinationHandler::RecordInfo&); > > + // Get the socket status > > + DestinationStatus GetSockStatus(); > > + // Form rfc5424 syslog format > > + static void FormRfc5424( > > + const DestinationHandler::RecordInfo& msg, > > + RfcBuffer* buf); > > + > > + private: > > + explicit UnixSocketHandler(const char*); > > + ~UnixSocketHandler(); > > + > > + // Get the @status_ up-to-date > > + void FlushStatus(); > > + // Convert AIS log stream severity to syslog severity > > + static base::LogMessage::Severity Sev(uint16_t); > > + > > + // Hold destination info (@value) > > + std::string sock_path_; > > + base::UnixClientSocket sock_; > > + // Hold the connection status > > + DestinationStatus status_; > > + > > + DELETE_COPY_AND_MOVE_OPERATORS(UnixSocketHandler); > > +}; > > + > > +//> > > +// @UnixSocketType: Local Socket Destination Type > > +// > > +// This class represents local socket destination type. > > +// Every destinations name with local socket destination type > > +// must refer to one and only one instance of this class. > > +// Therefore, it has been designed as a singleton pattern. > > +// > > +// Outside world are not allowed to see any methods of this class > > +// except DestinationHandler. Right after analyzing DestinationHandler > messages, > > +// knowing what is the destination type, DestinationHandler will pass > > +// the message to this class via the unique instance. > > +// > > +// This class holds a map b/w destination name and @UnixSocketHandler > instance > > +// that represents the connection to destination for that destination > name. > > +// > > +// Based on what type of messages come to, it will take specific actions > > +// accordingly. > > +// 1) Create/Update destination message > > +// The message will contain destination name, destination type, > > +// and probably destination info (local socket path). > > +// Basing on the destination name, the Handler will sure that > > +// a) Any such destination name has been created before? > > +// b) And any @UnixSocketHandler instance is mapped to that > > +// destination name? > > +// If no destination name exist in the @map, then Hander will > > +// create a new pair <name, @UnixSocketHandler> and update its > destination. > > +// If the destination name already exist, will check if configuration info > > +// provided in the message is different with the existing or not. > > +// We expect it should be different with the existing, otherwise > > +// we have code fault somewhere. If different from the existing, closing > > +// the old connection, and creating new one and re-map to that name. > > +// > > +// 2) Sending log record message > > +// The message will contain destination name, log record, log stream > DN > > +// and other infos. Basing on the destination name, the Handler will > sure: > > +// a) Any such destination name has been created before? > > +// b) And any @UnixSocketHandler instance is mapped to that > > +// destination name? > > +// With this message, the Handler expects the destination name and > > +// @UnixSocketHandler must exist. Otherwise, there is a code > > +// fault somewhere. > > +// and the Handler will drop that message and log info to syslog. > > +// If as expected, the Handler will send the message to > > +// @UnixSocketHandler instance, in turn, > > +// it will form that message according to RF5424 format and > > +// send that message to local unix socket. > > +// > > +// 3) Delete destination message > > +// This message will contain only destination name. Basing on that info, > > +// the Hanlder will find that name in the @map to see any name is there. > > +// If have, do: > > +// 1) Close the connection > > +// 2) Free resources connected to that destination name > > +// Once destination name is deleted, any log record sent to destination > name > > +// will be drop or no writing to the destination happens. > > +//< > > +class UnixSocketType { > > + public: > > + // @UnixSocketType class is dedicated to @DestinationHandler class. > > + // Outside world is not granted to access to this class resources > > + friend class DestinationHandler; > > + > > + // Get @type that represents for @UnixSocketType. This type must be > unique. > > + static const std::string Type() { return std::string{name_}; } > > + > > + private: > > + // typedef for the map. Aim to shorten the type declaration. > > + using NameSockHdlrMap = std::map<std::string, UnixSocketHandler*>; > > + > > + UnixSocketType(); > > + ~UnixSocketType(); > > + > > + // Get @UnixSocketHandler instance which has been assigned > > + // to this destination @name > > + UnixSocketHandler* GetDestHandle(const std::string& name); > > + // Get configuration value that goes with this destination name @name > > + const char* GetCfgValue(const std::string& name); > > + // Find if any destination @name configured so far > > + bool FindName(const std::string&) const; > > + // Interpret the DestinationHandler msg and forward to right handle > > + ErrCode ProcessMsg(const DestinationHandler::HandleMsg&); > > + // Processing @Dispacher::RecordMsg msg, then forward to its instance > > + // @UnixSocketHandler to form RFC5424 syslog format before writing to > socket. > > + ErrCode HandleRecordMsg(const DestinationHandler::RecordMsg&); > > + // Processing @DestinationHandler::CfgDestMsg msg. Go thought all > destinations > > + // and create or update destination configuration depending on > contents. > > + ErrCode HandleCfgMsg(const DestinationHandler::CfgDestMsg&); > > + // Processing @DestinationHandler::CfgDestMsg msg. Go thought all > deleted > > + // destinations names, then do close connections and free resources. > > + ErrCode HandleDelCfgMsg(const DestinationHandler::DelDestMsg&); > > + // Get destination status for destination @name. > > + // The value could be: > > + // 1) "CONNECTED": destination @name is configured and connected to > other end. > > + // 2) "FAILED": destination @name is configured, but not able co connect > to. > > + // or no destination value has been given. > > + const std::string GetDestinationStatus(const std::string& name); > > + // Convert enum status to string > > + const std::string DestStatusToStr(DestinationStatus status); > > + // Get the unique instance represents this unique type > > + // This method should only be used by @DestinationHandler class > > + // Get all destination status for Local Socket Destination Typen > > + // @return a vector of status, with format > > + // {"name,active", "name2,inactive, etc."} > > + static const VectorString GetAllDestStatus(); > > + // Unique object instance for this @UnixSocketType class > > + static UnixSocketType& Instance() { return me_; } > > + // Unique instance for this class > > + static UnixSocketType me_; > > + // The type name of this @UnixSocketType (my identity). > > + // Must use this "type" name in destination configuration > > + // if want to destinate to local unix socket. > > + static const char name_[]; > > + > > + // Map b/w dest name and its own @UnixSocketHandler instance. > > + // Same @name must have same @UnixSocketHandler instance. > > + NameSockHdlrMap name_sockethdlr_map_; > > + > > + DELETE_COPY_AND_MOVE_OPERATORS(UnixSocketType); > > +}; > > + > > +#endif // SRC_LOG_LOGD_LGS_UNIXSOCK_DEST_H_ > > diff --git a/src/log/logd/lgs_util.cc b/src/log/logd/lgs_util.cc > > --- a/src/log/logd/lgs_util.cc > > +++ b/src/log/logd/lgs_util.cc > > @@ -837,6 +837,40 @@ bool lgs_is_extended_name_valid(const Sa > > return true; > > } > > > > > +//============================================================ > ================== > > +// logutil namespace > > > +//============================================================ > ================== > > +namespace logutil { > > + > > +// Split a string @str with delimiter @delimiter > > +// and return an vector of strings. > > +std::vector<std::string> Parser(const std::string& str, > > + const std::string& delimiter) { > > + std::vector<std::string> temp; > > + std::string s{str}; > > + size_t pos = 0; > > + while ((pos = s.find(delimiter)) != std::string::npos) { > > + temp.push_back(s.substr(0, pos)); > > + s.erase(0, pos + delimiter.length()); > > + } > > + temp.push_back(s); > > + return temp; > > +} > > + > > +bool isValidName(const std::string& name) { > > + // Valid name if @name not contain any characters outside > > + // of below strings. > > + const std::string validChar = "abcdefghijklmnopqrstuvwxyz" > > + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" > > + "01234567890_-"; > > + if (name.find_first_not_of(validChar) != std::string::npos) > > + return false; > > + > > + return true; > > +} > > + > > +}; // namespace logutil > > + > > /** > > * Check if severity filter is supported for client > > * > > diff --git a/src/log/logd/lgs_util.h b/src/log/logd/lgs_util.h > > --- a/src/log/logd/lgs_util.h > > +++ b/src/log/logd/lgs_util.h > > @@ -27,7 +27,7 @@ > > > > #include "osaf/saf/saAis.h" > > #include "amf/saf/saAmf.h" > > - > > +#include <vector> > > #include "lgs_stream.h" > > #include "lgs_evt.h" > > > > @@ -86,4 +86,13 @@ bool lgs_is_extended_name_valid(const Sa > > void lgs_send_severity_filter_to_clients(uint32_t stream_id, > > SaLogSeverityFlagsT serverity); > > > > +namespace logutil { > > +// Parse string format "a;b;c" to vector of string {a, b, c} > > +// In generic, this function could be used to split a string > > +// separated by delimiter to a vector of strings. > > +std::vector<std::string> Parser(const std::string&, const std::string&); > > +// Check if @name contain special characters in. > > +bool isValidName(const std::string& name); > > +}; // namespace logutil > > + > > #endif // LOG_LOGD_LGS_UTIL_H_ ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, SlashDot.org! http://sdm.link/slashdot _______________________________________________ Opensaf-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/opensaf-devel
