Hi Vu, 5.1 & 5.2 Release not related our parallel implementations 5.2 details , one release one version , so #2146 & #2258 both shoud use LGS_MBCSV_VERSION_6 6 , please do change .
-AVM On 2/24/2017 12:17 PM, Vu Minh Nguyen wrote: > 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
