osaf/services/infrastructure/dtms/scripts/osaf-transport.in | 2 +
osaf/services/infrastructure/dtms/transport/Makefile.am | 4 +
osaf/services/infrastructure/dtms/transport/log_server.cc | 62 +++++
osaf/services/infrastructure/dtms/transport/log_server.h | 49 ++++
osaf/services/infrastructure/dtms/transport/log_writer.cc | 111
++++++++++
osaf/services/infrastructure/dtms/transport/log_writer.h | 68 ++++++
osaf/services/infrastructure/dtms/transport/main.cc | 105
++++++++-
osaf/services/infrastructure/dtms/transport/transport_monitor.cc | 35 +--
osaf/services/infrastructure/dtms/transport/transport_monitor.h | 28 +-
9 files changed, 396 insertions(+), 68 deletions(-)
Add a new thread that reads MDS log messages from a UNIX socket and writes them
to disk. Rotate the MDS log file when it exceeds the maximum file size limit.
diff --git a/osaf/services/infrastructure/dtms/scripts/osaf-transport.in
b/osaf/services/infrastructure/dtms/scripts/osaf-transport.in
--- a/osaf/services/infrastructure/dtms/scripts/osaf-transport.in
+++ b/osaf/services/infrastructure/dtms/scripts/osaf-transport.in
@@ -34,6 +34,7 @@ RETVAL=0
binary=$pkglibdir/$osafprog
pidfile=$pkgpiddir/$osafprog.pid
lockfile=$lockdir/$initscript
+sockfile=$pkglocalstatedir/mds_log.sock
start() {
[ -p $NIDFIFO ] || return 1
@@ -100,6 +101,7 @@ stop() {
killproc -p "$pidfile" "$osafprog"
RETVAL=$?
if [ "$RETVAL" -eq 0 ] || [ "$RETVAL" -eq 7 ]; then
+ rm -f "$sockfile"
rm -f "$lockfile"
RETVAL=0
fi
diff --git a/osaf/services/infrastructure/dtms/transport/Makefile.am
b/osaf/services/infrastructure/dtms/transport/Makefile.am
--- a/osaf/services/infrastructure/dtms/transport/Makefile.am
+++ b/osaf/services/infrastructure/dtms/transport/Makefile.am
@@ -23,6 +23,8 @@ DEFAULT_INCLUDES =
SUBDIRS = tests
noinst_HEADERS = \
+ log_server.h \
+ log_writer.h \
transport_monitor.h
osaf_execbindir = $(pkglibdir)
@@ -34,6 +36,8 @@ osaftransportd_CPPFLAGS = \
$(AM_CPPFLAGS)
osaftransportd_SOURCES = \
+ log_server.cc \
+ log_writer.cc \
transport_monitor.cc \
main.cc
diff --git a/osaf/services/infrastructure/dtms/transport/log_server.cc
b/osaf/services/infrastructure/dtms/transport/log_server.cc
new file mode 100644
--- /dev/null
+++ b/osaf/services/infrastructure/dtms/transport/log_server.cc
@@ -0,0 +1,62 @@
+/* -*- 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/services/infrastructure/dtms/transport/log_server.h"
+#include "./configmake.h"
+#include "osaf/libs/core/common/include/osaf_poll.h"
+#include "osaf/libs/core/cplusplus/base/getenv.h"
+#include "osaf/libs/core/cplusplus/base/time.h"
+
+LogServer::LogServer(int term_fd)
+ : term_fd_{term_fd},
+ log_socket_{base::GetEnv<std::string>("pkglocalstatedir",
+ PKGLOCALSTATEDIR) + "/mds_log.sock"},
+ log_writer_{} {
+}
+
+LogServer::~LogServer() {
+}
+
+void LogServer::Run() {
+ struct pollfd pfd[2] = {
+ {term_fd_, POLLIN, 0},
+ {log_socket_.fd(), POLLIN, 0}
+ };
+ struct timespec last_flush = base::ReadMonotonicClock();
+ do {
+ for (int i = 0; i < 256; ++i) {
+ char* buffer = log_writer_.current_buffer_position();
+ ssize_t result = log_socket_.Recv(buffer, LogWriter::kMaxMessageSize);
+ if (result < 0) break;
+ while (result != 0 && buffer[result - 1] == '\n') --result;
+ if (static_cast<size_t>(result) != LogWriter::kMaxMessageSize) {
+ buffer[result++] = '\n';
+ } else {
+ buffer[result - 1] = '\n';
+ }
+ log_writer_.Write(result);
+ }
+ struct timespec current = base::ReadMonotonicClock();
+ if ((current - last_flush) >= base::kFifteenSeconds) {
+ log_writer_.Flush();
+ last_flush = current;
+ }
+ struct timespec timeout = (last_flush + base::kFifteenSeconds) - current;
+ pfd[1].fd = log_socket_.fd();
+ osaf_ppoll(pfd, 2, &timeout, nullptr);
+ } while ((pfd[0].revents & POLLIN) == 0);
+}
diff --git a/osaf/services/infrastructure/dtms/transport/log_server.h
b/osaf/services/infrastructure/dtms/transport/log_server.h
new file mode 100644
--- /dev/null
+++ b/osaf/services/infrastructure/dtms/transport/log_server.h
@@ -0,0 +1,49 @@
+/* -*- 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_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_SERVER_H_
+#define OSAF_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_SERVER_H_
+
+#include <cstddef>
+#include <string>
+#include "osaf/libs/core/cplusplus/base/macros.h"
+#include "osaf/libs/core/cplusplus/base/unix_server_socket.h"
+#include "osaf/services/infrastructure/dtms/transport/log_writer.h"
+
+// This class implements a loop that receives log messages over a UNIX socket
+// and sends them to a LogWriter instance.
+class LogServer {
+ public:
+ // @a term_fd is a file descriptor that will become readable when the program
+ // should exit because it has received the SIGTERM signal.
+ explicit LogServer(int term_fd);
+ virtual ~LogServer();
+
+ // Run in a loop, receiving log messages over the UNIX socket until the
+ // process has received the SIGTERM signal, which is indicated by the caller
+ // by making the term_fd (provided in the constructor) readable.
+ void Run();
+
+ private:
+ int term_fd_;
+ base::UnixServerSocket log_socket_;
+ LogWriter log_writer_;
+
+ DELETE_COPY_AND_MOVE_OPERATORS(LogServer);
+};
+
+#endif // OSAF_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_SERVER_H_
diff --git a/osaf/services/infrastructure/dtms/transport/log_writer.cc
b/osaf/services/infrastructure/dtms/transport/log_writer.cc
new file mode 100644
--- /dev/null
+++ b/osaf/services/infrastructure/dtms/transport/log_writer.cc
@@ -0,0 +1,111 @@
+/* -*- 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/services/infrastructure/dtms/transport/log_writer.h"
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <cerrno>
+#include <cstdio>
+#include "./configmake.h"
+#include "osaf/libs/core/cplusplus/base/getenv.h"
+
+LogWriter::LogWriter()
+ : mds_log_file_{base::GetEnv<std::string>("pkglogdir", PKGLOGDIR)
+ + "/mds.log"},
+ old_mds_log_file_{mds_log_file_ + ".old"},
+ fd_{-1},
+ current_file_size_{0},
+ current_buffer_size_{0},
+ buffer_{new char[kBufferSize]} {
+}
+
+LogWriter::~LogWriter() {
+ Flush();
+ Close();
+ delete [] buffer_;
+}
+
+void LogWriter::Open() {
+ if (fd_ < 0) {
+ int fd;
+ do {
+ fd = open(mds_log_file(), O_WRONLY | O_CLOEXEC | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ } while (fd == -1 && errno == EINTR);
+ if (fd >= 0) {
+ fd_ = fd;
+ current_file_size_ = FileSize(fd);
+ }
+ }
+}
+
+void LogWriter::Close() {
+ int fd = fd_;
+ if (fd >= 0) {
+ close(fd);
+ fd_ = -1;
+ current_file_size_ = 0;
+ }
+}
+
+void LogWriter::RotateLog() {
+ Close();
+ unlink(old_mds_log_file());
+ if (rename(mds_log_file(), old_mds_log_file()) != 0) {
+ unlink(mds_log_file());
+ }
+}
+
+void LogWriter::Write(size_t size) {
+ current_buffer_size_ += size;
+ if (current_buffer_size_ > kBufferSize - kMaxMessageSize) Flush();
+}
+
+void LogWriter::Flush() {
+ size_t size = current_buffer_size_;
+ if (size == 0) return;
+ if (fd_ < 0) Open();
+ if (fd_ < 0) return;
+ if (current_file_size_ >= kMaxFileSize) {
+ RotateLog();
+ if (fd_ < 0) Open();
+ if (fd_ < 0) return;
+ }
+ size_t bytes_written = 0;
+ while (bytes_written < size) {
+ ssize_t result = write(fd_, buffer_ + bytes_written, size - bytes_written);
+ if (result < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) continue;
+ break;
+ }
+ bytes_written += result;
+ }
+ current_buffer_size_ = 0;
+ current_file_size_ += bytes_written;
+}
+
+size_t LogWriter::FileSize(int fd) {
+ struct stat stat_buf;
+ size_t file_size;
+ if (fstat(fd, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) != 0) {
+ file_size = static_cast<size_t>(stat_buf.st_blocks) * 512;
+ } else {
+ file_size = 0;
+ }
+ return file_size;
+}
diff --git a/osaf/services/infrastructure/dtms/transport/log_writer.h
b/osaf/services/infrastructure/dtms/transport/log_writer.h
new file mode 100644
--- /dev/null
+++ b/osaf/services/infrastructure/dtms/transport/log_writer.h
@@ -0,0 +1,68 @@
+/* -*- 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_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_WRITER_H_
+#define OSAF_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_WRITER_H_
+
+#include <cstddef>
+#include <string>
+#include "osaf/libs/core/cplusplus/base/macros.h"
+
+// This class is responsible for writing MDS log messages to disk, and rotating
+// the log file when it exceeds the maximum file size limit.
+class LogWriter {
+ public:
+ constexpr static const size_t kMaxMessageSize = 2 * size_t{1024};
+
+ LogWriter();
+ virtual ~LogWriter();
+
+ char* current_buffer_position() { return buffer_ + current_buffer_size_; }
+
+ // Write @a size bytes of log message data in the memory pointed to by @a
+ // buffer to the MDS log file. After the log message has been written, the
+ // file will be rotated if necessary. This method performs blocking file I/O.
+ void Write(size_t size);
+ void Flush();
+
+ private:
+ constexpr static const size_t kBufferSize = 128 * size_t{1024};
+ constexpr static const size_t kMaxFileSize = 5000 * size_t{1024};
+ static size_t FileSize(int fd);
+ void Open();
+ void Close();
+ void RotateLog();
+
+ const char* mds_log_file() const {
+ return mds_log_file_.c_str();
+ }
+
+ const char* old_mds_log_file() const {
+ return old_mds_log_file_.c_str();
+ }
+
+ const std::string mds_log_file_;
+ const std::string old_mds_log_file_;
+ int fd_;
+ size_t current_file_size_;
+ size_t current_buffer_size_;
+ char* buffer_;
+
+ DELETE_COPY_AND_MOVE_OPERATORS(LogWriter);
+};
+
+#endif // OSAF_SERVICES_INFRASTRUCTURE_DTMS_TRANSPORT_LOG_WRITER_H_
diff --git a/osaf/services/infrastructure/dtms/transport/main.cc
b/osaf/services/infrastructure/dtms/transport/main.cc
--- a/osaf/services/infrastructure/dtms/transport/main.cc
+++ b/osaf/services/infrastructure/dtms/transport/main.cc
@@ -15,22 +15,78 @@
*
*/
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <unistd.h>
+#include <pthread.h>
+#include <sched.h>
+#include <syslog.h>
+#include <cerrno>
#include <cstdlib>
#include "osaf/libs/core/common/include/daemon.h"
#include "osaf/libs/core/include/ncssysf_def.h"
+#include "osaf/services/infrastructure/dtms/transport/log_server.h"
#include "osaf/services/infrastructure/dtms/transport/transport_monitor.h"
constexpr static const int kDaemonStartWaitTimeInSeconds = 15;
-int main(int argc, char** argv) {
- opensaf_reboot_prepare();
- daemonize(argc, argv);
- int term_fd;
- daemon_sigterm_install(&term_fd);
+enum Termination {
+ kExit,
+ kDaemonExit,
+ kReboot
+};
+
+struct Result {
+ Result(Termination t, const char* m, int e) :
+ term{t}, msg{m}, error{e} {}
+ Termination term;
+ const char* msg;
+ int error;
+};
+
+static void* LogServerStartFunction(void* instance) {
+ LogServer* log_server = static_cast<LogServer*>(instance);
+ log_server->Run();
+ return nullptr;
+}
+
+Result MainFunction(int term_fd) {
+ pthread_attr_t attr;
+ int result = pthread_attr_init(&attr);
+ if (result != 0) return Result{kExit, "pthread_attr_init() failed", result};
+ result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "pthread_attr_setscope() failed", result};
+ }
+ result = pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "pthread_attr_setschedpolicy() failed", result};
+ }
+ struct sched_param param{};
+ param.sched_priority = sched_get_priority_min(SCHED_OTHER);
+ if (param.sched_priority == -1) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "sched_get_priority_min() failed", errno};
+ }
+ result = pthread_attr_setschedparam(&attr, ¶m);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "pthread_attr_setschedparam() failed", result};
+ }
+ result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "pthread_attr_setinheritsched() failed", result};
+ }
+ LogServer log_server{term_fd};
+ pthread_t thread_id;
+ result = pthread_create(&thread_id, &attr,
+ LogServerStartFunction, &log_server);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return Result{kExit, "pthread_create() failed", result};
+ }
+ result = pthread_attr_destroy(&attr);
+ if (result != 0) return Result{kExit, "pthread_attr_destroy() failed",
result};
TransportMonitor monitor{term_fd};
pid_t pid = pid_t{0};
if (!monitor.use_tipc()) {
@@ -38,15 +94,36 @@ int main(int argc, char** argv) {
}
const char* msg;
if (pid != pid_t{-1}) {
- monitor.RotateMdsLogs(pid);
+ monitor.SuperviseDaemon(pid);
msg = "osafdtmd Process down, Rebooting the node";
} else {
msg = "osafdtmd failed to start";
}
- if (!monitor.Sleep(0)) {
- opensaf_reboot(0, nullptr, msg);
- } else {
- daemon_exit();
+ result = pthread_join(thread_id, nullptr);
+ if (result != 0) syslog(LOG_ERR, "pthread_join() failed: %d", result);
+ return Result{monitor.Sleep(0) ? kDaemonExit : kReboot, msg, 0};
+}
+
+int main(int argc, char** argv) {
+ opensaf_reboot_prepare();
+ daemonize(argc, argv);
+ int term_fd;
+ daemon_sigterm_install(&term_fd);
+ Result result = MainFunction(term_fd);
+ switch (result.term) {
+ case kExit:
+ if (result.error != 0) {
+ syslog(LOG_ERR, "%s: %d", result.msg, result.error);
+ } else {
+ syslog(LOG_ERR, "%s", result.msg);
+ }
+ break;
+ case kDaemonExit:
+ daemon_exit();
+ break;
+ case kReboot:
+ opensaf_reboot(0, nullptr, result.msg);
+ break;
}
return EXIT_FAILURE;
}
diff --git a/osaf/services/infrastructure/dtms/transport/transport_monitor.cc
b/osaf/services/infrastructure/dtms/transport/transport_monitor.cc
--- a/osaf/services/infrastructure/dtms/transport/transport_monitor.cc
+++ b/osaf/services/infrastructure/dtms/transport/transport_monitor.cc
@@ -15,12 +15,8 @@
*
*/
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
#include "osaf/services/infrastructure/dtms/transport/transport_monitor.h"
#include <sys/stat.h>
-#include <cstdio>
#include <fstream>
#include "./configmake.h"
#include "osaf/libs/core/common/include/osaf_poll.h"
@@ -30,9 +26,6 @@ TransportMonitor::TransportMonitor(int t
: term_fd_{term_fd},
pkgpiddir_{base::GetEnv<std::string>("pkgpiddir", PKGPIDDIR)},
proc_path_{"/proc/"},
- mds_log_file_{base::GetEnv<std::string>("pkglogdir", PKGLOGDIR)
- + "/mds.log"},
- old_mds_log_file_{mds_log_file_ + ".old"},
use_tipc_{base::GetEnv<std::string>("MDS_TRANSPORT", "TCP") == "TIPC"} {
}
@@ -64,32 +57,10 @@ bool TransportMonitor::IsDir(const std::
return stat_result == 0 && S_ISDIR(stat_buf.st_mode) != 0;
}
-void TransportMonitor::RotateMdsLogs(pid_t pid_to_watch) {
+void TransportMonitor::SuperviseDaemon(pid_t pid_to_watch) {
+ if (pid_to_watch == pid_t{0}) return;
std::string pid_path{proc_path_ + std::to_string(pid_to_watch)};
for (;;) {
- if (FileSize(mds_log_file_) > kMaxFileSize) {
- unlink(old_mds_log_file());
- rename(mds_log_file(), old_mds_log_file());
- }
- if (pid_to_watch != pid_t{0}) {
- for (int64_t i = 0; i != kLogRotationIntervalInSeconds; ++i) {
- if (!IsDir(pid_path) || Sleep(1))
- return;
- }
- } else {
- if (Sleep(kLogRotationIntervalInSeconds))
- return;
- }
+ if (!IsDir(pid_path) || Sleep(1)) return;
}
}
-
-uint64_t TransportMonitor::FileSize(const std::string& path) {
- struct stat stat_buf;
- uint64_t file_size;
- if (stat(path.c_str(), &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) != 0) {
- file_size = static_cast<uint64_t>(stat_buf.st_blocks) * 512;
- } else {
- file_size = 0;
- }
- return file_size;
-}
diff --git a/osaf/services/infrastructure/dtms/transport/transport_monitor.h
b/osaf/services/infrastructure/dtms/transport/transport_monitor.h
--- a/osaf/services/infrastructure/dtms/transport/transport_monitor.h
+++ b/osaf/services/infrastructure/dtms/transport/transport_monitor.h
@@ -23,8 +23,7 @@
#include <string>
#include "osaf/libs/core/cplusplus/base/macros.h"
-// This class is responsible for monitoring the osafdtmd process and rotating
-// the MDS logs.
+// This class is responsible for monitoring the osafdtmd process.
class TransportMonitor {
public:
// @a term_fd is a file descriptor that will become readable when the program
@@ -38,12 +37,11 @@ class TransportMonitor {
// SIGTERM signal and should exit.
pid_t WaitForDaemon(const std::string& daemon_name, int64_t seconds_to_wait);
- // Run in a loop, rotating the MDS logs every kLogRotationIntervalInSeconds
- // seconds if the MDS log file size is larger than kMaxFileSize. If @a
- // pid_to_watch is non-zero, watch the process with that process id. Return
if
- // the process dies, or if we have received the SIGTERM signal and should
- // exit.
- void RotateMdsLogs(pid_t pid_to_watch);
+ // If @a pid_to_watch is non-zero, run in a loop watching the process with
+ // that process id. Return if the process dies, or if we have received the
+ // SIGTERM signal and should exit. If @a pid_to_watch is zero, return
+ // immediately.
+ void SuperviseDaemon(pid_t pid_to_watch);
// Sleep for @a seconds_to_wait seconds, or until we have received the
SIGTERM
// signal and should exit, whichever happens first. Return true if the
SIGTERM
@@ -57,9 +55,6 @@ class TransportMonitor {
}
private:
- constexpr static const uint64_t kMaxFileSize = 5000 * uint64_t{1024};
- constexpr static const int64_t kLogRotationIntervalInSeconds = 15;
-
const char* pkgpiddir() const {
return pkgpiddir_.c_str();
}
@@ -68,22 +63,11 @@ class TransportMonitor {
return proc_path_.c_str();
}
- const char* mds_log_file() const {
- return mds_log_file_.c_str();
- }
-
- const char* old_mds_log_file() const {
- return old_mds_log_file_.c_str();
- }
-
static bool IsDir(const std::string& path);
- static uint64_t FileSize(const std::string& path);
int term_fd_;
const std::string pkgpiddir_;
const std::string proc_path_;
- const std::string mds_log_file_;
- const std::string old_mds_log_file_;
const bool use_tipc_;
DELETE_COPY_AND_MOVE_OPERATORS(TransportMonitor);
------------------------------------------------------------------------------
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