diff options
Diffstat (limited to 'test/ipc')
-rw-r--r-- | test/ipc/meson.build | 13 | ||||
-rw-r--r-- | test/ipc/unixsocket.cpp | 66 | ||||
-rw-r--r-- | test/ipc/unixsocket_ipc.cpp | 233 |
3 files changed, 279 insertions, 33 deletions
diff --git a/test/ipc/meson.build b/test/ipc/meson.build index cc46b41c..8e447d22 100644 --- a/test/ipc/meson.build +++ b/test/ipc/meson.build @@ -1,12 +1,15 @@ +# SPDX-License-Identifier: CC0-1.0 + ipc_tests = [ - [ 'unixsocket', 'unixsocket.cpp' ], + {'name': 'unixsocket_ipc', 'sources': ['unixsocket_ipc.cpp']}, + {'name': 'unixsocket', 'sources': ['unixsocket.cpp']}, ] -foreach t : ipc_tests - exe = executable(t[0], t[1], - dependencies : libcamera_dep, +foreach test : ipc_tests + exe = executable(test['name'], test['sources'], + dependencies : libcamera_private, link_with : test_libraries, include_directories : test_includes_internal) - test(t[0], exe, suite : 'ipc') + test(test['name'], exe, suite : 'ipc') endforeach diff --git a/test/ipc/unixsocket.cpp b/test/ipc/unixsocket.cpp index f53042b8..f39bd986 100644 --- a/test/ipc/unixsocket.cpp +++ b/test/ipc/unixsocket.cpp @@ -2,10 +2,11 @@ /* * Copyright (C) 2019, Google Inc. * - * unixsocket.cpp - Unix socket IPC test + * Unix socket IPC test */ #include <algorithm> +#include <array> #include <fcntl.h> #include <iostream> #include <stdlib.h> @@ -14,14 +15,15 @@ #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#include <vector> -#include <libcamera/event_dispatcher.h> -#include <libcamera/timer.h> +#include <libcamera/base/event_dispatcher.h> +#include <libcamera/base/thread.h> +#include <libcamera/base/timer.h> + +#include "libcamera/internal/ipc_unixsocket.h" -#include "ipc_unixsocket.h" #include "test.h" -#include "thread.h" -#include "utils.h" #define CMD_CLOSE 0 #define CMD_REVERSE 1 @@ -29,8 +31,11 @@ #define CMD_LEN_CMP 3 #define CMD_JOIN 4 -using namespace std; using namespace libcamera; +using namespace std; +using namespace std::chrono_literals; + +namespace { int calculateLength(int fd) { @@ -41,6 +46,8 @@ int calculateLength(int fd) return size; } +} /* namespace */ + class UnixSocketTestSlave { public: @@ -51,9 +58,9 @@ public: ipc_.readyRead.connect(this, &UnixSocketTestSlave::readyRead); } - int run(int fd) + int run(UniqueFD fd) { - if (ipc_.bind(fd)) { + if (ipc_.bind(std::move(fd))) { cerr << "Failed to connect to IPC channel" << endl; return EXIT_FAILURE; } @@ -67,12 +74,12 @@ public: } private: - void readyRead(IPCUnixSocket *ipc) + void readyRead() { IPCUnixSocket::Payload message, response; int ret; - ret = ipc->receive(&message); + ret = ipc_.receive(&message); if (ret) { cerr << "Receive message failed: " << ret << endl; return; @@ -145,6 +152,7 @@ private: if (num < 0) { cerr << "Read failed" << endl; + close(outfd); stop(-EIO); return; } else if (!num) @@ -152,6 +160,7 @@ private: if (write(outfd, buf, num) < 0) { cerr << "Write failed" << endl; + close(outfd); stop(-EIO); return; } @@ -206,8 +215,7 @@ protected: if (!pid_) { std::string arg = std::to_string(fd); - execl("/proc/self/exe", "/proc/self/exe", - arg.c_str(), nullptr); + execl(self().c_str(), self().c_str(), arg.c_str(), nullptr); /* Only get here if exec fails. */ exit(TestFail); @@ -309,7 +317,7 @@ protected: }; int fds[2]; - for (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) { + for (unsigned int i = 0; i < std::size(strings); i++) { unsigned int len = strlen(strings[i]); fds[i] = open("/tmp", O_TMPFILE | O_RDWR, @@ -331,16 +339,16 @@ protected: if (ret) return ret; - for (unsigned int i = 0; i < ARRAY_SIZE(strings); i++) { + for (unsigned int i = 0; i < std::size(strings); i++) { unsigned int len = strlen(strings[i]); - char buf[len]; + std::vector<char> buf(len); close(fds[i]); - if (read(response.fds[0], &buf, len) <= 0) + if (read(response.fds[0], buf.data(), len) <= 0) return TestFail; - if (memcmp(buf, strings[i], len)) + if (memcmp(buf.data(), strings[i], len)) return TestFail; } @@ -357,11 +365,11 @@ protected: int run() { - int slavefd = ipc_.create(); - if (slavefd < 0) + UniqueFD slavefd = ipc_.create(); + if (!slavefd.isValid()) return TestFail; - if (slaveStart(slavefd)) { + if (slaveStart(slavefd.release())) { cerr << "Failed to start slave" << endl; return TestFail; } @@ -428,7 +436,7 @@ private: if (ret) return ret; - timeout.start(200); + timeout.start(2s); while (!callDone_) { if (!timeout.isRunning()) { cerr << "Call timeout!" << endl; @@ -444,14 +452,14 @@ private: return 0; } - void readyRead(IPCUnixSocket *ipc) + void readyRead() { if (!callResponse_) { cerr << "Read ready without expecting data, fail." << endl; return; } - if (ipc->receive(callResponse_)) { + if (ipc_.receive(callResponse_)) { cerr << "Receive message failed" << endl; return; } @@ -461,7 +469,7 @@ private: int prepareFDs(IPCUnixSocket::Payload *message, unsigned int num) { - int fd = open("/proc/self/exe", O_RDONLY); + int fd = open(self().c_str(), O_RDONLY); if (fd < 0) return fd; @@ -493,10 +501,12 @@ private: int main(int argc, char **argv) { if (argc == 2) { - int ipcfd = std::stoi(argv[1]); + UniqueFD ipcfd = UniqueFD(std::stoi(argv[1])); UnixSocketTestSlave slave; - return slave.run(ipcfd); + return slave.run(std::move(ipcfd)); } - return UnixSocketTest().execute(); + UnixSocketTest test; + test.setArgs(argc, argv); + return test.execute(); } diff --git a/test/ipc/unixsocket_ipc.cpp b/test/ipc/unixsocket_ipc.cpp new file mode 100644 index 00000000..df7d9c2b --- /dev/null +++ b/test/ipc/unixsocket_ipc.cpp @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * Unix socket IPC test + */ + +#include <algorithm> +#include <fcntl.h> +#include <iostream> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <libcamera/base/event_dispatcher.h> +#include <libcamera/base/thread.h> +#include <libcamera/base/timer.h> +#include <libcamera/base/utils.h> + +#include "libcamera/internal/ipa_data_serializer.h" +#include "libcamera/internal/ipc_pipe.h" +#include "libcamera/internal/ipc_pipe_unixsocket.h" +#include "libcamera/internal/process.h" + +#include "test.h" + +using namespace std; +using namespace libcamera; + +enum { + CmdExit = 0, + CmdGetSync = 1, + CmdSetAsync = 2, +}; + +const int32_t kInitialValue = 1337; +const int32_t kChangedValue = 9001; + +class UnixSocketTestIPCSlave +{ +public: + UnixSocketTestIPCSlave() + : value_(kInitialValue), exitCode_(EXIT_FAILURE), exit_(false) + { + dispatcher_ = Thread::current()->eventDispatcher(); + ipc_.readyRead.connect(this, &UnixSocketTestIPCSlave::readyRead); + } + + int run(UniqueFD fd) + { + if (ipc_.bind(std::move(fd))) { + cerr << "Failed to connect to IPC channel" << endl; + return EXIT_FAILURE; + } + + while (!exit_) + dispatcher_->processEvents(); + + ipc_.close(); + + return exitCode_; + } + +private: + void readyRead() + { + IPCUnixSocket::Payload message; + int ret; + + ret = ipc_.receive(&message); + if (ret) { + cerr << "Receive message failed: " << ret << endl; + return; + } + + IPCMessage ipcMessage(message); + uint32_t cmd = ipcMessage.header().cmd; + + switch (cmd) { + case CmdExit: { + exit_ = true; + break; + } + + case CmdGetSync: { + IPCMessage::Header header = { cmd, ipcMessage.header().cookie }; + IPCMessage response(header); + + vector<uint8_t> buf; + tie(buf, ignore) = IPADataSerializer<int32_t>::serialize(value_); + response.data().insert(response.data().end(), buf.begin(), buf.end()); + + ret = ipc_.send(response.payload()); + if (ret < 0) { + cerr << "Reply failed" << endl; + stop(ret); + } + break; + } + + case CmdSetAsync: { + value_ = IPADataSerializer<int32_t>::deserialize(ipcMessage.data()); + break; + } + } + } + + void stop(int code) + { + exitCode_ = code; + exit_ = true; + } + + int32_t value_; + + IPCUnixSocket ipc_; + EventDispatcher *dispatcher_; + int exitCode_; + bool exit_; +}; + +class UnixSocketTestIPC : public Test +{ +protected: + int init() + { + return 0; + } + + int setValue(int32_t val) + { + IPCMessage msg(CmdSetAsync); + tie(msg.data(), ignore) = IPADataSerializer<int32_t>::serialize(val); + + int ret = ipc_->sendAsync(msg); + if (ret < 0) { + cerr << "Failed to call set value" << endl; + return ret; + } + + return 0; + } + + int getValue() + { + IPCMessage msg(CmdGetSync); + IPCMessage buf; + + int ret = ipc_->sendSync(msg, &buf); + if (ret < 0) { + cerr << "Failed to call get value" << endl; + return ret; + } + + return IPADataSerializer<int32_t>::deserialize(buf.data()); + } + + int exit() + { + IPCMessage msg(CmdExit); + + int ret = ipc_->sendAsync(msg); + if (ret < 0) { + cerr << "Failed to call exit" << endl; + return ret; + } + + return 0; + } + + int run() + { + ipc_ = std::make_unique<IPCPipeUnixSocket>("", self().c_str()); + if (!ipc_->isConnected()) { + cerr << "Failed to create IPCPipe" << endl; + return TestFail; + } + + int ret = getValue(); + if (ret != kInitialValue) { + cerr << "Wrong initial value, expected " + << kInitialValue << ", got " << ret << endl; + return TestFail; + } + + ret = setValue(kChangedValue); + if (ret < 0) { + cerr << "Failed to set value: " << strerror(-ret) << endl; + return TestFail; + } + + ret = getValue(); + if (ret != kChangedValue) { + cerr << "Wrong set value, expected " << kChangedValue + << ", got " << ret << endl; + return TestFail; + } + + ret = exit(); + if (ret < 0) { + cerr << "Failed to exit: " << strerror(-ret) << endl; + return TestFail; + } + + return TestPass; + } + +private: + ProcessManager processManager_; + + unique_ptr<IPCPipeUnixSocket> ipc_; +}; + +/* + * Can't use TEST_REGISTER() as single binary needs to act as both client and + * server + */ +int main(int argc, char **argv) +{ + /* IPCPipeUnixSocket passes IPA module path in argv[1] */ + if (argc == 3) { + UniqueFD ipcfd = UniqueFD(std::stoi(argv[2])); + UnixSocketTestIPCSlave slave; + return slave.run(std::move(ipcfd)); + } + + UnixSocketTestIPC test; + test.setArgs(argc, argv); + return test.execute(); +} |