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
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel