Ack.

Thanks,
Ramesh.

On 10/10/2016 8:24 PM, Anders Widell wrote:
>   osaf/libs/core/cplusplus/base/Makefile.am               |   13 +-
>   osaf/libs/core/cplusplus/base/buffer.h                  |  100 ++++++++
>   osaf/libs/core/cplusplus/base/log_message.cc            |  130 +++++++++++
>   osaf/libs/core/cplusplus/base/log_message.h             |  186 
> ++++++++++++++++
>   osaf/libs/core/cplusplus/base/tests/Makefile.am         |   12 +-
>   osaf/libs/core/cplusplus/base/tests/log_message_test.cc |  150 ++++++++++++
>   osaf/libs/core/cplusplus/base/unix_client_socket.cc     |   52 ++++
>   osaf/libs/core/cplusplus/base/unix_client_socket.h      |   41 +++
>   osaf/libs/core/cplusplus/base/unix_server_socket.cc     |   51 ++++
>   osaf/libs/core/cplusplus/base/unix_server_socket.h      |   42 +++
>   osaf/libs/core/cplusplus/base/unix_socket.cc            |   58 ++++
>   osaf/libs/core/cplusplus/base/unix_socket.h             |   89 +++++++
>   12 files changed, 917 insertions(+), 7 deletions(-)
>
>
> Add support classes for using UNIX sockets, and for formatting log messages
> according to rfc5424.
>
> diff --git a/osaf/libs/core/cplusplus/base/Makefile.am 
> b/osaf/libs/core/cplusplus/base/Makefile.am
> --- a/osaf/libs/core/cplusplus/base/Makefile.am
> +++ b/osaf/libs/core/cplusplus/base/Makefile.am
> @@ -23,10 +23,15 @@ DEFAULT_INCLUDES =
>   SUBDIRS = tests
>   
>   noinst_HEADERS = \
> +     buffer.h \
>       getenv.h \
> +     log_message.h \
>       macros.h \
>       process.h \
> -     time.h
> +     time.h \
> +     unix_client_socket.h \
> +     unix_server_socket.h \
> +     unix_socket.h
>   
>   noinst_LTLIBRARIES = libbase.la
>   
> @@ -39,4 +44,8 @@ libbase_la_LDFLAGS = -static
>   
>   libbase_la_SOURCES = \
>       getenv.cc \
> -     process.cc
> +     log_message.cc \
> +     process.cc \
> +     unix_client_socket.cc \
> +     unix_server_socket.cc \
> +     unix_socket.cc
> diff --git a/osaf/libs/core/cplusplus/base/buffer.h 
> b/osaf/libs/core/cplusplus/base/buffer.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/buffer.h
> @@ -0,0 +1,100 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_BUFFER_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_BUFFER_H_
> +
> +#include <cstddef>
> +#include <cstdint>
> +#include <cstring>
> +#include "osaf/libs/core/cplusplus/base/macros.h"
> +
> +namespace base {
> +
> +// An output buffer that can be used to build e.g. a message to be sent over 
> a
> +// network.
> +class Buffer {
> + public:
> +  // Allocate a buffer with enough space to store @a capacity bytes of data.
> +  explicit Buffer(size_t capacity) :
> +      buffer_{new char[capacity]},
> +      capacity_{capacity},
> +      size_{0} {
> +  }
> +  ~Buffer() {
> +    delete [] buffer_;
> +  }
> +  // Reset the write position to the start of the buffer.
> +  void clear() { size_ = 0; }
> +  // Returns true if the buffer is empty.
> +  bool empty() const { return size_ == 0; }
> +  // Returns a pointer to the start of the buffer.
> +  const char* data() const { return buffer_; }
> +  // Returns a pointer to the end of the buffer where new data can be 
> appended.
> +  char* end() const { return buffer_ + size_; }
> +  // Returns the number of bytes that have been written to the buffer.
> +  size_t size() const { return size_; }
> +  // Set new size of the buffer (e.g. after manually adding data at the end).
> +  void set_size(size_t s) { size_ = s; }
> +  // Returns the maximum number of bytes that can be stored in this buffer.
> +  size_t capacity() const { return capacity_; }
> +  // Append a single character to the end of the buffer.
> +  void AppendChar(char c) {
> +    if (size_ != capacity_) buffer_[size_++] = c;
> +  }
> +  // This function is similar to AppendNumber(), except that leading zeros 
> will
> +  // be printed - i.e. this method implements a fixed field width.
> +  void AppendFixedWidthNumber(uint32_t number, uint32_t power) {
> +    for (;;) {
> +      uint32_t digit = number / power;
> +      AppendChar(digit + '0');
> +      if (power == 1) break;
> +      number -= digit * power;
> +      power /= 10;
> +    }
> +  }
> +  // Append decimal @a number to the end of the buffer. The @a power 
> parameter
> +  // must be a power of ten, pointing to the highest possible digit in the
> +  // decimal number. E.g. if @a power is 1000, then the @a number must not be
> +  // greater than 9999.
> +  void AppendNumber(uint32_t number, uint32_t power) {
> +    while (power != 1 && power > number) power /= 10;
> +    AppendFixedWidthNumber(number, power);
> +  }
> +  // Append a string of @a size characters to the end of the buffer.
> +  void AppendString(const char* str, size_t size) {
> +    size_t bytes_to_copy = capacity_ - size_;
> +    if (size < bytes_to_copy) bytes_to_copy = size;
> +    memcpy(buffer_ + size_, str, bytes_to_copy);
> +    size_ += bytes_to_copy;
> +  }
> +  // Append a NUL-terminated string to the end of the buffer.
> +  void AppendString(const char* str) {
> +    AppendString(str, strlen(str));
> +  }
> +
> + private:
> +  char* buffer_;
> +  size_t capacity_;
> +  size_t size_;
> +
> +  DELETE_COPY_AND_MOVE_OPERATORS(Buffer);
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_BUFFER_H_
> diff --git a/osaf/libs/core/cplusplus/base/log_message.cc 
> b/osaf/libs/core/cplusplus/base/log_message.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/log_message.cc
> @@ -0,0 +1,130 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "osaf/libs/core/cplusplus/base/log_message.h"
> +#include <time.h>
> +#include <cstdint>
> +#include "osaf/libs/core/common/include/osaf_time.h"
> +#include "osaf/libs/core/cplusplus/base/buffer.h"
> +#include "osaf/libs/core/cplusplus/base/time.h"
> +
> +namespace base {
> +
> +const struct timespec LogMessage::kNullTime{0, -1};
> +
> +void LogMessage::Write(Facility facility, Severity severity,
> +                       const struct timespec& time_stamp,
> +                       const HostName& host_name,
> +                       const AppName& app_name,
> +                       const ProcId& proc_id,
> +                       const MsgId& msg_id,
> +                       const StructuredElements& structured_elements,
> +                       const std::string& message,
> +                       Buffer* buffer) {
> +  uint32_t priority = static_cast<uint32_t>(facility) * uint32_t{8}
> +      + static_cast<uint32_t>(severity);
> +  buffer->AppendChar('<');
> +  buffer->AppendNumber(priority, 100);
> +  buffer->AppendString(">1 ", 3);
> +  WriteTime(time_stamp, buffer);
> +  buffer->AppendChar(' ');
> +  buffer->AppendString(host_name.data(), host_name.size());
> +  buffer->AppendChar(' ');
> +  buffer->AppendString(app_name.data(), app_name.size());
> +  buffer->AppendChar(' ');
> +  buffer->AppendString(proc_id.data(), proc_id.size());
> +  buffer->AppendChar(' ');
> +  buffer->AppendString(msg_id.data(), msg_id.size());
> +  buffer->AppendChar(' ');
> +  if (structured_elements.empty()) {
> +    buffer->AppendChar('-');
> +  } else {
> +    for (const auto& elem : structured_elements) elem.Write(buffer);
> +  }
> +  if (!message.empty()) {
> +    buffer->AppendChar(' ');
> +    buffer->AppendString(message.data(), message.size());
> +  }
> +}
> +
> +void LogMessage::WriteTime(const struct timespec& ts, Buffer* buffer) {
> +  struct tm local_time;
> +  struct tm* local_ptr = localtime_r(&ts.tv_sec, &local_time);
> +  if (local_ptr != nullptr && local_ptr->tm_year >= -1900
> +      && local_ptr->tm_year <= (9999 - 1900)
> +      && ts.tv_nsec >= 0 && ts.tv_nsec < kNanosPerSec) {
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_year + 1900, 1000);
> +    buffer->AppendChar('-');
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_mon + 1, 10);
> +    buffer->AppendChar('-');
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_mday, 10);
> +    buffer->AppendChar('T');
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_hour, 10);
> +    buffer->AppendChar(':');
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_min, 10);
> +    buffer->AppendChar(':');
> +    buffer->AppendFixedWidthNumber(local_ptr->tm_sec, 10);
> +    uint32_t decimals = ts.tv_nsec / 1000;
> +    if (decimals != 0) {
> +      uint32_t power = 100000;
> +      while (decimals % 10 == 0) {
> +        decimals /= 10;
> +        power /= 10;
> +      }
> +      buffer->AppendChar('.');
> +      buffer->AppendFixedWidthNumber(decimals, power);
> +    }
> +    char* buf = buffer->end();
> +    if ((buffer->capacity() - buffer->size()) >= 6 &&
> +        strftime(buf, 6, "%z", local_ptr) == 5) {
> +      if (buf[1] != '0' || buf[2] != '0' ||
> +          buf[3] != '0' || buf[4] != '0') {
> +        buf[5] = buf[4];
> +        buf[4] = buf[3];
> +        buf[3] = ':';
> +        buffer->set_size(buffer->size() + 6);
> +      } else {
> +        buffer->AppendChar('Z');
> +      }
> +    }
> +  } else {
> +    buffer->AppendChar('-');
> +  }
> +}
> +
> +void LogMessage::Element::Write(Buffer* buffer) const {
> +  buffer->AppendChar('[');
> +  buffer->AppendString(id_.data(), id_.size());
> +  for (const Parameter& param : parameter_list_) {
> +    buffer->AppendChar(' ');
> +    param.Write(buffer);
> +  }
> +  buffer->AppendChar(']');
> +}
> +
> +void LogMessage::Parameter::Write(Buffer* buffer) const {
> +  buffer->AppendString(name_.data(), name_.size());
> +  buffer->AppendChar('=');
> +  buffer->AppendChar('"');
> +  for (const char& c : value_) {
> +    if (c == '"' || c == '\\' || c == ']') buffer->AppendChar('\\');
> +    buffer->AppendChar(c);
> +  }
> +  buffer->AppendChar('"');
> +}
> +
> +}  // namespace base
> diff --git a/osaf/libs/core/cplusplus/base/log_message.h 
> b/osaf/libs/core/cplusplus/base/log_message.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/log_message.h
> @@ -0,0 +1,186 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_LOG_MESSAGE_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_LOG_MESSAGE_H_
> +
> +#include <list>
> +#include <set>
> +#include <string>
> +
> +namespace base {
> +
> +class Buffer;
> +
> +// The LogMessage class implements support for formatting log records 
> according
> +// to RFC 5424
> +class LogMessage {
> + public:
> +  class String {
> +   public:
> +    String(const char* str, const std::string::size_type size) :
> +        str_{size != 0 ? str : "-", size != 0 ? size : 1} {}
> +    String(const std::string& str, const std::string::size_type max_size) :
> +        str_{str.empty() ? std::string{"-"} : str.substr(0, max_size)} {}
> +    bool empty() const { return str_.empty(); }
> +    const char* c_str() const { return str_.c_str(); }
> +    const char* data() const { return str_.data(); }
> +    const std::string::size_type size() const { return str_.size(); }
> +    bool operator<(const String& str) const { return str_ < str.str_; }
> +    bool operator==(const String& str) const { return str_ == str.str_; }
> +   protected:
> +    constexpr static const bool IsPrintableAscii(char c) {
> +      return c >= 33 && c <= 126;
> +    }
> +    std::string str_;
> +  };
> +  // std::string extended with a maximum string length and a limitation that 
> all
> +  // characters must be printable ASCII. Empty strings are not allowed. When
> +  // creating an object of this class, the string is truncated if it exceeds 
> the
> +  // maximum string length. Characters outside the range of printable ASCII 
> will
> +  // be replaced with underscore characters (_). If the string is empty, it 
> will
> +  // be replaced with a single dash (-).
> +  template <std::string::size_type MaxSize>
> +  class PrintableAscii : public String {
> +   public:
> +    explicit PrintableAscii(const std::string& str) :
> +        String{str, MaxSize} {
> +      for (char& c : str_) if (!IsPrintableAscii(c)) c = '_';
> +    }
> +  };
> +  // std::string extended with a maximum string length of 32 characters and a
> +  // limitation that all characters must be printable ASCII. Empty strings 
> are
> +  // not allowed. The characters =, ] and " are not allowed. When creating an
> +  // object of this class, the string is truncated if it exceeds the maximum
> +  // string length. Illegal characters will be replaced with underscore
> +  // characters (_). If the string is empty, it will be replaced with a 
> single
> +  // dash (-).
> +  class SdName : public String {
> +   public:
> +    constexpr static const std::string::size_type kMaxSize = 32;
> +    explicit SdName(const std::string& sd_name) :
> +        String{sd_name, kMaxSize} {
> +      for (char& c : str_) {
> +        if (!IsPrintableAscii(c) || c == '=' || c == ']' || c == '"') c = 
> '_';
> +      }
> +    }
> +  };
> +  // Host name where the log record was created. Maximum length is 255 
> printable
> +  // ASCII characters.
> +  using HostName = PrintableAscii<255>;
> +  // Name of the application that created the log record. Maximum length is 
> 48
> +  // printable ASCII characters.
> +  using AppName = PrintableAscii<48>;
> +  // Process if of the application that created the log record. Maximum 
> length
> +  // is 128 printable ASCII characters.
> +  using ProcId = PrintableAscii<128>;
> +  // Message id of this log record. Maximum length is 32 printable ASCII
> +  // characters.
> +  using MsgId = PrintableAscii<32>;
> +  // The facility that produced this log record.
> +  enum class Facility {
> +    kKern = 0,
> +    kUser = 1,
> +    kMail = 2,
> +    kDaemon = 3,
> +    kAuth = 4,
> +    kSyslog = 5,
> +    kLpr = 6,
> +    kNews = 7,
> +    kUucp = 8,
> +    kCron = 9,
> +    kAuthPriv = 10,
> +    kFtp = 11,
> +    kNtp = 12,
> +    kAudit = 13,
> +    kAlert = 14,
> +    kClock = 15,
> +    kLocal0 = 16,
> +    kLocal1 = 17,
> +    kLocal2 = 18,
> +    kLocal3 = 19,
> +    kLocal4 = 20,
> +    kLocal5 = 21,
> +    kLocal6 = 22,
> +    kLocal7 = 23
> +  };
> +  // The severity level of this log record.
> +  enum class Severity {
> +    kEmerg = 0,
> +    kAlert = 1,
> +    kCrit = 2,
> +    kErr = 3,
> +    kWarning = 4,
> +    kNotice = 5,
> +    kInfo = 6,
> +    kDebug = 7
> +  };
> +  // A parameter/value pair for a structued element
> +  class Parameter {
> +   public:
> +    Parameter(const SdName& name, const std::string& value) :
> +        name_{name},
> +        value_{value} {}
> +    void Write(Buffer* buffer) const;
> +    bool operator==(const Parameter& param) const {
> +      return name_ == param.name_ && value_ == param.value_;
> +    }
> +   private:
> +    SdName name_;
> +    std::string value_;
> +  };
> +  // A list of parameter/value pairs for a structued element
> +  using ParameterList = std::list<Parameter>;
> +  // A stuctured element consisting of an identifier and a list of
> +  // parameter/value pairs.
> +  class Element {
> +   public:
> +    Element(const SdName& id,
> +            const ParameterList& parameter_list) :
> +        id_{id},
> +        parameter_list_{parameter_list} {}
> +    void Write(Buffer* buffer) const;
> +    bool operator<(const Element& elem) const { return id_ < elem.id_; }
> +    bool operator==(const Element& elem) const {
> +      return id_ == elem.id_ && parameter_list_ == elem.parameter_list_;
> +    }
> +   private:
> +    SdName id_;
> +    ParameterList parameter_list_;
> +  };
> +  // A set of stuctured elements. Each element must have a unique identifier.
> +  using StructuredElements = std::set<Element>;
> +  // kNullTime is intended to be used when the time the log record was 
> generated
> +  // is not known.
> +  static const struct timespec kNullTime;
> +  // Format a log record according to rfc5424 and write it to the provided
> +  // buffer.
> +  static void Write(Facility facility, Severity severity,
> +                    const struct timespec& time_stamp,
> +                    const HostName& host_name,
> +                    const AppName& app_name,
> +                    const ProcId& proc_id,
> +                    const MsgId& msg_id,
> +                    const StructuredElements& structured_elements,
> +                    const std::string& message,
> +                    Buffer* buffer);
> +  static void WriteTime(const struct timespec& ts, Buffer* buffer);
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_LOG_MESSAGE_H_
> diff --git a/osaf/libs/core/cplusplus/base/tests/Makefile.am 
> b/osaf/libs/core/cplusplus/base/tests/Makefile.am
> --- a/osaf/libs/core/cplusplus/base/tests/Makefile.am
> +++ b/osaf/libs/core/cplusplus/base/tests/Makefile.am
> @@ -32,17 +32,19 @@ libbase_test_CPPFLAGS = \
>   libbase_test_LDFLAGS = \
>       -pthread -lrt \
>       $(top_builddir)/osaf/libs/core/cplusplus/base/libbase_la-getenv.o \
> +     $(top_builddir)/osaf/libs/core/cplusplus/base/libbase_la-log_message.o \
>       $(top_builddir)/osaf/libs/core/cplusplus/base/libbase_la-process.o
>   
>   libbase_test_SOURCES = \
> +     getenv_test.cc \
> +     log_message_test.cc \
> +     mock_logtrace.cc \
> +     mock_osaf_abort.cc \
> +     mock_osafassert.cc \
>       time_add_test.cc \
> -     time_subtract_test.cc \
>       time_compare_test.cc \
>       time_convert_test.cc \
> -     getenv_test.cc \
> -     mock_logtrace.cc \
> -     mock_osafassert.cc \
> -     mock_osaf_abort.cc
> +     time_subtract_test.cc
>   
>   libbase_test_LDADD = \
>       $(GTEST_DIR)/lib/libgtest.la \
> diff --git a/osaf/libs/core/cplusplus/base/tests/log_message_test.cc 
> b/osaf/libs/core/cplusplus/base/tests/log_message_test.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/tests/log_message_test.cc
> @@ -0,0 +1,150 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include <time.h>
> +#include <cstdlib>
> +#include <cstring>
> +#include "gtest/gtest.h"
> +#include "osaf/libs/core/cplusplus/base/buffer.h"
> +#include "osaf/libs/core/cplusplus/base/log_message.h"
> +
> +static const struct timespec time_stamp_1 = { 1475749599, 497243812 };
> +static const struct timespec time_stamp_2 = { 1458469599, 97240812 };
> +
> +static const char hello_world_text_1[] = "<133>1 2016-10-06T12:26:39.497243"
> +    "+02:00 PL-42 log_message_test 24744 4711 "
> +    "[elem1 param1=\"value1\" param2=\"value2\"][elem2] hello, world!";
> +
> +static const char hello_world_text_2[] = "<191>1 2016-03-20T11:26:39.09724"
> +    "+01:00 dark_star - _ 12345678901234567890123456789012 "
> +    "[- -=\"\" a_b_c=\"d=e\\]f\"][_]  test ";
> +
> +static const char null_text[] = "<0>1 - - - - - -";
> +
> +TEST(LogMessageTest, WriteHelloWorld1) {
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf{256};
> +  base::LogMessage::Write(
> +      base::LogMessage::Facility::kLocal0,
> +      base::LogMessage::Severity::kNotice,
> +      time_stamp_1,
> +      base::LogMessage::HostName{"PL-42"},
> +      base::LogMessage::AppName{"log_message_test"},
> +      base::LogMessage::ProcId{"24744"},
> +      base::LogMessage::MsgId{"4711"},
> +      {{base::LogMessage::SdName{"elem1"},
> +          {base::LogMessage::Parameter{base::LogMessage::SdName{"param1"},
> +                  "value1"},
> +                
> base::LogMessage::Parameter{base::LogMessage::SdName{"param2"},
> +                      "value2"}}},
> +        {base::LogMessage::SdName{"elem2"},
> +          {}}},
> +      "hello, world!",
> +      &buf);
> +  EXPECT_EQ(buf.size(), sizeof(hello_world_text_1) - 1);
> +  EXPECT_EQ(memcmp(buf.data(),
> +                   hello_world_text_1,
> +                   sizeof(hello_world_text_1) - 1), 0);
> +}
> +
> +TEST(LogMessageTest, WriteHelloWorld2) {
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf{256};
> +  base::LogMessage::Write(
> +      base::LogMessage::Facility::kLocal7,
> +      base::LogMessage::Severity::kDebug,
> +      time_stamp_2,
> +      base::LogMessage::HostName{"dark star"},
> +      base::LogMessage::AppName{""},
> +      base::LogMessage::ProcId{"_"},
> +      base::LogMessage::MsgId{"123456789012345678901234567890123"},
> +      {{base::LogMessage::SdName{""},
> +          {base::LogMessage::Parameter{base::LogMessage::SdName{""},
> +                  ""},
> +                
> base::LogMessage::Parameter{base::LogMessage::SdName{"a=b]c"},
> +                      "d=e]f"}}},
> +        {base::LogMessage::SdName{"_"},
> +          {}}},
> +      " test ",
> +      &buf);
> +  EXPECT_EQ(buf.size(), sizeof(hello_world_text_2) - 1);
> +  EXPECT_EQ(memcmp(buf.data(),
> +                   hello_world_text_2,
> +                   sizeof(hello_world_text_2) - 1), 0);
> +}
> +
> +TEST(LogMessageTest, WriteNullMessage) {
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf(256);
> +  base::LogMessage::Write(
> +      base::LogMessage::Facility::kKern,
> +      base::LogMessage::Severity::kEmerg,
> +      base::LogMessage::kNullTime,
> +      base::LogMessage::HostName{""},
> +      base::LogMessage::AppName{""},
> +      base::LogMessage::ProcId{""},
> +      base::LogMessage::MsgId{""},
> +      {},
> +      "",
> +      &buf);
> +
> +  EXPECT_EQ(buf.size(), sizeof(null_text) - 1);
> +  EXPECT_EQ(memcmp(buf.data(),
> +                   null_text,
> +                   sizeof(null_text) - 1), 0);
> +}
> +
> +TEST(LogMessageTimeTest, WriteBCTime) {
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf(256);
> +  base::LogMessage::WriteTime({-62188992000, 0}, &buf);
> +  EXPECT_EQ(buf.size(), 1);
> +  EXPECT_EQ(memcmp(buf.data(), "-", 1), 0);
> +}
> +
> +TEST(LogMessageTimeTest, WriteFarFutureTime) {
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf(256);
> +  base::LogMessage::WriteTime({253423296000, 0}, &buf);
> +  EXPECT_EQ(buf.size(), 1);
> +  EXPECT_EQ(memcmp(buf.data(), "-", 1), 0);
> +}
> +
> +TEST(LogMessageTimeTest, WriteTimeInSmallBuffer) {
> +  static const char expected_result[] = "2016-10-10T16:24:02.505489";
> +  setenv("TZ", "Europe/Stockholm", 1);
> +  tzset();
> +  base::Buffer buf(30);
> +  base::LogMessage::WriteTime({1476109442, 505489184}, &buf);
> +  EXPECT_EQ(buf.size(), sizeof(expected_result) - 1);
> +  EXPECT_EQ(memcmp(buf.data(), expected_result, buf.size()), 0);
> +}
> +
> +TEST(LogMessageTimeTest, WriteTimeWithUtcTimeZone) {
> +  static const char expected_result[] = "2016-10-10T14:33:32.82328Z";
> +  setenv("TZ", "UTC", 1);
> +  tzset();
> +  base::Buffer buf(256);
> +  base::LogMessage::WriteTime({1476110012, 823280288}, &buf);
> +  EXPECT_EQ(buf.size(), sizeof(expected_result) - 1);
> +  EXPECT_EQ(memcmp(buf.data(), expected_result, buf.size()), 0);
> +}
> diff --git a/osaf/libs/core/cplusplus/base/unix_client_socket.cc 
> b/osaf/libs/core/cplusplus/base/unix_client_socket.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_client_socket.cc
> @@ -0,0 +1,52 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "osaf/libs/core/cplusplus/base/unix_client_socket.h"
> +#include <sys/socket.h>
> +#include <time.h>
> +#include <cerrno>
> +
> +namespace base {
> +
> +UnixClientSocket::UnixClientSocket(const std::string& path) :
> +    UnixSocket{path} {
> +}
> +
> +UnixClientSocket::~UnixClientSocket() {
> +}
> +
> +void UnixClientSocket::Open() {
> +  if (fd() < 0) {
> +    UnixSocket::Open();
> +    if (fd() >= 0) {
> +      int result;
> +      int e;
> +      do {
> +        result = connect(fd(), addr(), addrlen());
> +        e = errno;
> +        if (result != 0 && (e == EALREADY || e == EINPROGRESS)) {
> +          struct timespec delay{0, 10000000};
> +          clock_nanosleep(CLOCK_MONOTONIC, 0, &delay, nullptr);
> +        }
> +      } while (result != 0 && (e == EINTR || e == EALREADY
> +                               || e == EINPROGRESS));
> +      if (result != 0) Close();
> +    }
> +  }
> +}
> +
> +}  // namespace base
> diff --git a/osaf/libs/core/cplusplus/base/unix_client_socket.h 
> b/osaf/libs/core/cplusplus/base/unix_client_socket.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_client_socket.h
> @@ -0,0 +1,41 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_CLIENT_SOCKET_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_CLIENT_SOCKET_H_
> +
> +#include <string>
> +#include "osaf/libs/core/cplusplus/base/unix_socket.h"
> +
> +namespace base {
> +
> +// A class implementing a non-blocking UNIX domain client socket.
> +class UnixClientSocket : public UnixSocket {
> + public:
> +  // Set the path name for this client socket. Note that this call does not
> +  // create the socket - you need to call Send() or Recv() for that to 
> happen.
> +  explicit UnixClientSocket(const std::string& path);
> +  // Closes the client socket if it was open, but does not delete the socket
> +  // from the file system.
> +  virtual ~UnixClientSocket();
> + protected:
> +  virtual void Open();
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_CLIENT_SOCKET_H_
> diff --git a/osaf/libs/core/cplusplus/base/unix_server_socket.cc 
> b/osaf/libs/core/cplusplus/base/unix_server_socket.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_server_socket.cc
> @@ -0,0 +1,51 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "osaf/libs/core/cplusplus/base/unix_server_socket.h"
> +#include <sys/socket.h>
> +#include <unistd.h>
> +#include <cerrno>
> +
> +namespace base {
> +
> +UnixServerSocket::UnixServerSocket(const std::string& path) :
> +    UnixSocket{path} {
> +}
> +
> +UnixServerSocket::~UnixServerSocket() {
> +}
> +
> +void UnixServerSocket::Open() {
> +  if (fd() < 0) {
> +    UnixSocket::Open();
> +    if (fd() >= 0) {
> +      int result = bind(fd(), addr(), addrlen());
> +      if (result != 0) Close();
> +    }
> +  }
> +}
> +
> +void UnixServerSocket::Close() {
> +  if (fd() >= 0) {
> +    int e = errno;
> +    UnixSocket::Close();
> +    unlink(path());
> +    errno = e;
> +  }
> +}
> +
> +}  // namespace base
> diff --git a/osaf/libs/core/cplusplus/base/unix_server_socket.h 
> b/osaf/libs/core/cplusplus/base/unix_server_socket.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_server_socket.h
> @@ -0,0 +1,42 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SERVER_SOCKET_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SERVER_SOCKET_H_
> +
> +#include <string>
> +#include "osaf/libs/core/cplusplus/base/unix_socket.h"
> +
> +namespace base {
> +
> +// A class implementing a non-blocking UNIX domain server socket.
> +class UnixServerSocket : public UnixSocket {
> + public:
> +  // Set the path name for this server socket. Note that this call does not
> +  // create the socket - you need to call Send() or Recv() for that to 
> happen.
> +  explicit UnixServerSocket(const std::string& path);
> +  // Closes the server socket if it was open, and deletes the socket from the
> +  // file system.
> +  virtual ~UnixServerSocket();
> + protected:
> +  virtual void Open();
> +  virtual void Close();
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SERVER_SOCKET_H_
> diff --git a/osaf/libs/core/cplusplus/base/unix_socket.cc 
> b/osaf/libs/core/cplusplus/base/unix_socket.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_socket.cc
> @@ -0,0 +1,58 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "osaf/libs/core/cplusplus/base/unix_socket.h"
> +#include <sys/socket.h>
> +#include <unistd.h>
> +#include <cstring>
> +
> +namespace base {
> +
> +UnixSocket::UnixSocket(const std::string& path) :
> +    fd_{-1},
> +    addr_{AF_UNIX, {}} {
> +  if (path.size() < sizeof(addr_.sun_path)) {
> +    memcpy(addr_.sun_path, path.c_str(), path.size() + 1);
> +  } else {
> +    addr_.sun_path[0] = '\0';
> +  }
> +}
> +
> +void UnixSocket::Open() {
> +  if (fd_ < 0) {
> +    if (addr_.sun_path[0] != '\0') {
> +      fd_ = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
> +    } else {
> +      errno = ENAMETOOLONG;
> +    }
> +  }
> +}
> +
> +UnixSocket::~UnixSocket() {
> +  Close();
> +}
> +
> +void UnixSocket::Close() {
> +  if (fd_ >= 0) {
> +    int e = errno;
> +    close(fd_);
> +    errno = e;
> +    fd_ = -1;
> +  }
> +}
> +
> +}  // namespace base
> diff --git a/osaf/libs/core/cplusplus/base/unix_socket.h 
> b/osaf/libs/core/cplusplus/base/unix_socket.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/libs/core/cplusplus/base/unix_socket.h
> @@ -0,0 +1,89 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF Foundation
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
> + * under the GNU Lesser General Public License Version 2.1, February 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SOCKET_H_
> +#define OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SOCKET_H_
> +
> +#include <sys/socket.h>
> +#include <sys/un.h>
> +#include <cerrno>
> +#include <string>
> +#include "osaf/libs/core/cplusplus/base/macros.h"
> +
> +namespace base {
> +
> +// A class implementing non-blocking operations on a UNIX domain socket.
> +class UnixSocket {
> + public:
> +  // Close the socket.
> +  virtual ~UnixSocket();
> +  // Send a message in non-blocking mode. This call will open the socket if 
> it
> +  // was not already open. The EINTR error code from the send() libc 
> function is
> +  // handled by retrying the send() call in a loop. In case of other errors, 
> the
> +  // socket will be closed.
> +  ssize_t Send(const void* buffer, size_t length) {
> +    if (fd_ < 0) Open();
> +    ssize_t result = -1;
> +    if (fd_ >= 0) {
> +      do {
> +        result = send(fd_, buffer, length, MSG_NOSIGNAL);
> +      } while (result < 0 && errno == EINTR);
> +      if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) Close();
> +    }
> +    return result;
> +  }
> +  // Receive a message in non-blocking mode. This call will open the socket 
> if
> +  // it was not already open. The EINTR error code from the recv() libc 
> function
> +  // is handled by retrying the recv() call in a loop. In case of other 
> errors,
> +  // the socket will be closed.
> +  ssize_t Recv(void* buffer, size_t length) {
> +    if (fd_ < 0) Open();
> +    ssize_t result = -1;
> +    if (fd_ >= 0) {
> +      do {
> +        result = recv(fd_, buffer, length, 0);
> +      } while (result < 0 && errno == EINTR);
> +      if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) Close();
> +    }
> +    return result;
> +  }
> +  // Returns the current file descriptor for this UNIX socket, or -1 if the
> +  // socket is currently not open. Note that the Send() and Recv() methods 
> may
> +  // open and/or close the socket, and potentially the file descriptor will 
> be
> +  // different after a call to any of these two methods.
> +  int fd() const { return fd_; }
> +
> + protected:
> +  explicit UnixSocket(const std::string& path);
> +  virtual void Open();
> +  virtual void Close();
> +  const struct sockaddr* addr() const {
> +    return reinterpret_cast<const struct sockaddr*>(&addr_);
> +  }
> +  static socklen_t addrlen() { return sizeof(addr_); }
> +  const char* path() const { return addr_.sun_path; }
> +
> + private:
> +  int fd_;
> +  struct sockaddr_un addr_;
> +
> +  DELETE_COPY_AND_MOVE_OPERATORS(UnixSocket);
> +};
> +
> +}  // namespace base
> +
> +#endif  // OSAF_LIBS_CORE_CPLUSPLUS_BASE_UNIX_SOCKET_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
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to