Skip to content

Commit

Permalink
IPC via abstract unix domain sockets (#4)
Browse files Browse the repository at this point in the history
- Added new "SDK" library target; added `ocvsmd-cli` executable target
to consume the SDK.
- Posix calls now are wrapped with `platform::posixSyscallError` (which
does retries on `EINTR`). For now only IPC stuff correctly wrapped; the
same for other places (like executors, udp sockets, etc.) to be
continued...

Also:
- Now compiles on macOS by adding kqueue-based implementation of
executor for Darwin. Thank you @thirtytwobits for sharing your original
implementation (I did some fixes related to `kevent` timeout
calculations - now it's **nano**seconds based instead of seconds).
  • Loading branch information
serges147 authored Dec 27, 2024
1 parent f458771 commit 94fb76d
Show file tree
Hide file tree
Showing 26 changed files with 1,007 additions and 26 deletions.
1 change: 0 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ jobs:
retention-days: 2

style_check:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand Down
9 changes: 8 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ if (NOT clang_format)
message(STATUS "Could not locate clang-format")
else ()
file(GLOB_RECURSE format_files
${include_dir}/**/*.[ch]pp
${include_dir}/**/*.hpp
${src_dir}/**/*.[ch]
${src_dir}/**/*.[ch]pp
${test_dir}/**/*.[ch]pp
Expand Down Expand Up @@ -67,6 +67,13 @@ add_definitions(
-DVCS_REVISION_ID=0x${vcs_revision_id}ULL
-DNODE_NAME="org.opencyphal.ocvsmd"
)
if (DEFINED PLATFORM_LINUX_TYPE)
if(${PLATFORM_LINUX_TYPE} STREQUAL "bsd")
add_definitions(-DPLATFORM_LINUX_TYPE_BSD)
elseif(${PLATFORM_LINUX_TYPE} STREQUAL "debian")
add_definitions(-DPLATFORM_LINUX_TYPE_DEBIAN)
endif()
endif()

add_subdirectory(src)
add_subdirectory(test)
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ Then one of the two presets depending on your system:
###### Debug
```bash
sudo cp build/bin/Debug/ocvsmd /usr/local/bin/ocvsmd
sudo cp build/bin/Debug/ocvsmd-cli /usr/local/bin/ocvsmd-cli
```
###### Release
```bash
sudo cp build/bin/Release/ocvsmd /usr/local/bin/ocvsmd
sudo cp build/bin/Release/ocvsmd-cli /usr/local/bin/ocvsmd-cli
```
- Installing the Init Script:
```bash
Expand Down
40 changes: 40 additions & 0 deletions include/ocvsmd/sdk/daemon.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#ifndef OCVSMD_SDK_DAEMON_HPP_INCLUDED
#define OCVSMD_SDK_DAEMON_HPP_INCLUDED

#include <memory>

namespace ocvsmd
{
namespace sdk
{

/// An abstract factory for the specialized interfaces.
///
class Daemon
{
public:
static std::unique_ptr<Daemon> make();

Daemon(Daemon&&) = delete;
Daemon(const Daemon&) = delete;
Daemon& operator=(Daemon&&) = delete;
Daemon& operator=(const Daemon&) = delete;

virtual ~Daemon() = default;

virtual void send_messages() const = 0;

protected:
Daemon() = default;

}; // Daemon

} // namespace sdk
} // namespace ocvsmd

#endif // OCVSMD_SDK_DAEMON_HPP_INCLUDED
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ cmake_minimum_required(VERSION 3.27)

add_subdirectory(common)
add_subdirectory(daemon)
add_subdirectory(sdk)
add_subdirectory(cli)
10 changes: 10 additions & 0 deletions src/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@
#

cmake_minimum_required(VERSION 3.27)

add_executable(ocvsmd-cli
main.cpp
)
target_link_libraries(ocvsmd-cli
PUBLIC ocvsmd_sdk
)
add_dependencies(ocvsmd-cli
ocvsmd
)
19 changes: 19 additions & 0 deletions src/cli/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#include <ocvsmd/sdk/daemon.hpp>

int main(const int argc, const char** const argv)
{
(void) argc;
(void) argv;

if (auto daemon = ocvsmd::sdk::Daemon::make())
{
daemon->send_messages();
}

return 0;
}
12 changes: 12 additions & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,15 @@
#

cmake_minimum_required(VERSION 3.27)

add_library(ocvsmd_common
ipc/unix_socket_client.cpp
ipc/unix_socket_server.cpp
)
target_include_directories(ocvsmd_common
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
)
target_include_directories(ocvsmd_common SYSTEM
PUBLIC ${submodules_dir}/cetl/include
PUBLIC ${submodules_dir}/libcyphal/include
)
116 changes: 116 additions & 0 deletions src/common/ipc/unix_socket_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#include "unix_socket_client.hpp"

#include "platform/posix_utils.hpp"

#include <cetl/cetl.hpp>

#include <algorithm>
#include <array>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <utility>

namespace ocvsmd
{
namespace common
{
namespace ipc
{

UnixSocketClient::UnixSocketClient(std::string socket_path)
: socket_path_{std::move(socket_path)}
, client_fd_{-1}
{
}

UnixSocketClient::~UnixSocketClient()
{
if (client_fd_ != -1)
{
platform::posixSyscallError([this] {
//
return ::close(client_fd_);
});
}
}

bool UnixSocketClient::connect_to_server()
{
CETL_DEBUG_ASSERT(client_fd_ == -1, "");

if (const auto err = platform::posixSyscallError([this] {
//
return client_fd_ = ::socket(AF_UNIX, SOCK_STREAM, 0);
}))
{
std::cerr << "Failed to create socket: " << ::strerror(err) << "\n";
return false;
}

sockaddr_un addr{};
addr.sun_family = AF_UNIX;
const std::string abstract_socket_path = '\0' + socket_path_;
CETL_DEBUG_ASSERT(abstract_socket_path.size() <= sizeof(addr.sun_path), "");
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay)
std::memcpy(addr.sun_path,
abstract_socket_path.c_str(),
std::min(sizeof(addr.sun_path), abstract_socket_path.size()));

if (const auto err = platform::posixSyscallError([this, &addr, &abstract_socket_path] {
//
return ::connect(client_fd_,
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
reinterpret_cast<const sockaddr*>(&addr),
offsetof(struct sockaddr_un, sun_path) + abstract_socket_path.size());
}))
{
std::cerr << "Failed to connect to server: " << ::strerror(err) << "\n";
return false;
}

return true;
}

void UnixSocketClient::send_message(const std::string& message) const
{
if (const auto err = platform::posixSyscallError([this, &message] {
//
return ::write(client_fd_, message.c_str(), message.size());
}))
{
std::cerr << "Failed to write: " << ::strerror(err) << "\n";
return;
}

constexpr std::size_t buf_size = 256;
std::array<char, buf_size> buffer{};
ssize_t bytes_read = 0;
if (const auto err = platform::posixSyscallError([this, &bytes_read, &buffer] {
//
return bytes_read = ::read(client_fd_, buffer.data(), buffer.size() - 1);
}))
{
std::cerr << "Failed to read: " << ::strerror(err) << "\n";
return;
}
if (bytes_read > 0)
{
buffer[bytes_read] = '\0'; // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)
std::cout << "Received: " << buffer.data() << "\n";
}
}

} // namespace ipc
} // namespace common
} // namespace ocvsmd
43 changes: 43 additions & 0 deletions src/common/ipc/unix_socket_client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#ifndef OCVSMD_COMMON_IPC_UNIX_SOCKET_CLIENT_HPP_INCLUDED
#define OCVSMD_COMMON_IPC_UNIX_SOCKET_CLIENT_HPP_INCLUDED

#include <string>

namespace ocvsmd
{
namespace common
{
namespace ipc
{

class UnixSocketClient final
{
public:
explicit UnixSocketClient(std::string socket_path);

UnixSocketClient(UnixSocketClient&&) = delete;
UnixSocketClient(const UnixSocketClient&) = delete;
UnixSocketClient& operator=(UnixSocketClient&&) = delete;
UnixSocketClient& operator=(const UnixSocketClient&) = delete;

~UnixSocketClient();

bool connect_to_server();
void send_message(const std::string& message) const;

private:
std::string socket_path_;
int client_fd_;

}; // UnixSocketClient

} // namespace ipc
} // namespace common
} // namespace ocvsmd

#endif // OCVSMD_COMMON_IPC_UNIX_SOCKET_CLIENT_HPP_INCLUDED
Loading

0 comments on commit 94fb76d

Please sign in to comment.