summaryrefslogtreecommitdiff
path: root/test/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'test/ipc')
-rw-r--r--test/ipc/meson.build13
-rw-r--r--test/ipc/unixsocket.cpp66
-rw-r--r--test/ipc/unixsocket_ipc.cpp233
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();
+}