SET (CTRL_APP_LIB_PROJECT_NAME nmlib)
SET (IOTIVITY_LIB_PROJECT_NAME iotivity)
SET (AGENT_LIB_PROJECT_NAME agent_policy)
+SET (RMI_PROJECT_NAME rmi)
if (DEFINED DEBUG)
SET (CMAKE_BUILD_TYPE "Debug")
-get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${AGENT_LIB_PROJECT_NAME})
+add_subdirectory(${RMI_PROJECT_NAME})
+
include_directories (
inc
../iotivity_lib/inc
../ctrl_app_lib/inc
+ rmi/inc
)
FILE(GLOB SRCS src/*.cpp)
target_link_libraries(${PROJECT_NAME}
${IOTIVITY_LIB_PROJECT_NAME}
+ ${RMI_PROJECT_NAME}
)
install(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR})
#install(FILES tests.manifest DESTINATION ${MANIFESTDIR})
-message(STATUS "Configuring: " ${ProjectId})
+message(STATUS "Configuring: " ${PROJECT_NAME})
message(STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS})
+
--- /dev/null
+project(${RMI_PROJECT_NAME})
+
+FILE(GLOB SRCS src/*.cpp src/rmi/*.cpp)
+
+include_directories(inc inc/rmi)
+
+add_library (${PROJECT_NAME} ${SRCS})
+
+message(STATUS "Configuring: " ${PROJECT_NAME})
+message(STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS})
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_ARRAY_H__
+#define __RUNTIME_ARRAY_H__
+
+#include <vector>
+#include <utility>
+
+namespace runtime {
+
+template <typename T>
+class Array final {
+public:
+ Array() = delete;
+ Array(std::vector<T> &&list) :
+ list(std::move(list)), it(this->list.begin())
+ {
+ };
+ Array(const std::vector<T> &list) :
+ list(list), it(this->list.begin())
+ {
+ };
+
+ T *next()
+ {
+ if (it != list.end()) {
+ return &(*it++);
+ }
+ return NULL;
+ }
+
+private:
+ std::vector<T> list;
+ typename std::vector<T>::iterator it;
+};
+
+} // namespace runtime
+
+#endif // __RUNTIME_ARRAY_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_DATA_TYPE_H__
+#define __RUNTIME_DATA_TYPE_H__
+#include <string>
+#include <vector>
+#include <utility>
+
+#include "reflection.h"
+
+struct Void {
+ NO_REFLECTABLE_PROPERTY
+};
+
+struct String {
+ String() = default;
+ String(const String& str) : value(str.value) {}
+ String(String&& str) : value(std::move(str.value)) {}
+
+ String(const char* str) : value(str) {}
+ String(const std::string& str) : value(str) {}
+
+ String& operator=(const String& str)
+ {
+ if (this != &str) {
+ value = str.value;
+ }
+
+ return *this;
+ }
+
+ String& operator=(String&& str)
+ {
+ if (this != &str) {
+ value = std::move(str.value);
+ }
+ return *this;
+ }
+
+ std::string value;
+ REFLECTABLE(value)
+};
+
+struct StringPair {
+ std::string first;
+ std::string second;
+ REFLECTABLE(first, second)
+};
+
+struct Status {
+ Status() : code(0) {}
+ Status(int v) : code(v) {}
+
+ operator int() const
+ {
+ return code;
+ }
+
+ int code;
+ REFLECTABLE(code)
+};
+
+template<typename T>
+struct Vector {
+ std::vector<T> value;
+ REFLECTABLE(value)
+};
+
+#endif //!__RUNTIME_DATA_TYPE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_ERROR_H__
+#define __RUNTIME_ERROR_H__
+
+#include <string>
+
+namespace runtime {
+
+class Error {
+public:
+ static std::string message();
+ static std::string message(int errorCode);
+ static int lastErrorCode();
+};
+
+std::string GetSystemErrorMessage();
+std::string GetSystemErrorMessage(int errorCode);
+
+} // namespace runtime
+#endif //__RUNTIME_ERROR_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_EVENTFD_H__
+#define __RUNTIME_EVENTFD_H__
+
+#include <sys/eventfd.h>
+
+namespace runtime {
+
+class EventFD {
+public:
+ EventFD(unsigned int initval = 0, int flags = EFD_SEMAPHORE | EFD_CLOEXEC);
+ ~EventFD();
+
+ EventFD(const EventFD&) = delete;
+ EventFD& operator=(const EventFD&) = delete;
+
+ void send();
+ void receive();
+
+ int getFd() const
+ {
+ return fd;
+ }
+
+private:
+ int fd;
+};
+
+} // namespace runtime
+
+#endif //__RUNTIME_EVENTFD_H__
+
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_EXCEPTION_H__
+#define __RUNTIME_EXCEPTION_H__
+
+#include <stdexcept>
+#include <string>
+
+namespace runtime {
+
+class Exception: public std::runtime_error {
+public:
+ Exception(const std::string& error) :
+ std::runtime_error(error)
+ {
+ }
+};
+} // namespace runtime
+#endif //__RUNTIME_EXCEPTION_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_FILE_DESCRIPTOR_H__
+#define __RUNTIME_FILE_DESCRIPTOR_H__
+
+#include <unistd.h>
+
+#include <iostream>
+
+struct FileDescriptor {
+ FileDescriptor(int fd = -1, bool autoclose = false) :
+ fileDescriptor(fd),
+ autoClose(autoclose)
+ {
+ }
+
+ FileDescriptor(const FileDescriptor&) = delete;
+ FileDescriptor(FileDescriptor&& rhs) :
+ fileDescriptor(rhs.fileDescriptor),
+ autoClose(rhs.autoClose)
+ {
+ rhs.fileDescriptor = -1;
+ }
+
+ ~FileDescriptor() {
+ if ((fileDescriptor != -1) && (autoClose == true)) {
+ ::close(fileDescriptor);
+ }
+ }
+
+ FileDescriptor& operator=(const int fd) {
+ fileDescriptor = fd;
+ autoClose = false;
+ return *this;
+ }
+
+ FileDescriptor& operator=(FileDescriptor&& rhs) {
+ if (this != &rhs) {
+ fileDescriptor = rhs.fileDescriptor;
+ autoClose = rhs.autoClose;
+ rhs.fileDescriptor = -1;
+ }
+
+ return *this;
+ }
+
+ int fileDescriptor;
+ bool autoClose;
+};
+
+#endif //__RUNTIME_FILE_DESCRIPTOR_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_FILESYSTEM_H__
+#define __RUNTIME_FILESYSTEM_H__
+
+#include <dirent.h>
+
+#include <string>
+
+namespace runtime {
+
+class Path {
+public:
+ Path();
+ Path(const std::string& path);
+ Path(const char* path);
+ Path(const Path& path);
+
+ ~Path();
+
+ Path& operator=(const Path& path);
+ Path& operator=(const std::string& path);
+ Path& operator=(const char* path);
+
+ bool operator==(const Path& path) const
+ {
+ return (pathname == path.pathname);
+ }
+
+ bool operator!=(const Path& path) const
+ {
+ return !(pathname == path.pathname);
+ }
+
+ bool isAbsolute() const
+ {
+ return (pathname[0] == '/');
+ }
+
+ bool isRelative() const
+ {
+ return !(pathname[0] == '/');
+ }
+
+ const std::string& getPathname() const
+ {
+ return pathname;
+ }
+
+private:
+ Path& assign(const Path& path);
+ Path& assign(const std::string& path);
+ Path& assign(const char* path);
+
+ std::string pathname;
+};
+
+class File {
+public:
+ File();
+ File(const std::string& pathname);
+ File(const File& file);
+ File(const Path& filePath);
+
+ ~File();
+
+ File& operator=(const std::string& pathname)
+ {
+ path = pathname;
+ return *this;
+ }
+
+ File& operator=(const File& file)
+ {
+ path = file.path;
+ return *this;
+ }
+
+ File& operator=(const Path& filePath)
+ {
+ path = filePath;
+ return *this;
+ }
+
+ bool operator<(const File& file) const;
+ bool operator>(const File& file) const;
+ bool operator<=(const File& file) const;
+ bool operator>=(const File& file) const;
+
+ bool operator==(const File& file) const
+ {
+ return (path == file.path);
+ }
+
+ bool operator!=(const File& file) const
+ {
+ return !(path == file.path);
+ }
+
+ bool exists() const;
+ bool canRead() const;
+ bool canWrite() const;
+ bool canExecute() const;
+
+ bool isLink() const;
+ bool isFile() const;
+ bool isDirectory() const;
+ bool isDevice() const;
+ bool isHidden() const;
+
+ void open(int flags, mode_t mode);
+ void close();
+ void copyTo(const std::string& pathname) const;
+ void moveTo(const std::string& pathname);
+ void renameTo(const std::string& pathname);
+ void remove(bool recursive = false);
+ void makeDirectory(bool recursive = false);
+
+ void chown(uid_t uid, gid_t gid);
+ void chmod(mode_t mode);
+
+ std::string toString() const;
+
+ const std::string& getPath() const
+ {
+ return path.getPathname();
+ }
+
+private:
+ int descriptor;
+ Path path;
+};
+
+class DirectoryIterator {
+public:
+ DirectoryIterator();
+ DirectoryIterator(const std::string& dir);
+ DirectoryIterator(const Path& dir);
+
+ ~DirectoryIterator();
+
+ DirectoryIterator& operator=(const std::string& dir);
+ DirectoryIterator& operator=(const Path& dir);
+ DirectoryIterator& operator++();
+
+ bool operator==(const DirectoryIterator& iterator) const
+ {
+ return (current == iterator.current);
+ }
+
+ bool operator!=(const DirectoryIterator& iterator) const
+ {
+ return !(current == iterator.current);
+ }
+
+ const File& operator*() const
+ {
+ return current;
+ }
+
+ File& operator*()
+ {
+ return current;
+ }
+
+ const File* operator->() const
+ {
+ return ¤t;
+ }
+
+ File* operator->()
+ {
+ return ¤t;
+ }
+
+private:
+ void next();
+ void reset(const std::string& dir);
+
+ File current;
+ DIR* directoryHandle;
+ std::string basename;
+};
+
+class Mount final {
+public:
+ Mount() = delete;
+
+ static void mountEntry(const std::string& src, const std::string& dest,
+ const std::string& type, const std::string& opts);
+};
+
+int Open(const std::string& path, int flags, mode_t mode);
+void Close(int fd);
+
+} // namespace runtime
+#endif //__RUNTIME_FILESYSTEM_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_MAINLOOP_H__
+#define __RUNTIME_MAINLOOP_H__
+
+#include <sys/epoll.h>
+
+#include <string>
+#include <functional>
+#include <unordered_map>
+#include <memory>
+#include <mutex>
+#include <atomic>
+
+#include "eventfd.h"
+
+namespace runtime {
+
+class Mainloop {
+public:
+ typedef unsigned int Event;
+ typedef std::function<void(int fd, Event event)> Callback;
+
+ Mainloop();
+ ~Mainloop();
+
+ void addEventSource(const int fd, const Event events, Callback&& callback);
+ void removeEventSource(const int fd);
+ bool dispatch(const int timeout);
+ void run();
+ void stop();
+
+private:
+ typedef std::recursive_mutex Mutex;
+
+ std::unordered_map<int, std::shared_ptr<Callback>> callbacks;
+ Mutex mutex;
+ int pollFd;
+ std::atomic<bool> stopped;
+ runtime::EventFD wakeupSignal;
+};
+
+} // namespace runtime
+
+#endif //__RUNTIME_MAINLOOP_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_OBJECT_LATCH_H__
+#define __RUNTIME_OBJECT_LATCH_H__
+
+#include <utility>
+#include <mutex>
+#include <condition_variable>
+
+template<typename DataType>
+class ObjectLatch {
+public:
+ ObjectLatch() :
+ state(false)
+ {
+ }
+
+ ObjectLatch(const ObjectLatch&) = delete;
+ ObjectLatch& operator=(const ObjectLatch&) = delete;
+
+ void set(const DataType& val)
+ {
+ data = val;
+ state = true;
+ condition.notify_one();
+ }
+
+ void set(DataType&& val)
+ {
+ data = std::move(val);
+ state = true;
+ condition.notify_one();
+ }
+
+ DataType get()
+ {
+ return DataType(std::move(data));
+ }
+
+ bool isValid() const
+ {
+ return state == true;
+ }
+
+ void wait()
+ {
+ std::unique_lock<std::mutex> lock(stateLock);
+ condition.wait(lock, [this]{
+ return isValid();
+ });
+ }
+
+private:
+ DataType data;
+ bool state;
+ std::mutex stateLock;
+ std::condition_variable condition;
+};
+
+#endif //__RUNTIME_OBJECT_LATCH_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_PAM_H__
+#define __RUNTIME_PAM_H__
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <syslog.h>
+#include <security/pam_appl.h>
+
+namespace runtime {
+
+class PAM final {
+public:
+ PAM(PAM&&) = delete;
+ PAM(const PAM&) = delete;
+ PAM(const std::string& service, const std::string& user);
+ ~PAM();
+
+ PAM& operator=(const PAM&) = delete;
+ PAM& operator=(PAM &&) = delete;
+
+ void setData(const std::string &name, void* data, void (*cleanup)(pam_handle_t* pamh, void* data, int error));
+ const void* getData(const std::string &name) const;
+
+ void setItem(int item, void* data);
+ const void* getItem(int item) const;
+
+ const std::string getUser(const std::string &prompt = "") const;
+
+ void putEnv(const std::string &name_value);
+ const std::string getEnv(const std::string &name) const;
+ const std::vector<std::string> getEnvList() const;
+
+ void syslog(const std::string &log, int priority = LOG_ERR);
+
+ int authenticate(int flags);
+ int setCredential(int flags);
+ int accountManagement(int flags);
+ int changeAuthenticationToken(int flags);
+ void openSession(int flags);
+ void closeSession(int flags);
+
+private:
+ pam_handle_t* pamh;
+};
+
+} // namespace runtime
+#endif // __RUNTIME_PAM_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_PREPROCESSOR_H__
+#define __RUNTIME_PREPROCESSOR_H__
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+
+#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2)
+#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2)
+#define CONCATENATE2(arg1, arg2) arg1##arg2
+
+#define VAR_ARGS_SIZE(...) VAR_ARGS_SIZE_(__VA_ARGS__, FOR_EACH_VAR_ARGS_RSEQ_N())
+#define VAR_ARGS_SIZE_(...) FOR_EACH_VAR_ARGS_ARG_N(__VA_ARGS__)
+
+#define FOR_EACH_VAR_ARGS_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, N, ...) N
+#define FOR_EACH_VAR_ARGS_RSEQ_N() 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+#define FOR_EACH_VAR_ARGS_1(what, x, ...) what(x)
+#define FOR_EACH_VAR_ARGS_2(what, x, ...) what(x); FOR_EACH_VAR_ARGS_1(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_3(what, x, ...) what(x); FOR_EACH_VAR_ARGS_2(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_4(what, x, ...) what(x); FOR_EACH_VAR_ARGS_3(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_5(what, x, ...) what(x); FOR_EACH_VAR_ARGS_4(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_6(what, x, ...) what(x); FOR_EACH_VAR_ARGS_5(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_7(what, x, ...) what(x); FOR_EACH_VAR_ARGS_6(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_8(what, x, ...) what(x); FOR_EACH_VAR_ARGS_7(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_9(what, x, ...) what(x); FOR_EACH_VAR_ARGS_8(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_10(what, x, ...) what(x); FOR_EACH_VAR_ARGS_9(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_11(what, x, ...) what(x); FOR_EACH_VAR_ARGS_10(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_12(what, x, ...) what(x); FOR_EACH_VAR_ARGS_11(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_13(what, x, ...) what(x); FOR_EACH_VAR_ARGS_12(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_14(what, x, ...) what(x); FOR_EACH_VAR_ARGS_13(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_15(what, x, ...) what(x); FOR_EACH_VAR_ARGS_14(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_16(what, x, ...) what(x); FOR_EACH_VAR_ARGS_15(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_17(what, x, ...) what(x); FOR_EACH_VAR_ARGS_16(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_18(what, x, ...) what(x); FOR_EACH_VAR_ARGS_17(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_19(what, x, ...) what(x); FOR_EACH_VAR_ARGS_18(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_20(what, x, ...) what(x); FOR_EACH_VAR_ARGS_19(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_21(what, x, ...) what(x); FOR_EACH_VAR_ARGS_20(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_22(what, x, ...) what(x); FOR_EACH_VAR_ARGS_21(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_23(what, x, ...) what(x); FOR_EACH_VAR_ARGS_22(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_24(what, x, ...) what(x); FOR_EACH_VAR_ARGS_23(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_25(what, x, ...) what(x); FOR_EACH_VAR_ARGS_24(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_26(what, x, ...) what(x); FOR_EACH_VAR_ARGS_25(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_27(what, x, ...) what(x); FOR_EACH_VAR_ARGS_26(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_28(what, x, ...) what(x); FOR_EACH_VAR_ARGS_27(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_29(what, x, ...) what(x); FOR_EACH_VAR_ARGS_28(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_30(what, x, ...) what(x); FOR_EACH_VAR_ARGS_29(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_31(what, x, ...) what(x); FOR_EACH_VAR_ARGS_30(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS_32(what, x, ...) what(x); FOR_EACH_VAR_ARGS_31(what, __VA_ARGS__)
+
+#define FOR_EACH_VAR_ARGS_(N, what, ...) CONCATENATE(FOR_EACH_VAR_ARGS_, N)(what, __VA_ARGS__)
+#define FOR_EACH_VAR_ARGS(what, ...) FOR_EACH_VAR_ARGS_(VAR_ARGS_SIZE(__VA_ARGS__), what, __VA_ARGS__)
+
+#define SEQUENCE_1(how) how(1)
+#define SEQUENCE_2(how) SEQUENCE_1(how), how(2)
+#define SEQUENCE_3(how) SEQUENCE_2(how), how(3)
+#define SEQUENCE_4(how) SEQUENCE_3(how), how(4)
+#define SEQUENCE_5(how) SEQUENCE_4(how), how(5)
+#define SEQUENCE_6(how) SEQUENCE_5(how), how(6)
+#define SEQUENCE_7(how) SEQUENCE_6(how), how(7)
+#define SEQUENCE_8(how) SEQUENCE_7(how), how(8)
+#define SEQUENCE_9(how) SEQUENCE_8(how), how(9)
+#define SEQUENCE_10(how) SEQUENCE_9(how), how(10)
+#define SEQUENCE_11(how) SEQUENCE_10(how), how(11)
+#define SEQUENCE_12(how) SEQUENCE_11(how), how(12)
+#define SEQUENCE_13(how) SEQUENCE_12(how), how(13)
+#define SEQUENCE_14(how) SEQUENCE_13(how), how(14)
+#define SEQUENCE_15(how) SEQUENCE_14(how), how(15)
+#define SEQUENCE_16(how) SEQUENCE_15(how), how(16)
+#define SEQUENCE_17(how) SEQUENCE_16(how), how(17)
+#define SEQUENCE_18(how) SEQUENCE_17(how), how(18)
+#define SEQUENCE_19(how) SEQUENCE_18(how), how(19)
+#define SEQUENCE_20(how) SEQUENCE_19(how), how(20)
+#define SEQUENCE_21(how) SEQUENCE_20(how), how(21)
+#define SEQUENCE_22(how) SEQUENCE_21(how), how(22)
+#define SEQUENCE_23(how) SEQUENCE_22(how), how(23)
+#define SEQUENCE_24(how) SEQUENCE_23(how), how(24)
+#define SEQUENCE_25(how) SEQUENCE_24(how), how(25)
+#define SEQUENCE_26(how) SEQUENCE_25(how), how(26)
+#define SEQUENCE_27(how) SEQUENCE_26(how), how(27)
+#define SEQUENCE_28(how) SEQUENCE_27(how), how(28)
+#define SEQUENCE_29(how) SEQUENCE_28(how), how(29)
+#define SEQUENCE_30(how) SEQUENCE_29(how), how(30)
+#define SEQUENCE_31(how) SEQUENCE_30(how), how(31)
+#define SEQUENCE_32(how) SEQUENCE_31(how), how(32)
+#define SEQUENCE(how, N) SEQUENCE_##N(how)
+
+#endif //!__RUNTIME_PREPROCESSOR_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_PROCESS_H__
+#define __RUNTIME_PROCESS_H__
+
+#include <string>
+#include <vector>
+
+namespace runtime {
+
+class Process {
+public:
+ typedef pid_t Pid;
+
+ Process(const std::string& prog);
+ Process(const std::string& prog, const std::vector<std::string>& args);
+ Process(const Process& proc);
+
+ ~Process();
+
+ Process& operator=(const Process& proc);
+
+ int execute();
+ int start();
+ int waitForFinished();
+ int waitForStarted();
+ void terminate();
+ void kill();
+
+ bool isRunning() const;
+
+private:
+ int status;
+ Pid pid;
+ std::string program;
+ std::vector<std::string> args;
+};
+
+} // namespace runtime
+#endif //__RUNTIME_PROCESS_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_REFLECTION_H__
+#define __RUNTIME_REFLECTION_H__
+
+#include <type_traits>
+
+#include "preprocessor.h"
+
+#define VISIT_ELEMENT(elem) v.visit(#elem, elem)
+
+#define REFLECTABLE(...) \
+template<typename V> \
+void accept(V v) \
+{ \
+ FOR_EACH_VAR_ARGS(VISIT_ELEMENT, __VA_ARGS__); \
+} \
+template<typename V> \
+void accept(V v) const \
+{ \
+ FOR_EACH_VAR_ARGS(VISIT_ELEMENT, __VA_ARGS__); \
+}
+
+#define NO_REFLECTABLE_PROPERTY \
+ template<typename V> \
+ static void accept(V) {}
+
+template<typename T>
+struct ReflectionTraitChecker {
+ struct Visitor {};
+
+ template <typename C> static std::true_type
+ test(decltype(std::declval<C>().template accept(Visitor()))*);
+
+ template <typename C> static std::false_type
+ test(...);
+
+ static constexpr bool value = std::is_same<decltype(test<T>(0)), std::true_type>::value;
+};
+
+template<typename T>
+struct IsReflectable : public std::integral_constant<bool, ReflectionTraitChecker<T>::value> {};
+
+#endif //!__RUNTIME_REFLECTION_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_CALLBACK_HOLDER_H__
+#define __RMI_CALLBACK_HOLDER_H__
+
+#include <utility>
+#include <functional>
+
+#include "message.h"
+
+namespace rmi {
+
+template<typename Type, typename... Args>
+struct MethodHandler {
+ typedef std::function<Type(Args&...)> type;
+};
+// using MethodHandler = std::function<Type(Args&...)>;
+
+template<typename Type, typename... Args>
+struct CallbackHolder {
+ template<int...>
+ struct Sequence {};
+
+ template<int N, int... S>
+ struct SequenceExpansion : SequenceExpansion<N-1, N-1, S...> {};
+
+ template<int... S>
+ struct SequenceExpansion<0, S...> {
+ typedef Sequence<S...> type;
+ };
+
+ std::tuple<Args...> parameters;
+ const typename MethodHandler<Type, Args...>::type& callback;
+
+ CallbackHolder(const typename MethodHandler<Type, Args...>::type& m) :
+ callback(m)
+ {
+ }
+
+ Type dispatch(Message& message)
+ {
+ return callCallback(message, typename SequenceExpansion<sizeof...(Args)>::type());
+ }
+
+ template<typename...R>
+ Type callCallback(Message& message, R&... args)
+ {
+ message.unpackParameters(args...);
+ return callback(args...);
+ }
+
+ template<int... S>
+ Type callCallback(Message& message, Sequence<S...>)
+ {
+ return callCallback(message, std::get<S>(parameters)...);
+ }
+};
+
+} // namespace rmi
+#endif //!__RMI_CALLBACK_HOLDER_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_CLIENT_H__
+#define __RMI_CLIENT_H__
+
+#include <thread>
+#include <string>
+#include <memory>
+
+#include "error.h"
+#include "message.h"
+#include "connection.h"
+#include "mainloop.h"
+#include "callback-holder.h"
+
+namespace rmi {
+
+class Client {
+public:
+ Client(const std::string& address);
+ ~Client();
+
+ Client(const Client&) = delete;
+ Client& operator=(const Client&) = delete;
+
+ void connect();
+ void disconnect();
+
+ int subscribe(const std::string& provider, const std::string& name);
+
+ template<typename... Args>
+ int subscribe(const std::string& provider, const std::string& name,
+ const typename MethodHandler<void, Args...>::type& handler);
+
+ int unsubscribe(const std::string& provider, int handle);
+
+ template<typename Type, typename... Args>
+ Type methodCall(const std::string& method, Args&&... args);
+
+private:
+ std::string address;
+ std::shared_ptr<Connection> connection;
+ runtime::Mainloop mainloop;
+ std::thread dispatcher;
+};
+
+template<typename... Args>
+int Client::subscribe(const std::string& provider, const std::string& name,
+ const typename MethodHandler<void, Args...>::type& handler)
+{
+ int id = subscribe(provider, name);
+ if (id < 0) {
+ return -1;
+ }
+
+ std::shared_ptr<Socket> transport = std::make_shared<Socket>(id);
+
+ auto callback = [handler, transport, this](int fd, runtime::Mainloop::Event event) {
+ if ((event & EPOLLHUP) || (event & EPOLLRDHUP)) {
+ mainloop.removeEventSource(fd);
+ return;
+ }
+
+ try {
+ Message msg;
+ msg.decode(*transport);
+
+ CallbackHolder<void, Args...> callback(handler);
+ callback.dispatch(msg);
+ } catch (std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ };
+
+ mainloop.addEventSource(id, EPOLLIN | EPOLLHUP | EPOLLRDHUP, callback);
+
+ return id;
+}
+
+template<typename Type, typename... Args>
+Type Client::methodCall(const std::string& method, Args&&... args)
+{
+ Message request = connection->createMessage(Message::MethodCall, method);
+ request.packParameters(std::forward<Args>(args)...);
+ connection->send(request);
+
+ Message reply = connection->dispatch();
+
+ Type response;
+ reply.disclose<Type>(response);
+
+ return response;
+}
+
+} // namespace rmi
+#endif //__RMI_CLIENT_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_CONNECTION_H__
+#define __RMI_CONNECTION_H__
+
+#include <string>
+#include <mutex>
+
+#include "socket.h"
+#include "serialize.h"
+#include "message.h"
+
+namespace rmi {
+
+class Connection {
+public:
+ Connection(Socket&& sock);
+ Connection(const Connection&) = delete;
+ ~Connection() noexcept;
+
+ Connection& operator=(const Connection&) = delete;
+ Connection& operator=(Connection&) = delete;
+
+ Message createMessage(unsigned int type, const std::string& target);
+
+ void send(const Message& message) const;
+ Message dispatch() const;
+
+ int getFd() const
+ {
+ return socket.getFd();
+ }
+
+ Credentials getPeerCredentials() const
+ {
+ return socket.getPeerCredentials();
+ }
+
+private:
+ Socket socket;
+ mutable std::mutex receiveMutex;
+ mutable std::mutex transmitMutex;
+};
+
+} // namespace rmi
+#endif //__RMI_CONNECTION_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RMI_MESSAGE_COMPOSER_H__
+#define __RMI_MESSAGE_COMPOSER_H__
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <memory>
+
+namespace rmi {
+
+class MessageComposer {
+public:
+ MessageComposer(size_t caps = 1024);
+ MessageComposer(const MessageComposer& rhs);
+ MessageComposer(MessageComposer&& rhs);
+
+ ~MessageComposer();
+
+ MessageComposer& operator=(const MessageComposer& rhs);
+ MessageComposer& operator=(MessageComposer&& rhs);
+
+ void write(const void* ptr, const size_t sz);
+ void read(void* ptr, const size_t sz);
+ void insure(size_t sz);
+
+ void reserve(size_t size)
+ {
+ produce = size;
+ }
+
+ void reset()
+ {
+ produce = consume = 0;
+ }
+
+ char* begin() const
+ {
+ return buffer + consume;
+ }
+
+ char* end() const
+ {
+ return buffer + produce;
+ }
+
+ size_t size() const
+ {
+ return (end() - begin());
+ }
+
+private:
+ size_t capacity;
+ size_t produce;
+ size_t consume;
+ char *buffer;
+};
+
+} // namespae rmi
+#endif //__RMI_MESSAGE_COMPOSER_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_MESSAGE_H__
+#define __RMI_MESSAGE_H__
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <memory>
+#include <atomic>
+#include <deque>
+
+#include "message-composer.h"
+
+#include "reflection.h"
+#include "serialize.h"
+#include "file-descriptor.h"
+
+namespace rmi {
+
+class Message {
+public:
+ enum Type {
+ Invalid,
+ MethodCall,
+ Reply,
+ Error,
+ Signal
+ };
+
+ Message();
+ Message(unsigned int id, unsigned int type, const std::string&);
+ Message(unsigned int type, const std::string&);
+ Message(const Message& rhs);
+ Message(Message&& rhs);
+
+ ~Message();
+
+ Message& operator=(const Message& rhs);
+ Message& operator=(Message&& rhs);
+
+ // [TBD] Take arguments
+ Message createReplyMessage() const;
+ Message createErrorMessage() const;
+
+ unsigned int id() const
+ {
+ return signature.id;
+ }
+
+ unsigned int type() const
+ {
+ return signature.type;
+ }
+
+ const std::string& target() const
+ {
+ return signature.target;
+ }
+
+ bool isInvalid() const
+ {
+ return type() == Invalid;
+ }
+
+ bool isError() const
+ {
+ return type() == Error;
+ }
+
+ bool isMethodCall() const
+ {
+ return type() == MethodCall;
+ }
+
+ bool isSignal() const
+ {
+ return type() == Signal;
+ }
+
+ bool isReply() const
+ {
+ return type() == Reply;
+ }
+
+ template<typename T>
+ void encode(const T& device) const;
+
+ template<typename T>
+ void decode(const T& device);
+
+ void packParameters()
+ {
+ }
+
+ template<typename F>
+ void packParameters(F&& arg);
+
+ template<typename F, typename...R>
+ void packParameters(F&& first, R&&... rest);
+
+ void unpackParameters()
+ {
+ }
+
+ template<typename F>
+ void unpackParameters(F& arg);
+
+ template<typename F, typename... R>
+ void unpackParameters(F& first, R&... rest);
+
+ template<typename DataType>
+ void enclose(DataType&& data);
+
+ template<typename DataType>
+ void disclose(DataType& data);
+
+private:
+ struct MessageHeader {
+ unsigned int id; // Unique message id
+ unsigned int type; // Mesage type
+ size_t length;// Total message length except MessageHeader itself
+ size_t ancillary;
+ };
+
+ struct MessageSignature {
+ unsigned int id;
+ unsigned int type;
+ std::string target;
+
+ REFLECTABLE(
+ id,
+ type,
+ target
+ )
+ };
+
+ MessageSignature signature;
+ MessageComposer buffer;
+ std::deque<FileDescriptor> fileDescriptors;
+
+ static std::atomic<unsigned int> sequence;
+};
+
+template<typename F>
+void Message::packParameters(F&& arg)
+{
+ enclose<F>(std::forward<F>(arg));
+}
+
+template<typename F, typename...R>
+void Message::packParameters(F&& first, R&&... rest)
+{
+ packParameters(std::forward<F>(first));
+ packParameters(std::forward<R>(rest)...);
+}
+
+template<typename F>
+void Message::unpackParameters(F& arg)
+{
+ disclose<F>(arg);
+}
+
+template<typename F, typename... R>
+void Message::unpackParameters(F& first, R&... rest)
+{
+ unpackParameters(first);
+ unpackParameters(rest...);
+}
+
+template<typename DataType>
+void Message::enclose(DataType&& data)
+{
+ runtime::Serializer<MessageComposer> serializer(buffer);
+ runtime::SerializableArgument<DataType> arg(std::forward<DataType>(data));
+ arg.accept(serializer);
+}
+
+template<typename DataType>
+void Message::disclose(DataType& data)
+{
+ runtime::Deserializer<MessageComposer> deserializer(buffer);
+ runtime::DeserializableArgument<DataType> arg(data);
+ arg.accept(deserializer);
+}
+
+template<typename T>
+void Message::encode(const T& device) const
+{
+ MessageHeader header = {
+ signature.id,
+ signature.type,
+ buffer.size(),
+ fileDescriptors.size()
+ };
+
+ device.write(&header, sizeof(header));
+ device.write(buffer.begin(), header.length);
+
+ int i = 0, fds[fileDescriptors.size()];
+ for (const FileDescriptor& fd : fileDescriptors) {
+ fds[i++] = fd.fileDescriptor;
+ }
+
+ device.sendFileDescriptors(fds, fileDescriptors.size());
+}
+
+template<typename T>
+void Message::decode(const T& device)
+{
+ MessageHeader header;
+ device.read(&header, sizeof(header));
+ buffer.insure(header.length);
+ device.read(buffer.begin(), header.length);
+ buffer.reserve(header.length);
+
+ int fds[header.ancillary];
+
+ device.receiveFileDescriptors(fds, header.ancillary);
+ for (unsigned int i = 0; i < header.ancillary; i++) {
+ fileDescriptors.emplace_back(FileDescriptor(fds[i]));
+ }
+
+ disclose(signature);
+}
+
+template<> void Message::enclose(FileDescriptor&& fd);
+template<> void Message::disclose(FileDescriptor& fd);
+
+} // namespae rmi
+#endif //__RMI_MESSAGE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_NOTIFICATION_H__
+#define __RMI_NOTIFICATION_H__
+
+#include <string>
+#include <vector>
+#include <mutex>
+#include <unordered_map>
+#include <utility>
+#include <memory>
+
+#include "socket.h"
+#include "message.h"
+//#include "audit/logger.h"
+
+namespace rmi {
+
+typedef std::pair<int, int> SubscriptionId;
+
+class Notification {
+public:
+ Notification();
+ Notification(const std::string& name);
+ Notification(const Notification&) = default;
+ Notification(Notification&&);
+
+ SubscriptionId createSubscriber();
+ int removeSubscriber(const int id);
+
+ template<typename... Args>
+ void notify(Args&&... args);
+
+private:
+ std::string signalName;
+ std::vector<std::shared_ptr<Socket>> subscribers;
+ std::mutex subscriberLock;
+};
+
+template<typename... Args>
+void Notification::notify(Args&&... args)
+{
+ Message msg(Message::Signal, signalName);
+ msg.packParameters(std::forward<Args>(args)...);
+
+ std::lock_guard<std::mutex> lock(subscriberLock);
+
+ for (std::shared_ptr<Socket>& subscriber : subscribers) {
+ try {
+ msg.encode(*subscriber);
+ } catch (runtime::Exception& e) {
+ //FIXME! switch to dlog
+ //ERROR(e.what());
+ }
+ }
+}
+
+} // namespae rmi
+#endif //__RMI_NOTIFICATION_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_SERVICE_H__
+#define __RMI_SERVICE_H__
+
+#include <mutex>
+#include <string>
+#include <functional>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+#include <thread>
+
+#include "preprocessor.h"
+#include "thread-pool.h"
+#include "mainloop.h"
+#include "connection.h"
+#include "message.h"
+#include "callback-holder.h"
+#include "notification.h"
+
+#define STRIP_(...)
+#define STRIP(x) STRIP_ x
+
+#define TYPEOF____(...) __VA_ARGS__
+#define TYPEOF___(...) (__VA_ARGS__),
+#define TYPEOF__(x, ...) TYPEOF____ x
+#define TYPEOF_(...) TYPEOF__(__VA_ARGS__)
+#define TYPEOF(x) TYPEOF_(TYPEOF___ x, )
+
+#define PLACEHOLDER(n) std::placeholders::_##n
+
+#define PROTOTYPE_(D, N) SEQUENCE(D, N)
+#define PROTOTYPE(...) PROTOTYPE_(PLACEHOLDER, VAR_ARGS_SIZE(__VA_ARGS__))
+
+#define registerMethod(T, M, ...) \
+setMethodHandler<TYPEOF(M), TYPEOF(STRIP(STRIP(M)))> \
+ (STRINGIFY(TYPEOF(STRIP(M))), std::bind(&TYPEOF(STRIP(M)), T, \
+ PROTOTYPE(TYPEOF(STRIP(STRIP(M))))))
+
+#define registerParametricMethod(T, M, ...) \
+setMethodHandler<TYPEOF(M), TYPEOF(STRIP(STRIP(M)))> \
+ (STRINGIFY(TYPEOF(STRIP(M))), std::bind(&TYPEOF(STRIP(M)), T, \
+ PROTOTYPE(TYPEOF(STRIP(STRIP(M))))))
+
+#define registerNonparametricMethod(T, M, ...) \
+setMethodHandler<TYPEOF(M)> \
+ (STRINGIFY(TYPEOF(STRIP(M))), std::bind(&TYPEOF(STRIP(M)), T))
+
+namespace rmi {
+
+typedef std::function<bool(const Connection& connection)> ConnectionCallback;
+
+class Service {
+public:
+ Service(const std::string& address);
+ ~Service();
+
+ Service(const Service&) = delete;
+ Service& operator=(const Service&) = delete;
+
+ void start();
+ void stop();
+
+ void setNewConnectionCallback(const ConnectionCallback& callback);
+ void setCloseConnectionCallback(const ConnectionCallback& callback);
+
+ template<typename Type, typename... Args>
+ void setMethodHandler(const std::string& method,
+ const typename MethodHandler<Type, Args...>::type& handler);
+
+ void createNotification(const std::string& name);
+ int subscribeNotification(const std::string& name);
+ int unsubscribeNotification(const std::string& name, const int id);
+
+ template <typename... Args>
+ void notify(const std::string& name, Args&&... args);
+
+ pid_t getPeerPid() const
+ {
+ return processingContext.credentials.pid;
+ }
+
+ uid_t getPeerUid() const
+ {
+ return processingContext.credentials.uid;
+ }
+
+ gid_t getPeerGid() const
+ {
+ return processingContext.credentials.gid;
+ }
+
+private:
+ struct ProcessingContext {
+ ProcessingContext() = default;
+ ProcessingContext(const std::shared_ptr<Connection>& connection) :
+ credentials(connection->getPeerCredentials())
+ {
+ }
+
+ Credentials credentials;
+ };
+
+ typedef std::vector<std::shared_ptr<Connection>> ConnectionRegistry;
+ typedef std::function<void(const std::shared_ptr<Connection>& connection)> CallbackDispatcher;
+
+ typedef std::function<Message(Message& message)> MethodDispatcher;
+ typedef std::unordered_map<std::string, std::shared_ptr<MethodDispatcher>> MethodRegistry;
+ typedef std::unordered_map<std::string, Notification> NotificationRegistry;
+
+ void onMessageProcess(const std::shared_ptr<Connection>& connection);
+
+ ConnectionRegistry::iterator getConnectionIterator(const int id);
+
+ CallbackDispatcher onNewConnection;
+ CallbackDispatcher onCloseConnection;
+
+ MethodRegistry methodRegistry;
+ NotificationRegistry notificationRegistry;
+ ConnectionRegistry connectionRegistry;
+
+ runtime::Mainloop mainloop;
+ std::string address;
+
+ runtime::ThreadPool workqueue;
+ std::mutex stateLock;
+ std::mutex notificationLock;
+
+ static thread_local ProcessingContext processingContext;
+};
+
+template<typename Type, typename... Args>
+void Service::setMethodHandler(const std::string& method,
+ const typename MethodHandler<Type, Args...>::type& handler)
+{
+ auto dispatchMethod = [handler](Message& message) {
+ CallbackHolder<Type, Args...> callback(handler);
+ Message reply = message.createReplyMessage();
+ reply.packParameters<Type>(callback.dispatch(message));
+
+ return reply;
+ };
+
+ std::lock_guard<std::mutex> lock(stateLock);
+
+ if (methodRegistry.count(method)) {
+ throw runtime::Exception("Method handler already registered");
+ }
+
+ methodRegistry[method] = std::make_shared<MethodDispatcher>(std::move(dispatchMethod));
+}
+
+template <typename... Args>
+void Service::notify(const std::string& name, Args&&... args)
+{
+ Notification& slot = notificationRegistry[name];
+ slot.notify(name, std::forward<Args>(args)...);
+}
+
+} // namespace rmi
+
+#endif //__RMI_SERVICE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RMI_SOCKET_H__
+#define __RMI_SOCKET_H__
+
+#include "exception.h"
+
+namespace rmi {
+
+class SocketException: public runtime::Exception {
+public:
+ SocketException(const std::string& msg) : runtime::Exception(msg) {}
+};
+
+struct Credentials {
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+};
+
+class Socket {
+public:
+ explicit Socket(int socketFd = -1, bool autoclose = true);
+ Socket(Socket&& socket) noexcept;
+ ~Socket() noexcept;
+
+ Socket(const Socket&) = delete;
+ Socket& operator=(const Socket&) = delete;
+ Socket& operator=(Socket&) = delete;
+
+ Socket accept();
+ int getFd() const;
+ Credentials getPeerCredentials() const;
+
+ void write(const void* buffer, const size_t size) const;
+ void read(void* buffer, const size_t size) const;
+
+ void sendFileDescriptors(const int* fds, const size_t nr) const;
+ void receiveFileDescriptors(int* fds, const size_t nr) const;
+
+ static Socket create(const std::string& path);
+ static Socket connect(const std::string& path);
+
+private:
+ static int createRegularSocket(const std::string& path);
+
+#ifdef USE_SYSTEMD_SOCKET_ACTIVATION
+ static int createSystemdSocket(const std::string& path);
+#endif
+
+private:
+ int socketFd;
+ bool autoClose;
+};
+
+} // namespace rmi
+#endif //__RMI_SOCKET_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_SERIALIZER_H__
+#define __RUNTIME_SERIALIZER_H__
+
+#include <vector>
+#include <string>
+#include <utility>
+
+#include "reflection.h"
+
+namespace runtime {
+
+template<typename T>
+struct SerializableArgument {
+ SerializableArgument(const T& arg) : value(arg) {}
+
+ const T& value;
+ REFLECTABLE(value)
+};
+
+template<typename T>
+struct DeserializableArgument {
+ DeserializableArgument(T& arg) : value(arg) {}
+
+ T& value;
+ REFLECTABLE(value)
+};
+
+template<class StorageType>
+class Serializer {
+public:
+ Serializer(StorageType& source) :
+ storage(source)
+ {
+ }
+
+ template<typename DataType>
+ void visit(const std::string&, const DataType& value)
+ {
+ visitInternal(value);
+ }
+
+private:
+ void visitInternal(const std::string& value)
+ {
+ visitInternal(value.size());
+ storage.write(value.c_str(), value.size());
+ }
+
+ template<typename DataType, typename std::enable_if<std::is_arithmetic<DataType>::value, int>::type = 0>
+ void visitInternal(const DataType& value)
+ {
+ storage.write(&value, sizeof(DataType));
+ }
+
+ template<typename DataType, typename std::enable_if<::IsReflectable<DataType>::value, int>::type = 0>
+ void visitInternal(DataType& value)
+ {
+ value.accept(*this);
+ }
+
+ template<typename DataType>
+ void visitInternal(const std::vector<DataType>& values)
+ {
+ visitInternal(values.size());
+ for (const DataType& value : values) {
+ visitInternal(value);
+ }
+ }
+
+private:
+ StorageType& storage;
+};
+
+template<class StorageType>
+class Deserializer {
+public:
+ Deserializer(StorageType& source) :
+ storage(source)
+ {
+ }
+
+ template<typename DataType>
+ void visit(const std::string&, DataType& value)
+ {
+ visitInternal(value);
+ }
+
+private:
+ void visitInternal(std::string& value)
+ {
+ size_t size;
+ visitInternal(size);
+ value.resize(size);
+ storage.read(&value.front(), size);
+ }
+
+ template<typename DataType, typename std::enable_if<std::is_arithmetic<DataType>::value, int>::type = 0>
+ void visitInternal(DataType& value)
+ {
+ storage.read(&value, sizeof(DataType));
+ }
+
+ template<typename T, typename std::enable_if<::IsReflectable<T>::value, int>::type = 0>
+ void visitInternal(T& value)
+ {
+ value.accept(*this);
+ }
+
+ template<typename DataType>
+ void visitInternal(std::vector<DataType>& values)
+ {
+ size_t size;
+ visitInternal(size);
+ values.resize(size);
+
+ for (DataType& value : values) {
+ visitInternal(value);
+ }
+ }
+
+private:
+ StorageType& storage;
+};
+
+} // namespace runtime
+
+#endif //__RUNTIME_SERIALIZER_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_SMACK_H__
+#define __RUNTIME_SMACK_H__
+
+#include <string>
+
+#include "filesystem.h"
+
+namespace runtime {
+
+class Smack final {
+public:
+ Smack() = delete;
+ Smack(const Smack&) = delete;
+ Smack(Smack&&) = delete;
+
+ Smack& operator=(const Smack&) = delete;
+ Smack& operator=(Smack&&) = delete;
+
+ static void setAccess(File& file, const std::string& label);
+ static void setExecute(File& file, const std::string& label);
+ static void setMmap(File& file, const std::string& label);
+ static void setTransmute(File& file, const bool enable);
+
+ static std::string getAccess(File& file);
+ static std::string getExecute(File& file);
+ static std::string getMmap(File& file);
+ static bool getTransmute(File& file);
+
+
+private:
+ static void set(File& file, const char* xattr, const std::string& label);
+ static std::string get(File& file, const char* xattr);
+};
+
+} // namespace runtime
+#endif //__RUNTIME_SMACK_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __RUNTIME_THREAD_POOL_H__
+#define __RUNTIME_THREAD_POOL_H__
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <functional>
+#include <vector>
+#include <deque>
+
+namespace runtime {
+
+class ThreadPool {
+public:
+ ThreadPool(size_t threads);
+ ~ThreadPool();
+
+ void submit(std::function<void()>&& task);
+
+private:
+ std::vector<std::thread> workers;
+ std::deque<std::function<void()>> tasks;
+
+ std::mutex queueMutex;
+ std::condition_variable condition;
+ bool stop;
+};
+
+} // namespace runtime
+
+#endif //__RUNTIME_THREAD_POOL_H__
+
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <string>
+#include <cstring>
+#include <cerrno>
+
+#include "error.h"
+
+namespace runtime {
+
+int Error::lastErrorCode()
+{
+ return errno;
+}
+
+std::string Error::message(int errorCode)
+{
+ char errmsg[256];
+ return ::strerror_r(errorCode, errmsg, sizeof(errmsg));
+}
+
+std::string Error::message()
+{
+ return message(errno);
+}
+
+std::string GetSystemErrorMessage(int errorCode)
+{
+ return Error::message(errorCode);
+}
+
+std::string GetSystemErrorMessage()
+{
+ return GetSystemErrorMessage(errno);
+}
+
+} // namespace runtime
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdint>
+
+#include "eventfd.h"
+#include "error.h"
+#include "exception.h"
+
+namespace runtime {
+
+EventFD::EventFD(unsigned int initval, int flags)
+{
+ fd = ::eventfd(initval, flags);
+ if (fd == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+EventFD::~EventFD()
+{
+ if (fd != -1) {
+ ::close(fd);
+ }
+}
+
+void EventFD::send()
+{
+ const std::uint64_t val = 1;
+ if (::write(fd, &val, sizeof(val)) == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+void EventFD::receive()
+{
+ std::uint64_t val;
+ if (::read(fd, &val, sizeof(val)) == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+} // namespace runtime
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+
+#include <string>
+#include <sstream>
+
+#include "filesystem.h"
+#include "error.h"
+#include "exception.h"
+
+namespace runtime {
+
+Path::Path()
+{
+}
+
+Path::Path(const std::string& path)
+{
+ assign(path);
+}
+
+Path::Path(const char* path)
+{
+ assign(path);
+}
+
+Path::Path(const Path& path)
+ : pathname(path.pathname)
+{
+}
+
+Path::~Path()
+{
+}
+
+Path& Path::assign(const Path& path)
+{
+ if (&path != this) {
+ pathname = path.pathname;
+ }
+
+ return *this;
+}
+
+Path& Path::assign(const std::string& path)
+{
+ pathname = path;
+
+ return *this;
+}
+
+Path& Path::assign(const char* path)
+{
+ return assign(std::string(path));
+}
+
+Path& Path::operator=(const Path& path)
+{
+ return assign(path);
+}
+
+Path& Path::operator=(const std::string& path)
+{
+ return assign(path);
+}
+
+Path& Path::operator=(const char* path)
+{
+ return assign(path);
+}
+
+File::File()
+ : descriptor(-1)
+{
+}
+
+File::File(const std::string& pathname)
+ : descriptor(-1), path(pathname)
+{
+}
+
+File::File(const Path& filePath)
+ : descriptor(-1), path(filePath)
+{
+}
+
+File::File(const File& file)
+ : File(file.getPath())
+{
+}
+
+File::~File()
+{
+ if (descriptor != -1) {
+ close();
+ }
+}
+
+bool File::exists() const
+{
+ struct stat st;
+ return (::stat(path.getPathname().c_str(), &st) == 0);
+}
+
+bool File::canRead() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ if (st.st_uid == geteuid()) {
+ return ((st.st_mode & S_IRUSR) != 0);
+ } else if (st.st_gid == getegid()) {
+ return ((st.st_mode & S_IRGRP) != 0);
+ }
+
+ return (((st.st_mode & S_IROTH) != 0) || (geteuid() == 0));
+}
+
+bool File::canWrite() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ if (st.st_uid == geteuid()) {
+ return ((st.st_mode & S_IWUSR) != 0);
+ } else if (st.st_gid == getegid()) {
+ return ((st.st_mode & S_IWGRP) != 0);
+ }
+
+ return (((st.st_mode & S_IWOTH) != 0) || (geteuid() == 0));
+}
+
+bool File::canExecute() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ if (st.st_uid == geteuid()) {
+ return ((st.st_mode & S_IXUSR) != 0);
+ } else if (st.st_gid == getegid()) {
+ return ((st.st_mode & S_IXGRP) != 0);
+ }
+
+ return ((st.st_mode & S_IXOTH) != 0);
+}
+
+bool File::isLink() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ return S_ISLNK(st.st_mode);
+}
+
+bool File::isFile() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ return S_ISREG(st.st_mode);
+}
+
+bool File::isDirectory() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ return S_ISDIR(st.st_mode);
+}
+
+bool File::isDevice() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ return (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode));
+}
+
+bool File::isHidden() const
+{
+ return false;
+}
+
+std::string File::toString() const
+{
+ struct stat st;
+ if (::stat(path.getPathname().c_str(), &st) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ return std::string("Test String");
+}
+
+void File::open(int flags, mode_t mode)
+{
+ while (1) {
+ descriptor = ::open(path.getPathname().c_str(), flags, mode);
+ if (descriptor == -1) {
+ if (errno != EINTR) {
+ continue;
+ }
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+ return;
+ }
+}
+
+void File::close()
+{
+ while (1) {
+ if (::close(descriptor) == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ }
+ return;
+ }
+}
+
+void File::copyTo(const std::string& dest) const
+{
+}
+
+void File::moveTo(const std::string& dest)
+{
+}
+
+void File::renameTo(const std::string& dest)
+{
+}
+
+void File::remove(bool recursive)
+{
+ if (isDirectory()) {
+ if (recursive) {
+ DirectoryIterator iter(path), end;
+ while (iter != end) {
+ iter->remove(true);
+ ++iter;
+ }
+ }
+ if (::rmdir(path.getPathname().c_str()) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+ } else {
+ if (::unlink(path.getPathname().c_str()) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+ }
+}
+
+void File::makeDirectory(bool recursive)
+{
+ if (recursive) {
+ const std::string& pathStr = path.getPathname();
+ for (unsigned int i = 0; i != std::string::npos;) {
+ i = pathStr.find('/', i + 1);
+ ::mkdir(pathStr.substr(0, i).c_str(), 0777);
+ }
+ } else if (::mkdir(path.getPathname().c_str(), 0777) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+void File::chown(uid_t uid, gid_t gid)
+{
+ if (::chown(path.getPathname().c_str(), uid, gid) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+void File::chmod(mode_t mode)
+{
+ if (::chmod(path.getPathname().c_str(), mode) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+DirectoryIterator::DirectoryIterator()
+ : directoryHandle(nullptr)
+{
+}
+
+DirectoryIterator::DirectoryIterator(const std::string& dir)
+ : directoryHandle(nullptr)
+{
+ reset(dir);
+}
+
+DirectoryIterator::DirectoryIterator(const Path& dir)
+ : DirectoryIterator(dir.getPathname())
+{
+}
+
+DirectoryIterator::~DirectoryIterator()
+{
+ if (directoryHandle != nullptr) {
+ ::closedir(directoryHandle);
+ }
+}
+
+void DirectoryIterator::reset(const std::string& dir)
+{
+ if (directoryHandle != nullptr) {
+ ::closedir(directoryHandle);
+ directoryHandle = nullptr;
+ }
+
+ basename = dir;
+ directoryHandle = ::opendir(basename.c_str());
+ if (directoryHandle == nullptr) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ next();
+}
+
+void DirectoryIterator::next()
+{
+ std::string name;
+ struct dirent entry, *ent;
+
+ while (1) {
+ if (readdir_r(directoryHandle, &entry, &ent) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ if (ent == NULL)
+ break;
+
+ if (ent->d_name[0] == '.' && ent->d_name[1] == '\0') {
+ continue;
+ }
+
+ if (ent->d_name[0] == '.' &&
+ ent->d_name[1] == '.' && ent->d_name[2] == '\0') {
+ continue;
+ }
+
+ name = basename + "/" + std::string(ent->d_name);
+ break;
+ }
+
+ current = name;
+}
+
+DirectoryIterator& DirectoryIterator::operator=(const std::string& dir)
+{
+ reset(dir);
+ return *this;
+}
+
+DirectoryIterator& DirectoryIterator::operator=(const Path& dir)
+{
+ reset(dir.getPathname());
+ return *this;
+}
+
+DirectoryIterator& DirectoryIterator::operator++()
+{
+ next();
+ return *this;
+}
+
+static const struct mountOption {
+ const char* name;
+ int clear;
+ int flag;
+} mountOptions[] = {
+ { "defaults", 0, 0 },
+ { "ro", 0, MS_RDONLY },
+ { "rw", 1, MS_RDONLY },
+ { "suid", 1, MS_NOSUID },
+ { "nosuid", 0, MS_NOSUID },
+ { "dev", 1, MS_NODEV },
+ { "nodev", 0, MS_NODEV },
+ { "exec", 1, MS_NOEXEC },
+ { "noexec", 0, MS_NOEXEC },
+ { "sync", 0, MS_SYNCHRONOUS },
+ { "async", 1, MS_SYNCHRONOUS },
+ { "dirsync", 0, MS_DIRSYNC },
+ { "remount", 0, MS_REMOUNT },
+ { "mand", 0, MS_MANDLOCK },
+ { "nomand", 1, MS_MANDLOCK },
+ { "atime", 1, MS_NOATIME },
+ { "noatime", 0, MS_NOATIME },
+ { "diratime", 1, MS_NODIRATIME },
+ { "nodiratime", 0, MS_NODIRATIME },
+ { "bind", 0, MS_BIND },
+ { "rbind", 0, MS_BIND | MS_REC },
+ { "relatime", 0, MS_RELATIME },
+ { "norelatime", 1, MS_RELATIME },
+ { "strictatime", 0, MS_STRICTATIME },
+ { "nostrictatime", 1, MS_STRICTATIME },
+ { NULL, 0, 0 },
+};
+
+static unsigned long parseMountOptions(const std::string& opts, std::string& mntdata)
+{
+ std::stringstream optsSstream(opts);
+ const struct mountOption* mo;
+ unsigned long mntflags = 0L;
+ std::string opt;
+
+ while (std::getline(optsSstream, opt, ',')) {
+ for (mo = mountOptions; mo->name != NULL; mo++) {
+ if (opt == mo->name) {
+ if (mo->clear) {
+ mntflags &= ~mo->flag;
+ } else {
+ mntflags |= mo->flag;
+ }
+ break;
+ }
+ if (mo->name != NULL) {
+ continue;
+ }
+ if (!mntdata.empty()) {
+ mntdata += ",";
+ }
+ mntdata += opt;
+ }
+ }
+
+ return mntflags;
+}
+
+void Mount::mountEntry(const std::string& src, const std::string& dest, const std::string& type, const std::string& opts)
+{
+ int ret;
+ unsigned long mntflags;
+ std::string mntdata;
+
+ mntflags = parseMountOptions(opts, mntdata);
+
+ ret = ::mount(src.c_str(),
+ dest.c_str(),
+ type.c_str(),
+ mntflags & ~MS_REMOUNT,
+ mntdata.c_str());
+
+ if (ret) {
+ if ((mntflags & MS_REMOUNT) || (mntflags & MS_BIND)) {
+ ret = ::mount(src.c_str(),
+ dest.c_str(),
+ type.c_str(),
+ mntflags | MS_REMOUNT,
+ mntdata.c_str());
+ }
+
+ if (ret) {
+ throw runtime::Exception("failed to mount " + src + " on " + dest);
+ }
+ }
+}
+
+} // namespace runtime
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <sys/epoll.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <iostream>
+
+#include "error.h"
+#include "exception.h"
+#include "mainloop.h"
+
+#define MAX_EPOLL_EVENTS 16
+
+namespace runtime {
+
+Mainloop::Mainloop() :
+ pollFd(::epoll_create1(EPOLL_CLOEXEC)),
+ stopped(false)
+{
+ if (pollFd == -1) {
+ throw Exception(GetSystemErrorMessage());
+ }
+}
+
+Mainloop::~Mainloop()
+{
+ if (!callbacks.empty()) {
+ assert(0 && "callback list is not empty");
+ }
+
+ ::close(pollFd);
+}
+
+void Mainloop::addEventSource(const int fd, const Event events, Callback&& callback)
+{
+ epoll_event event;
+ std::lock_guard<Mutex> lock(mutex);
+
+ if (callbacks.find(fd) != callbacks.end()) {
+ throw Exception(GetSystemErrorMessage());
+ }
+
+ ::memset(&event, 0, sizeof(epoll_event));
+
+ event.events = events;
+ event.data.fd = fd;
+
+ if (::epoll_ctl(pollFd, EPOLL_CTL_ADD, fd, &event) == -1) {
+ throw Exception(GetSystemErrorMessage());
+ }
+
+ callbacks.insert({fd, std::make_shared<Callback>(std::move(callback))});
+}
+
+void Mainloop::removeEventSource(const int fd)
+{
+ std::lock_guard<Mutex> lock(mutex);
+
+ auto iter = callbacks.find(fd);
+ if (iter == callbacks.end()) {
+ return;
+ }
+
+ callbacks.erase(iter);
+
+ ::epoll_ctl(pollFd, EPOLL_CTL_DEL, fd, NULL);
+}
+
+bool Mainloop::dispatch(const int timeout)
+{
+ int nfds;
+ epoll_event event[MAX_EPOLL_EVENTS];
+
+ do {
+ nfds = ::epoll_wait(pollFd, event, MAX_EPOLL_EVENTS, timeout);
+ } while ((nfds == -1) && (errno == EINTR));
+
+ if (nfds < 0) {
+ throw Exception(GetSystemErrorMessage());
+ }
+
+ for (int i = 0; i < nfds; i++) {
+ std::lock_guard<Mutex> lock(mutex);
+
+ auto iter = callbacks.find(event[i].data.fd);
+ if (iter == callbacks.end()) {
+ continue;
+ }
+
+ std::shared_ptr<Callback> callback(iter->second);
+ try {
+ if ((event[i].events & (EPOLLHUP | EPOLLRDHUP))) {
+ event[i].events &= ~EPOLLIN;
+ }
+
+ (*callback)(event[i].data.fd, event[i].events);
+ } catch (std::exception& e) {
+ std::cout << "EXCEPTION ON MAINLOOP" << std::endl;
+ }
+ }
+
+ return true;
+}
+
+void Mainloop::stop()
+{
+ wakeupSignal.send();
+}
+
+void Mainloop::run()
+{
+ auto wakeupMainloop = [this](int fd, Mainloop::Event event) {
+ wakeupSignal.receive();
+ removeEventSource(wakeupSignal.getFd());
+ stopped = true;
+ };
+
+ addEventSource(wakeupSignal.getFd(), EPOLLIN, wakeupMainloop);
+
+ while (!stopped) {
+ dispatch(-1);
+ }
+}
+
+} // namespace runtime
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "process.h"
+#include "error.h"
+#include "exception.h"
+
+namespace runtime {
+
+Process::Process(const std::string& prog) :
+ status(-1), pid(-1), program(prog)
+{
+ args.push_back(prog);
+}
+
+Process::Process(const std::string& prog, const std::vector<std::string>& args) :
+ status(-1), pid(-1), program(prog), args(args)
+{
+}
+
+Process::Process(const Process& proc)
+{
+}
+
+Process::~Process()
+{
+}
+
+Process& Process::operator=(const Process& proc)
+{
+ return *this;
+}
+
+int Process::execute()
+{
+ pid = ::fork();
+ if (pid == -1) {
+ return -1;
+ }
+
+ if (pid == 0) {
+ const char** argv = new const char *[args.size() + 1];
+
+ int i = 0;
+ for (std::string & arg : args) {
+ argv[i++] = arg.c_str();
+ }
+ argv[i] = NULL;
+
+ ::execv(program.c_str(), const_cast<char* const*>(argv));
+ std::quick_exit(EXIT_FAILURE);
+ }
+
+ return waitForFinished();
+}
+
+int Process::waitForFinished()
+{
+ while (::waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR) {
+ return -1;
+ }
+ }
+
+ return status;
+}
+
+bool Process::isRunning() const
+{
+ if (::kill(pid, 0) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+void Process::kill()
+{
+ if (::kill(pid, SIGKILL) == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+void Process::terminate()
+{
+ if (::kill(pid, SIGINT) == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+} // namespace runtime
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "client.h"
+
+namespace rmi {
+
+Client::Client(const std::string& path) :
+ address(path)
+{
+}
+
+Client::~Client()
+{
+ disconnect();
+}
+
+void Client::connect()
+{
+ connection = std::make_shared<Connection>(Socket::connect(address));
+
+ dispatcher = std::thread([this] { mainloop.run(); });
+}
+
+int Client::unsubscribe(const std::string& provider, int id)
+{
+ mainloop.removeEventSource(id);
+ return 0;
+}
+
+int Client::subscribe(const std::string& provider, const std::string& name)
+{
+ Message request = connection->createMessage(Message::MethodCall, provider);
+ request.packParameters(name);
+ connection->send(request);
+
+ Message reply = connection->dispatch();
+ if (reply.isError()) {
+ return -1;
+ }
+
+ FileDescriptor response;
+ reply.disclose(response);
+
+ return response.fileDescriptor;
+}
+
+void Client::disconnect()
+{
+ mainloop.stop();
+ if (dispatcher.joinable()) {
+ dispatcher.join();
+ }
+}
+
+} // namespace rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utility>
+
+#include "connection.h"
+
+namespace rmi {
+
+Connection::Connection(Socket&& sock) :
+ socket(std::move(sock))
+{
+}
+
+Connection::~Connection() noexcept
+{
+}
+
+Message Connection::createMessage(unsigned int type, const std::string& target)
+{
+ return Message(type, target);
+}
+
+void Connection::send(const Message& message) const
+{
+ std::lock_guard<std::mutex> lock(transmitMutex);
+ message.encode(socket);
+}
+
+Message Connection::dispatch() const
+{
+ Message message;
+
+ std::lock_guard<std::mutex> lock(receiveMutex);
+ message.decode(socket);
+
+ return message;
+}
+
+} // namespace rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "message-composer.h"
+
+namespace rmi {
+
+MessageComposer::MessageComposer(size_t caps) :
+ capacity(caps),
+ produce(0),
+ consume(0),
+ buffer(new char[caps])
+{
+}
+
+MessageComposer::MessageComposer(const MessageComposer& rhs) :
+ capacity(rhs.capacity),
+ produce(rhs.produce),
+ consume(rhs.consume),
+ buffer(new char[rhs.capacity])
+{
+ std::copy(rhs.buffer + consume, rhs.buffer + produce, buffer + consume);
+}
+
+MessageComposer::MessageComposer(MessageComposer&& rhs) :
+ capacity(0),
+ produce(0),
+ consume(0),
+ buffer(nullptr)
+{
+ buffer = rhs.buffer;
+ capacity = rhs.capacity;
+ produce = rhs.produce;
+ consume = rhs.consume;
+
+ // Release buffer pointer from the source object so that
+ // the destructor does not free the memory multiple times.
+
+ rhs.buffer = nullptr;
+ rhs.produce = 0;
+ rhs.consume = 0;
+}
+
+MessageComposer::~MessageComposer()
+{
+ if (buffer != nullptr) {
+ delete[] buffer;
+ }
+}
+
+MessageComposer& MessageComposer::operator=(const MessageComposer& rhs)
+{
+ if (this != &rhs) {
+ delete[] buffer;
+
+ capacity = rhs.capacity;
+ produce = rhs.produce;
+ consume = rhs.consume;
+ buffer = new char[capacity];
+ std::copy(rhs.buffer + consume, rhs.buffer + produce, buffer + consume);
+ }
+
+ return *this;
+}
+
+MessageComposer& MessageComposer::operator=(MessageComposer&& rhs)
+{
+ if (this != &rhs) {
+ // Free existing buffer
+ delete[] buffer;
+
+ // Copy the buffer pointer and its attributes from the
+ // source object.
+ buffer = rhs.buffer;
+ produce = rhs.produce;
+ consume = rhs.consume;
+ capacity = rhs.capacity;
+
+ // Release buffer pointer from the source object so that
+ // the destructor does not free the memory multiple times.
+ rhs.buffer = nullptr;
+ rhs.produce = 0;
+ rhs.consume = 0;
+ rhs.capacity = 0;
+ }
+
+ return *this;
+}
+
+void MessageComposer::insure(size_t sz)
+{
+ if (sz > capacity)
+ {
+ size_t new_capacity = sz;
+ char* new_buffer = new char[new_capacity];
+
+ ::memcpy(new_buffer, buffer, capacity);
+
+ delete[] buffer;
+
+ buffer = new_buffer;
+ capacity = new_capacity;
+
+ }
+}
+
+void MessageComposer::write(const void* ptr, const size_t sz)
+{
+ size_t bytes = sz;
+ if ((produce + bytes) > capacity) {
+ insure(produce + bytes);
+ }
+
+ ::memcpy(reinterpret_cast<char *>(buffer + produce), ptr, bytes);
+ produce += bytes;
+}
+
+void MessageComposer::read(void* ptr, const size_t sz)
+{
+ size_t bytes = sz;
+ if ((consume + bytes) > produce) {
+ bytes = produce - consume;
+ }
+
+ ::memcpy(ptr, reinterpret_cast<char *>(buffer) + consume, bytes);
+ consume += bytes;
+
+ // Reset cursors if there is no data
+ if (consume == produce) {
+ consume = produce = 0;
+ }
+}
+
+} // namespae rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "message.h"
+
+namespace rmi {
+
+std::atomic<unsigned int> Message::sequence(0);
+
+Message::Message() :
+ signature({sequence++, Invalid, ""})
+{
+}
+
+Message::Message(unsigned int id, unsigned int type, const std::string& target) :
+ signature({id, type, target})
+{
+ enclose(signature);
+}
+
+Message::Message(unsigned int type, const std::string& target) :
+ signature({sequence++, type, target})
+{
+ enclose(signature);
+}
+
+Message::Message(Message&& rhs)
+ : signature(std::move(rhs.signature)),
+ buffer(std::move(rhs.buffer)),
+ fileDescriptors(std::move(rhs.fileDescriptors))
+{
+}
+
+Message::~Message()
+{
+}
+
+Message::Message(const Message& rhs) :
+ signature(rhs.signature),
+ buffer(rhs.buffer)
+{
+ enclose(signature);
+}
+
+Message& Message::operator=(const Message& rhs)
+{
+ if (this != &rhs) {
+ buffer = rhs.buffer;
+ signature = rhs.signature;
+ }
+
+ return *this;
+}
+
+Message& Message::operator=(Message&& rhs)
+{
+ if (this != &rhs) {
+ buffer = std::move(rhs.buffer);
+ signature = std::move(rhs.signature);
+ fileDescriptors = std::move(rhs.fileDescriptors);
+ }
+
+ return *this;
+}
+
+Message Message::createReplyMessage() const
+{
+ return Message(id(), Reply, target());
+}
+
+Message Message::createErrorMessage() const
+{
+ return Message(id(), Error, target());
+}
+
+template<> void Message::enclose(FileDescriptor&& fd)
+{
+ fileDescriptors.push_back(std::move(fd));
+}
+
+template<> void Message::disclose(FileDescriptor& fd)
+{
+ if (!fileDescriptors.empty()) {
+ fd.fileDescriptor = std::move(fileDescriptors.front()).fileDescriptor;
+ fileDescriptors.pop_front();
+ }
+}
+
+} // namespace rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "notification.h"
+#include "exception.h"
+#include "error.h"
+
+namespace rmi {
+
+Notification::Notification()
+{
+}
+
+Notification::Notification(const std::string& name) :
+ signalName(name)
+{
+}
+
+Notification::Notification(Notification&& rhs) :
+ signalName(std::move(rhs.signalName)),
+ subscribers(std::move(rhs.subscribers))
+{
+}
+
+SubscriptionId Notification::createSubscriber()
+{
+ int fds[2] = {-1, -1};
+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
+ throw runtime::Exception("Failed to create socket pair");
+ }
+
+ std::lock_guard<std::mutex> lock(subscriberLock);
+ subscribers.emplace_back(std::make_shared<Socket>(fds[0]));
+
+ return SubscriptionId(fds[0], fds[1]);
+}
+
+int Notification::removeSubscriber(const int id)
+{
+ std::lock_guard<std::mutex> lock(subscriberLock);
+
+ std::vector<std::shared_ptr<Socket>>::iterator it = subscribers.begin();
+
+ while (it != subscribers.end()) {
+ if ((*it)->getFd() == id) {
+ subscribers.erase(it);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+} // namespace rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <algorithm>
+
+#include "exception.h"
+#include "service.h"
+#include "message.h"
+
+namespace rmi {
+
+thread_local Service::ProcessingContext Service::processingContext;
+
+Service::Service(const std::string& path) :
+ address(path),
+ workqueue(5)
+{
+ setNewConnectionCallback(nullptr);
+ setCloseConnectionCallback(nullptr);
+}
+
+Service::~Service()
+{
+}
+
+void Service::start()
+{
+ Socket socket(Socket::create(address));
+
+ auto accept = [&](int fd, runtime::Mainloop::Event event) {
+ onNewConnection(std::make_shared<Connection>(socket.accept()));
+ };
+
+ mainloop.addEventSource(socket.getFd(),
+ EPOLLIN | EPOLLHUP | EPOLLRDHUP,
+ accept);
+ mainloop.run();
+}
+
+void Service::stop()
+{
+}
+
+Service::ConnectionRegistry::iterator Service::getConnectionIterator(const int id)
+{
+ std::lock_guard<std::mutex> lock(stateLock);
+
+ return std::find_if(connectionRegistry.begin(), connectionRegistry.end(),
+ [id](const std::shared_ptr<Connection>& connection) {
+ return id == connection->getFd();
+ });
+}
+
+void Service::setNewConnectionCallback(const ConnectionCallback& connectionCallback)
+{
+ auto callback = [connectionCallback, this](const std::shared_ptr<Connection>& connection) {
+ auto handle = [&](int fd, runtime::Mainloop::Event event) {
+ auto iter = getConnectionIterator(fd);
+ if (iter == connectionRegistry.end()) {
+ return;
+ }
+
+ if ((event & EPOLLHUP) || (event & EPOLLRDHUP)) {
+ onCloseConnection(*iter);
+ connectionRegistry.erase(iter);
+ return;
+ }
+ onMessageProcess(*iter);
+ };
+
+ if ((connectionCallback == nullptr) ||
+ (connectionCallback(*connection) == true)) {
+ mainloop.addEventSource(connection->getFd(),
+ EPOLLIN | EPOLLHUP | EPOLLRDHUP,
+ handle);
+ connectionRegistry.push_back(connection);
+ }
+ };
+
+ std::lock_guard<std::mutex> lock(stateLock);
+ onNewConnection = std::move(callback);
+}
+
+void Service::setCloseConnectionCallback(const ConnectionCallback& closeCallback)
+{
+ auto callback = [closeCallback, this](const std::shared_ptr<Connection>& connection) {
+ mainloop.removeEventSource(connection->getFd());
+ if (closeCallback) {
+ closeCallback(*connection);
+ }
+ };
+
+ std::lock_guard<std::mutex> lock(stateLock);
+ onCloseConnection = std::move(callback);
+}
+
+void Service::createNotification(const std::string& name)
+{
+ std::lock_guard<std::mutex> lock(notificationLock);
+
+ if (notificationRegistry.count(name)) {
+ throw runtime::Exception("Notification [" + name + "] already registered");
+ }
+
+ notificationRegistry.emplace(name, name);
+}
+
+int Service::subscribeNotification(const std::string& name)
+{
+ auto closeHandler = [&, name](int fd, runtime::Mainloop::Event event) {
+ if ((event & EPOLLHUP) || (event & EPOLLRDHUP)) {
+ unsubscribeNotification(name, fd);
+ return;
+ }
+ };
+
+ notificationLock.lock();
+ if (!notificationRegistry.count(name)) {
+ notificationLock.unlock();
+ return -1;
+ }
+
+ Notification& notification = notificationRegistry[name];
+ notificationLock.unlock();
+
+ try {
+ SubscriptionId slot = notification.createSubscriber();
+ mainloop.addEventSource(slot.first, EPOLLHUP | EPOLLRDHUP, closeHandler);
+ return slot.second;
+ } catch (runtime::Exception& e) {
+ return -1;
+ }
+
+ return -1;
+}
+
+int Service::unsubscribeNotification(const std::string& name, const int id)
+{
+ notificationLock.lock();
+
+ if (!notificationRegistry.count(name)) {
+ notificationLock.unlock();
+ return -1;
+ }
+
+ Notification& notification = notificationRegistry[name];
+ notificationLock.unlock();
+
+ notification.removeSubscriber(id);
+
+ mainloop.removeEventSource(id);
+
+ return 0;
+}
+
+void Service::onMessageProcess(const std::shared_ptr<Connection>& connection)
+{
+ auto process = [&](Message& request) {
+ try {
+ //stateLock.lock();
+ std::shared_ptr<MethodDispatcher> methodDispatcher = methodRegistry.at(request.target());
+ //stateLock.unlock();
+
+ // [TBD] Request authentication before dispatching method handler.
+ processingContext = ProcessingContext(connection);
+ connection->send((*methodDispatcher)(request));
+ } catch (std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ connection->send(request.createErrorMessage());
+ }
+ };
+
+ try {
+ workqueue.submit(std::bind(process, connection->dispatch()));
+ } catch (runtime::Exception& e) {
+ std::cerr << e.what() << std::endl;
+ }
+}
+
+} // namespace rmi
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cstring>
+#include <iostream>
+
+#include "error.h"
+#include "socket.h"
+
+namespace rmi {
+
+namespace {
+
+const int MAX_BACKLOG_SIZE = 100;
+
+void setCloseOnExec(int fd)
+{
+ if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+}
+
+Credentials getCredentials(int fd)
+{
+ struct ucred cred;
+ socklen_t credsz = sizeof(cred);
+ if (::getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &credsz)) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ return {cred.pid, cred.uid, cred.gid};
+}
+
+} // namespace
+
+Socket::Socket(int fd, bool autoclose) :
+ socketFd(fd),
+ autoClose(autoclose)
+{
+}
+
+Socket::Socket(Socket&& socket) noexcept :
+ socketFd(socket.socketFd),
+ autoClose(socket.autoClose)
+{
+ socket.socketFd = -1;
+}
+
+Socket::~Socket() noexcept
+{
+ if ((socketFd != -1) && (autoClose)) {
+ ::close(socketFd);
+ }
+}
+
+Socket Socket::accept()
+{
+ int sockfd = ::accept(socketFd, nullptr, nullptr);
+ if (sockfd == -1) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ setCloseOnExec(sockfd);
+
+ return Socket(sockfd);
+}
+
+int Socket::getFd() const
+{
+ return socketFd;
+}
+
+Credentials Socket::getPeerCredentials() const
+{
+ return getCredentials(socketFd);
+}
+
+void Socket::read(void *buffer, const size_t size) const
+{
+ size_t total = 0;
+
+ while (total < size) {
+ int bytes = ::read(socketFd, reinterpret_cast<char*>(buffer) + total, size - total);
+ if (bytes >= 0) {
+ total += bytes;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ continue;
+ } else {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+ }
+}
+
+void Socket::write(const void *buffer, const size_t size) const
+{
+ size_t written = 0;
+
+ while (written < size) {
+ int bytes = ::write(socketFd, reinterpret_cast<const char*>(buffer) + written, size - written);
+ if (bytes >= 0) {
+ written += bytes;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ continue;
+ } else {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+ }
+}
+
+void Socket::sendFileDescriptors(const int* fds, const size_t nr) const
+{
+ if (nr == 0) return;
+
+ int buf;
+ struct iovec iov = {
+ .iov_base = &buf,
+ .iov_len = sizeof(char)
+ };
+
+ char buffer[CMSG_SPACE(sizeof(int) * nr)];
+ ::memset(buffer, 0, sizeof(buffer));
+
+ struct msghdr msgh;
+ ::memset(&msgh, 0, sizeof(msgh));
+
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = buffer;
+ msgh.msg_controllen = sizeof(buffer);
+
+ struct cmsghdr *cmhp;
+ cmhp = CMSG_FIRSTHDR(&msgh);
+ cmhp->cmsg_level = SOL_SOCKET;
+ cmhp->cmsg_type = SCM_RIGHTS;
+ cmhp->cmsg_len = CMSG_LEN(sizeof(int) * nr);
+
+ ::memcpy(CMSG_DATA(cmhp), fds, sizeof(int) * nr);
+
+ int written = 0;
+ while (written < 1) {
+ ssize_t ret = ::sendmsg(socketFd, &msgh, MSG_NOSIGNAL);
+ if (ret >= 0) {
+ written += ret;
+ } else if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINTR)) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+ }
+}
+
+void Socket::receiveFileDescriptors(int* fds, const size_t nr) const
+{
+ if (nr == 0) return;
+
+ char buf = '!';
+ struct iovec iov = {
+ .iov_base = &buf,
+ .iov_len = sizeof(char)
+ };
+
+ char buffer[CMSG_SPACE(sizeof(int) * nr) + CMSG_SPACE(sizeof(struct ucred))];
+ ::memset(buffer, 0, sizeof(buffer));
+
+ struct msghdr msgh;
+ ::memset(&msgh, 0, sizeof(msgh));
+
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = buffer;
+ msgh.msg_controllen = sizeof(buffer);
+
+ ssize_t bytes = 0;
+ while (bytes < 1) {
+ ssize_t ret = ::recvmsg(socketFd, &msgh, MSG_WAITALL);
+ if (ret >= 0) {
+ bytes += ret;
+ } else {
+ if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != EINTR)) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+ }
+ }
+
+ int i = 0;
+ for (struct cmsghdr *cmhp = CMSG_FIRSTHDR(&msgh); cmhp != NULL; cmhp = CMSG_NXTHDR(&msgh, cmhp)) {
+ if ((cmhp->cmsg_level == SOL_SOCKET) && (cmhp->cmsg_type == SCM_RIGHTS)) {
+ if (cmhp->cmsg_len != CMSG_LEN(sizeof(int) * nr)) {
+ std::cout << "Invalid File Descriptor Table" << std::endl;
+ }
+
+ fds[i++] = *(reinterpret_cast<int*>(CMSG_DATA(cmhp)));
+ }
+ }
+}
+
+#ifdef USE_SYSTEMD_SOCKET_ACTIVATION
+int Socket::createSystemdSocket(const std::string& path)
+{
+ int n = ::sd_listen_fds(-1);
+ if (n < 0) {
+ throw SocketException("sd_listen_fds faield");
+ }
+
+ for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
+ if (::sd_is_socket_unix(fd, SOCK_STREAM, 1, path.c_str(), 0) > 0) {
+ setCloseOnExec(fd);
+ return fd;
+ }
+ }
+
+ return -1;
+}
+#endif
+
+int Socket::createRegularSocket(const std::string& path)
+{
+ if (path.size() >= sizeof(sockaddr_un::sun_path)) {
+ throw SocketException(runtime::GetSystemErrorMessage(ENAMETOOLONG));
+ }
+
+ int sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ setCloseOnExec(sockfd);
+
+ ::sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ ::strncpy(addr.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
+
+ if (addr.sun_path[0] == '@') {
+ addr.sun_path[0] = '\0';
+ } else {
+ unlink(path.c_str());
+ }
+
+ if (::bind(sockfd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(struct sockaddr_un)) == -1) {
+ ::close(sockfd);
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ int optval = 1;
+ if (::setsockopt(sockfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+ ::close(sockfd);
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ if (::listen(sockfd, MAX_BACKLOG_SIZE) == -1) {
+ ::close(sockfd);
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ return sockfd;
+}
+
+Socket Socket::create(const std::string& path)
+{
+ int fd;
+
+#ifdef USE_SYSTEMD_SOCKET_ACTIVATION
+ fd = createSystemdSocket(path);
+ if (fd == -1) {
+ fd = createRegularSocket(path);
+ }
+#else
+ fd = createRegularSocket(path);
+#endif
+
+ return Socket(fd);
+}
+
+Socket Socket::connect(const std::string& path)
+{
+ if (path.size() >= sizeof(sockaddr_un::sun_path)) {
+ throw SocketException(runtime::GetSystemErrorMessage(ENAMETOOLONG));
+ }
+
+ int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ setCloseOnExec(fd);
+
+ sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ ::strncpy(addr.sun_path, path.c_str(), sizeof(sockaddr_un::sun_path));
+
+ if (addr.sun_path[0] == '@') {
+ addr.sun_path[0] = '\0';
+ }
+
+ if (::connect(fd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(struct sockaddr_un)) == -1) {
+ ::close(fd);
+ throw SocketException(runtime::GetSystemErrorMessage());
+ }
+
+ return Socket(fd);
+}
+
+} // namespace Ipc
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "thread-pool.h"
+#include "exception.h"
+
+#define __BEGIN_CRITICAL__ { std::unique_lock<std::mutex> lock(this->queueMutex);
+#define __END_CRITICAL__ }
+
+namespace runtime {
+
+ThreadPool::ThreadPool(size_t threads)
+ : stop(false)
+{
+ for (size_t i = 0; i < threads; i++) {
+ workers.emplace_back([this] {
+ while (true) {
+ std::function<void()> task;
+
+ __BEGIN_CRITICAL__
+ condition.wait(lock, [this]{ return stop || !tasks.empty();});
+ if (stop && tasks.empty()) {
+ return;
+ }
+
+ task = std::move(tasks.front());
+ tasks.pop_front();
+ __END_CRITICAL__
+
+ task();
+ }
+ });
+ }
+}
+
+ThreadPool::~ThreadPool()
+{
+ __BEGIN_CRITICAL__
+ stop = true;
+ __END_CRITICAL__
+
+ condition.notify_all();
+
+ for (std::thread &worker: workers) {
+ if (worker.joinable()) {
+ worker.join();
+ }
+ }
+}
+
+void ThreadPool::submit(std::function<void()>&& task)
+{
+ __BEGIN_CRITICAL__
+ if (!stop) {
+ tasks.push_back(std::move(task));
+ }
+ __END_CRITICAL__
+
+ condition.notify_one();
+}
+
+} // namespace runtime
--- /dev/null
+/**
+ * @brief TODO
+ * @date Created 17.05.2017
+ * @author Created 2017 in Samsung Ukraine R&D Center (SURC) under a contract
+ * between LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
+ * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea).
+ * Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
+ * @author Mail to: <A HREF="mailto:a.gudz@samsung.com">Andriy Gudz, a.gudz@samsung.com</A>
+ */
+#include <iostream>
+#include <string>
+#include <mutex>
+#include <condition_variable>
+
+#include <gtest/gtest.h>
+
+#include "rmi/service.h"
+#include "rmi/client.h"
+#include <signal.h>
+#include <execinfo.h>
+
+using namespace std;
+
+namespace
+{
+
+const std::string RMI_SERVICE_ADDRESS = "/tmp/.rmi_service";
+
+}
+
+class AgentInterface
+{
+public:
+ void run()
+ {
+ // Prepare execution environment
+ cout << "2" << flush;
+ service->start();
+ cout << "3" << flush;
+ }
+
+ void terminate()
+ {
+ service->stop();
+ }
+
+ string handshake(string input)
+ {
+ if (input == "SYN")
+ return "SYN-ACC";
+ return "FAIL";
+ }
+
+ static AgentInterface& instance()
+ {
+ static AgentInterface _instance_;
+ return _instance_;
+ }
+
+private:
+ AgentInterface()
+ {
+ service.reset(new rmi::Service(RMI_SERVICE_ADDRESS));
+ cout << "0" << flush;
+ service->registerParametricMethod(this, (string)(AgentInterface::handshake)(string));
+ cout << "1" << flush;
+ }
+
+ ~AgentInterface()
+ {
+ }
+
+ std::unique_ptr<rmi::Service> service;
+};
+
+void sig_handler(int signal)
+{
+ std::cout << "Signal trapped: " << signal << std::endl;
+ const int SIZE = 100;
+ void* recs[SIZE];
+
+ int count = backtrace(recs, SIZE);
+ std::cout << "Stack records: " << count << std::endl;
+
+ char** str = backtrace_symbols(recs, count);
+
+ for (int i = 0; i < count; i++)
+ {
+ std::cout << str[i] << std::endl;
+ }
+}
+
+/**
+ * Test checks example of rmi
+ */
+TEST(test_rmi, handshakeCorrect)
+{
+// std::mutex mtx;
+// std::unique_lock<std::mutex> lock(mtx);
+// std::condition_variable cv;
+
+// signal(SIGABRT, sig_handler);
+
+ try
+ {
+ AgentInterface& service = AgentInterface::instance();
+ std::thread agentInterfaceThread ([&]
+ {
+ try
+ {
+ service.run();
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "test_rmi exception: " << e.what() <<std::endl;
+ }
+ });
+
+ rmi::Client client(RMI_SERVICE_ADDRESS);
+ client.connect();
+ ASSERT_EQ("SYN-ACC", client.methodCall<string>("AgentInterface::handshake", string("SYN")));
+ ASSERT_EQ("FAIL", client.methodCall<string>("AgentInterface::handshake", string("NOTSYN")));
+ client.disconnect();
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "test_rmi exception: " << e.what() <<std::endl;
+ }
+}