osaf/libs/core/cplusplus/base/Makefile.am               |   13 +-
 osaf/libs/core/cplusplus/base/buffer.h                  |   94 ++++++++
 osaf/libs/core/cplusplus/base/log_message.cc            |  143 ++++++++++++
 osaf/libs/core/cplusplus/base/log_message.h             |  188 ++++++++++++++++
 osaf/libs/core/cplusplus/base/tests/Makefile.am         |   12 +-
 osaf/libs/core/cplusplus/base/tests/log_message_test.cc |  112 +++++++++
 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, 888 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,94 @@
+/*      -*- 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 the number of bytes that have been written to the buffer.
+  size_t size() const { return size_; }
+  // 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,143 @@
+/*      -*- 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 (ts.tv_nsec >= 0 && ts.tv_nsec < kNanosPerSec && local_ptr != nullptr) {
+    char time_zone[8];
+    int16_t time_zone_offset = 0;
+    size_t result = strftime(time_zone, sizeof(time_zone), "%z", local_ptr);
+    if (result == 5) {
+      int hours = int{time_zone[1] - '0'} * 10 + int{time_zone[2] - '0'};
+      int minutes = int{time_zone[3] - '0'} * 10 + int{time_zone[4] - '0'};
+      time_zone_offset = 60 * hours + minutes;
+      if (time_zone[0] == '-') time_zone_offset = -time_zone_offset;
+    }
+    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_min, 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);
+    }
+    if (time_zone_offset != 0) {
+      char sign;
+      int16_t offset;
+      if (time_zone_offset >= 0) {
+        sign = '+';
+        offset = time_zone_offset;
+      } else {
+        sign = '-';
+        offset = -time_zone_offset;
+      }
+      int16_t hours = offset / 60;
+      int16_t minutes = offset % 60;
+      buffer->AppendChar(sign);
+      buffer->AppendFixedWidthNumber(hours, 10);
+      buffer->AppendChar(':');
+      buffer->AppendFixedWidthNumber(minutes, 10);
+    } 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,188 @@
+/*      -*- 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);
+
+ private:
+  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,112 @@
+/*      -*- 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:26.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:26.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);
+}
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