Skip to content

Commit

Permalink
feat: add is_opened flag to socket base class (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
domire8 authored Oct 6, 2023
1 parent e32f3b2 commit d0c5ef7
Show file tree
Hide file tree
Showing 37 changed files with 352 additions and 137 deletions.
22 changes: 22 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "network interfaces",
"remoteUser": "ros2",
"build": {
"dockerfile": "../Dockerfile",
"context": "..",
"target": "development",
"args": {
"ROS2_VERSION": "iron"
}
},
"workspaceMount": "source=${localWorkspaceFolder},target=/home/ros2/.devcontainer,type=bind,consistency=cached",
"workspaceFolder": "/home/ros2/.devcontainer",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools-extension-pack",
"eamodio.gitlens"
]
}
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.idea
*cmake-build-debug*
build/
15 changes: 15 additions & 0 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "AMD",
"includePath": [
"/home/ros2/.devcontainer/source/communication_interfaces/include/**"
],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "gnu++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cmake.sourceDirectory": "/home/ros2/.devcontainer/source/communication_interfaces",
"cmake.configureArgs": [ "-DBUILD_TESTING=ON" ],
"C_Cpp.clang_format_style": "file:/home/ros2/.clang-format"
}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Release Versions:
- [0.2.0](#020)
- [0.1.0](#010)

## Upcoming changes (in development)

- feat: add is_opened flag to socket base class (#68)

## 2.0.1

Version 2.0.1 contains a hotfix that enables socket communiction with any serialized message in Python, which was not
Expand Down
25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ respectively.
#### Implementing a derived socket class

To use this class, create a subclass that inherits from it and implement its pure virtual functions. The pure virtual
functions are `open()`, `receive_bytes(std::string&)`, and `send_bytes(const std::string&)`.
functions are `on_open()`, `on_receive_bytes(std::string&)`, and `on_send_bytes(const std::string&)`.

Configuration parameters should be passed with a configuration struct, resulting in a single argument constructor.

The `close()` function can optionally be overridden to perform steps to disconnect and close the socket communication.
If a derived class defines any cleanup behavior in `close()`, it should also be invoked statically and explicitly
The `on_close()` function can optionally be overridden to perform steps to disconnect and close the socket communication.
If a derived class defines any cleanup behavior in `on_close()`, it should also be invoked statically and explicitly
in the destructor of the derived class.

An example is given below.
Expand All @@ -45,13 +45,14 @@ public:

~DerivedSocket() override;

void open() override;
private:
void on_open() override;

bool receive_bytes(std::string& buffer) override;
bool on_receive_bytes(std::string& buffer) override;

bool send_bytes(const std::string& buffer) override;
bool on_send_bytes(const std::string& buffer) override;

void close() override;
void on_close() override;
}
```
Expand All @@ -62,24 +63,24 @@ DerivedSocket::DerivedSocket(DerivedSocketConfig configuraiton) {
}
DerivedSocket::~DerivedSocket() {
DerivedSocket::close();
DerivedSocket::on_close();
}
void DerivedSocket::open() {
void DerivedSocket::on_open() {
// Configure and open the socket
}
bool DerivedSocket::receive_bytes(std::string& buffer) {
bool DerivedSocket::on_receive_bytes(std::string& buffer) {
// Read the contents of the socket into the buffer and return true on success. Otherwise, return false.
return true;
}
bool DerivedSocket::send_bytes(const std::string& buffer) {
bool DerivedSocket::on_send_bytes(const std::string& buffer) {
// Write the contents of the buffer onto the socket and return true on success. Otherwise, return false.
return true;
}
void DerivedSocket::close() {
void DerivedSocket::on_close() {
// Perform clean-up steps here
}
```
Expand Down
16 changes: 8 additions & 8 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ ROS2_VERSION=humble

HELP_MESSAGE="Usage: build.sh [options]
Options:
--test Target the test layer to run the tests.
--test Target the test layer to run the tests.
--ros2-version <VERSION> Specify the version of ROS 2 to use.
(default: $ROS2_VERSION)
--ros2-version <VERSION> Specify the version of ROS 2 to use.
(default: $ROS2_VERSION)
-v|--verbose Set the build output to verbose.
-v|--verbose Set the build output to verbose.
--cache-id <id> Invalidate the mount cache (e.g. CMake build folder)
by providing a new value.
--cache-id <id> Invalidate the mount cache (e.g. CMake build folder)
by providing a new value.
-r|--no-cache Invalidate all cache (layer + mount).
-r|--no-cache Invalidate all cache (layer + mount).
-h|--help Show this help message.
-h|--help Show this help message.
"

TEST=0
Expand Down
15 changes: 1 addition & 14 deletions python/src/communication_interfaces_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,6 @@

using namespace communication_interfaces;

class PySocket : public sockets::ISocket, public std::enable_shared_from_this<PySocket> {
public:
using sockets::ISocket::ISocket;

void open() override { PYBIND11_OVERRIDE_PURE(void, ISocket, open, ); }

bool receive_bytes(std::string& buffer) override { PYBIND11_OVERRIDE_PURE(bool, ISocket, receive_bytes, buffer); }

bool send_bytes(const std::string& buffer) override { PYBIND11_OVERRIDE_PURE(bool, ISocket, send_bytes, buffer); }

void close() override { PYBIND11_OVERRIDE(void, ISocket, close, ); }
};

PYBIND11_MODULE(communication_interfaces, m) {
m.doc() = "Python bindings for communication interfaces";

Expand All @@ -36,7 +23,7 @@ PYBIND11_MODULE(communication_interfaces, m) {

auto m_sub_sock = m.def_submodule("sockets", "Submodule for communication interfaces sockets");

py::class_<sockets::ISocket, std::shared_ptr<sockets::ISocket>, PySocket>(m_sub_sock, "ISocket")
py::class_<sockets::ISocket, std::shared_ptr<sockets::ISocket>>(m_sub_sock, "ISocket")
.def("open", &sockets::ISocket::open, "Perform configuration steps to open the socket for communication")
.def(
"receive_bytes",
Expand Down
25 changes: 25 additions & 0 deletions python/test/test_tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest
import time

from communication_interfaces.exceptions import SocketConfigurationError
from communication_interfaces.sockets import TCPClientConfiguration, TCPClient, TCPServerConfiguration, TCPServer


Expand Down Expand Up @@ -29,3 +30,27 @@ def test_comm(self):
response = self.client.receive_bytes()
assert response
assert response.decode("utf-8").rstrip("\x00") == self.server_message

buffer = ""
self.server.close()
with pytest.raises(SocketConfigurationError):
self.server.receive_bytes()
with pytest.raises(SocketConfigurationError):
self.server.send_bytes(buffer)
self.client.close()
with pytest.raises(SocketConfigurationError):
self.client.receive_bytes()
with pytest.raises(SocketConfigurationError):
self.client.send_bytes(buffer)

def test_not_open(self):
buffer = ""
with pytest.raises(SocketConfigurationError):
self.server.receive_bytes()
with pytest.raises(SocketConfigurationError):
self.server.send_bytes(buffer)

with pytest.raises(SocketConfigurationError):
self.client.receive_bytes()
with pytest.raises(SocketConfigurationError):
self.client.send_bytes(buffer)
33 changes: 30 additions & 3 deletions python/test/test_udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,35 @@ def test_port_reuse(udp_config, server):
server2.open()


def test_open_close(server):
def test_open_close(udp_config):
buffer = ""
udp_config.timeout_duration_sec = 0.5
server = UDPServer(udp_config)
with pytest.raises(SocketConfigurationError):
server.send_bytes(buffer)
with pytest.raises(SocketConfigurationError):
server.receive_bytes()
server.open()
server.close()
assert server.send_bytes("test")
assert not server.receive_bytes()

assert not server.send_bytes("")
server.close()
with pytest.raises(SocketConfigurationError):
server.send_bytes(buffer)
with pytest.raises(SocketConfigurationError):
server.receive_bytes()

client = UDPClient(udp_config)
with pytest.raises(SocketConfigurationError):
client.send_bytes(buffer)
with pytest.raises(SocketConfigurationError):
client.receive_bytes()
client.open()
assert client.send_bytes("test")
assert not client.receive_bytes()

client.close()
with pytest.raises(SocketConfigurationError):
client.send_bytes(buffer)
with pytest.raises(SocketConfigurationError):
client.receive_bytes()
16 changes: 16 additions & 0 deletions python/test/test_zmq.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
import time

from communication_interfaces.exceptions import SocketConfigurationError
from communication_interfaces.sockets import ZMQContext, ZMQSocketConfiguration, ZMQPublisher, ZMQSubscriber, \
ZMQCombinedSocketsConfiguration, ZMQPublisherSubscriber

Expand Down Expand Up @@ -71,3 +72,18 @@ def test_send_receive_combined(zmq_context):

server.close()
client.close()


def test_open_close(zmq_config):
buffer = ""
socket = ZMQPublisher(zmq_config)
with pytest.raises(SocketConfigurationError):
socket.send_bytes(buffer)
with pytest.raises(SocketConfigurationError):
socket.receive_bytes()

socket.open()
assert socket.send_bytes("test")
socket.close()
with pytest.raises(SocketConfigurationError):
socket.send_bytes(buffer)
1 change: 1 addition & 0 deletions source/communication_interfaces/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ if (NOT cppzmq_POPULATED)
endif()

add_library(${PROJECT_NAME} SHARED
${PROJECT_SOURCE_DIR}/src/sockets/ISocket.cpp
${PROJECT_SOURCE_DIR}/src/sockets/UDPSocket.cpp
${PROJECT_SOURCE_DIR}/src/sockets/UDPClient.cpp
${PROJECT_SOURCE_DIR}/src/sockets/UDPServer.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <string>

#include "communication_interfaces/exceptions/SocketConfigurationException.hpp"

namespace communication_interfaces::sockets {

/**
Expand All @@ -23,25 +25,56 @@ class ISocket {
* @brief Perform configuration steps to open the socket for communication
* @throws SocketConfigurationException if opening fails
*/
virtual void open() = 0;
void open();

/**
* @brief Receive bytes from the socket
* @param buffer The buffer to fill with the received bytes
* @return True if bytes were received, false otherwise
* @throws SocketConfigurationException if socket has not been opened yet
*/
virtual bool receive_bytes(std::string& buffer) = 0;
bool receive_bytes(std::string& buffer);

/**
* @brief Send bytes to the socket
* @param buffer The buffer with the bytes to send
* @return True if bytes were sent, false otherwise
* @throws SocketConfigurationException if socket has not been opened yet
*/
virtual bool send_bytes(const std::string& buffer) = 0;
bool send_bytes(const std::string& buffer);

/**
* @brief Perform steps to disconnect and close the socket communication
*/
virtual void close() {}
void close();

protected:
/**
* @brief Perform configuration steps to open the socket for communication
* @throws SocketConfigurationException if opening fails
*/
virtual void on_open() = 0;

/**
* @brief Receive bytes from the socket
* @param buffer The buffer to fill with the received bytes
* @return True if bytes were received, false otherwise
*/
virtual bool on_receive_bytes(std::string& buffer) = 0;

/**
* @brief Send bytes to the socket
* @param buffer The buffer with the bytes to send
* @return True if bytes were sent, false otherwise
*/
virtual bool on_send_bytes(const std::string& buffer) = 0;

/**
* @brief Perform steps to disconnect and close the socket communication
*/
virtual void on_close() {};

private:
bool opened_ = false;
};
}// namespace communication_interfaces::sockets
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ class TCPClient : public TCPSocket {
*/
explicit TCPClient(TCPClientConfiguration configuration);

private:
/**
* @copydoc ISocket::open()
* @copydoc ISocket::on_open()
* @details Connect the client socket to the server
*/
void open() override;
void on_open() override;

private:
TCPClientConfiguration config_; ///< Socket configuration struct
};
} // namespace communication_interfaces::sockets
Loading

0 comments on commit d0c5ef7

Please sign in to comment.