Skip to content

Commit

Permalink
added first draft of Unix socket IPC client/server
Browse files Browse the repository at this point in the history
  • Loading branch information
serges147 committed Dec 19, 2024
1 parent 873161b commit a19e4e9
Show file tree
Hide file tree
Showing 15 changed files with 374 additions and 19 deletions.
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
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
PRIVATE ocvsmd_common
)
add_dependencies(ocvsmd-cli
ocvsmd
)
23 changes: 23 additions & 0 deletions src/cli/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#include "ipc/unix_socket_client.hpp"

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

ocvsmd::common::ipc::UnixSocketClient client{"/var/run/ocvsmd/local.sock"};

if (!client.connect_to_server())
{
return 1;
}

client.send_message("Hello, world!");

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
)
78 changes: 78 additions & 0 deletions src/common/ipc/unix_socket_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: MIT
//

#include "unix_socket_client.hpp"

#include <cerrno>
#include <cstring>
#include <iostream>
#include <string>
#include <sys/socket.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)
{
::close(client_fd_);
}
}

bool UnixSocketClient::connect_to_server()
{
client_fd_ = ::socket(AF_UNIX, SOCK_STREAM, 0);
if (client_fd_ == -1)
{
std::cerr << "Failed to create socket: " << ::strerror(errno) << "\n";
return false;
}

sockaddr_un addr{};
addr.sun_family = AF_UNIX;
::strncpy(addr.sun_path, socket_path_.c_str(), sizeof(addr.sun_path) - 1);

if (::connect(client_fd_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
{
std::cerr << "Failed to connect to server: " << ::strerror(errno) << "\n";
return false;
}

return true;
}

void UnixSocketClient::send_message(const std::string& message)
{
if (::write(client_fd_, message.c_str(), message.size()) == -1)
{
std::cerr << "Failed to send message: " << ::strerror(errno) << "\n";
}

char buffer[256];
ssize_t bytes_read = ::read(client_fd_, buffer, sizeof(buffer) - 1);
if (bytes_read > 0)
{
buffer[bytes_read] = '\0';
std::cout << "Received: " << buffer << "\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);

private:
std::string socket_path_;
int client_fd_;

}; // UnixSocketClient

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

#endif // OCVSMD_COMMON_IPC_UNIX_SOCKET_CLIENT_HPP_INCLUDED
116 changes: 116 additions & 0 deletions src/common/ipc/unix_socket_server.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_server.hpp"

#include "platform/posix_executor_extension.hpp"

#include <cetl/cetl.hpp>
#include <cetl/rtti.hpp>
#include <libcyphal/executor.hpp>

#include <cerrno>
#include <cstring>
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <utility>

namespace ocvsmd
{
namespace common
{
namespace ipc
{
UnixSocketServer::UnixSocketServer(libcyphal::IExecutor& executor, std::string socket_path)
: executor_{executor}
, socket_path_{std::move(socket_path)}
, server_fd_{-1}
{
}

UnixSocketServer::~UnixSocketServer()
{
if (server_fd_ != -1)
{
::close(server_fd_);
::unlink(socket_path_.c_str());
}
}

bool UnixSocketServer::start()
{
server_fd_ = ::socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd_ == -1)
{
std::cerr << "Failed to create socket: " << ::strerror(errno) << "\n";
return false;
}

sockaddr_un addr{};
addr.sun_family = AF_UNIX;
::strncpy(addr.sun_path, socket_path_.c_str(), sizeof(addr.sun_path) - 1);
::unlink(socket_path_.c_str());

if (::bind(server_fd_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
{
std::cerr << "Failed to bind socket: " << ::strerror(errno) << "\n";
return false;
}

if (::listen(server_fd_, 5) == -1)
{
std::cerr << "Failed to listen on socket: " << ::strerror(errno) << "\n";
return false;
}

return true;
}

void UnixSocketServer::accept()
{
int client_fd = ::accept(server_fd_, nullptr, nullptr);
if (client_fd == -1)
{
std::cerr << "Failed to accept connection: " << ::strerror(errno) << "\n";
return;
}

handle_client(client_fd);
::close(client_fd);
}

void UnixSocketServer::handle_client(int client_fd)
{
char buffer[256];
ssize_t bytes_read = ::read(client_fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0)
{
buffer[bytes_read] = '\0';
std::cout << "Received: " << buffer << "\n";
::write(client_fd, buffer, bytes_read); // Echo back
}
}

CETL_NODISCARD libcyphal::IExecutor::Callback::Any UnixSocketServer::registerListenCallback(
libcyphal::IExecutor::Callback::Function&& function) const
{
auto* const posix_executor_ext = cetl::rtti_cast<platform::IPosixExecutorExtension*>(&executor_);
if (nullptr == posix_executor_ext)
{
return {};
}

CETL_DEBUG_ASSERT(udp_handle_.fd >= 0, "");
return posix_executor_ext->registerAwaitableCallback( //
std::move(function),
platform::IPosixExecutorExtension::Trigger::Readable{server_fd_});
}

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

#ifndef OCVSMD_COMMON_IPC_UNIX_SOCKET_SERVER_HPP_INCLUDED
#define OCVSMD_COMMON_IPC_UNIX_SOCKET_SERVER_HPP_INCLUDED

#include <cetl/cetl.hpp>
#include <libcyphal/executor.hpp>

#include <string>

namespace ocvsmd
{
namespace common
{
namespace ipc
{

class UnixSocketServer final
{
public:
UnixSocketServer(libcyphal::IExecutor& executor, std::string socket_path);

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

~UnixSocketServer();

bool start();

CETL_NODISCARD libcyphal::IExecutor::Callback::Any registerListenCallback(
libcyphal::IExecutor::Callback::Function&& function) const;

void accept();

private:
void handle_client(int client_fd);

libcyphal::IExecutor& executor_;
std::string socket_path_;
int server_fd_;

}; // UnixSocketServer

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

#endif // OCVSMD_COMMON_IPC_UNIX_SOCKET_SERVER_HPP_INCLUDED
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// SPDX-License-Identifier: MIT
//

#ifndef OCVSMD_DAEMON_ENGINE_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED
#define OCVSMD_DAEMON_ENGINE_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED
#ifndef OCVSMD_COMMON_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED
#define OCVSMD_COMMON_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED

#include <cetl/cetl.hpp>
#include <cetl/pf17/cetlpf.hpp>
Expand All @@ -13,9 +13,7 @@

namespace ocvsmd
{
namespace daemon
{
namespace engine
namespace common
{
namespace platform
{
Expand Down Expand Up @@ -65,8 +63,7 @@ class IPosixExecutorExtension
}; // IPosixExecutorExtension

} // namespace platform
} // namespace engine
} // namespace daemon
} // namespace common
} // namespace ocvsmd

#endif // OCVSMD_DAEMON_ENGINE_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED
#endif // OCVSMD_COMMON_PLATFORM_POSIX_EXECUTOR_EXTENSION_HPP_INCLUDED
Loading

0 comments on commit a19e4e9

Please sign in to comment.