Skip to content

Iox #27 client port implementation and test part 2 #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3140e35
iox-#27 Add UML documentation for client and server service discovery
elBoberido Jun 23, 2021
07c0aa9
iox-#27 Add CaPro messages for request-response
elBoberido Jun 23, 2021
d5d666f
iox-#27 Implement ClientPortRouDi
elBoberido Jun 23, 2021
3e0a2f0
iox-#27 Use reference instead of not_null and update documentation
elBoberido Jun 24, 2021
d16c368
iox-#27 Test setup and initial tests for client port
elBoberido Jun 24, 2021
ed4c7a9
iox-#27 Fix typo and add U suffix
elBoberido Jun 28, 2021
23b1188
iox-#27 Add skeletons for ClientPortUserTests
elBoberido Jun 28, 2021
d1e8770
iox-#27 Simplify the service discovery for the client
elBoberido Jul 1, 2021
41ba185
iox-#27 Adjust client state machine according to new design
elBoberido Jul 1, 2021
26c3695
iox-#27 Make it more conveniet to output a CaproMessageType as string
elBoberido Jul 1, 2021
de1efff
iox-#27 Make it more conveniet to output a ConnectionState as string
elBoberido Jul 1, 2021
2c54884
iox-#27 Add missing return in switch
elBoberido Jul 1, 2021
a2d4b10
iox-#27 Make a bunch of tests pass
elBoberido Jul 1, 2021
2c21ef3
iox-#27 Make another bunch of tests pass
elBoberido Jul 2, 2021
eeebd96
iox-#27 Make condition variable related tests work
elBoberido Jul 2, 2021
242dfca
iox-#27 Finish ClientPortUser tests
elBoberido Jul 2, 2021
e6ef2fe
iox-#27 Rework ClientPortUser death test
elBoberido Jul 2, 2021
9516bfc
iox-#27 Implement stream operator for Error enum
elBoberido Jul 2, 2021
818a4a5
iox-#27 Check for nullptr access
elBoberido Jul 2, 2021
20e34c9
iox-#27 Fix build for ubuntu 16.04
elBoberido Jul 2, 2021
58b1474
iox-#27 Update copyright
elBoberido Jul 5, 2021
9317487
iox-#27 Code reuse in tests
elBoberido Jul 5, 2021
a2e43ba
iox-#27 Put all port related classes into a common struct
elBoberido Jul 6, 2021
c3710a1
iox-#27 Initial ClientPortRouDi tests
elBoberido Jul 6, 2021
86d7010
iox-#27 Add note regargint ClientPort thread safety
elBoberido Jul 6, 2021
64107a1
iox-#27 Add test for valid state transitions
elBoberido Jul 6, 2021
91db7a4
iox-#27 Add test for invalid state transitions
elBoberido Jul 6, 2021
5b0cd5b
iox-#27 Add option to set the LogLevel for the current scope
elBoberido Jul 6, 2021
44d3f64
iox-#27 Turn off logger for tests with invalid transitions
elBoberido Jul 6, 2021
2af5101
iox-#27 Fix typo
elBoberido Jul 12, 2021
41885ec
iox-#27 Fix typo and update copyright
elBoberido Jul 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
@startuml

== Client tries to connect (Server not present) ==

PortManager -> ClientPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::CONNECT

PortManager -> PortManager ++ : sendToAllMatchingServerPorts

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::NACK)
return cxx::nullopt

return

...

== Server offers service (Client not present) ==

PortManager -> ServerPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::OFFER

PortManager -> PortManager ++ : sendToAllMatchingClientPorts

return

...

== Client tries to connect (Server preset) ==

PortManager -> ClientPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::CONNECT

PortManager -> PortManager ++ : sendToAllMatchingServerPorts

PortManager -> ServerPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::CONNECT)
return CaproMessageType::OFFER

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::OFFER)
return CaproMessageType::HANDSHAKE

PortManager -> ServerPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::HANDSHAKE)
return CaproMessageType::ACK

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::ACK)
return cxx::nullopt

return

...

== Server offers service (Client present) ==

PortManager -> ServerPortRouDi ++ : tryGetCaProMessage
return CaproMessageType::OFFER

PortManager -> PortManager ++ : sendToAllMatchingClientPorts

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::OFFER)
return CaproMessageType::HANDSHAKE

PortManager -> ServerPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::HANDSHAKE)
return CaproMessageType::ACK

PortManager -> ClientPortRouDi ++ : dispatchCaProMessageAndGetPossibleResponse(CaproMessageType::ACK)
return cxx::nullopt

return

...

@enduml
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/design/diagrams/request_response/client_port.puml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class ClientPortUser {
}

class ClientPortRouDi {
getResponseQueueFullPolicy: QueueFullPolicy
tryGetCaProMessage(): optional<CaProMessage>
dispatchCaProMessageAndGetPossibleResponse(caProMessage: const CaProMessage): optional<CaProMessage>
releaseAllChunks(): void
Expand Down
12 changes: 6 additions & 6 deletions doc/design/diagrams/request_response/client_port.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions doc/design/diagrams/request_response/client_state_machine.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@startuml

[*] -down-> NOT_CONNECTED

NOT_CONNECTED -left-> NOT_CONNECTED : OFFER
NOT_CONNECTED -right-> CONNECT_REQUESTED : CONNECT

CONNECT_REQUESTED -left-> NOT_CONNECTED : DISCONNECT
CONNECT_REQUESTED -right-> CONNECT_REQUESTED : NACK
CONNECT_REQUESTED -down-> CONNECT_HANDSHAKE : OFFER

CONNECT_HANDSHAKE -left-> CONNECTED : ACK
CONNECT_HANDSHAKE -up-> CONNECT_REQUESTED : NACK

CONNECTED -up-> DISCONNECT_REQUESTED : DISCONNECT
CONNECTED -up-> CONNECT_REQUESTED : STOP_OFFER

DISCONNECT_REQUESTED -up--> NOT_CONNECTED : ACK/NACK

@enduml
12 changes: 12 additions & 0 deletions doc/design/diagrams/request_response/client_state_machine.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions doc/design/request_response_communication.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,21 @@ A client can ask a server to block if its response queue is full.
The server will obey if the corresponding `clientTooSlowPolicy` is set to `ConsumerTooSlowPolicy::WAIT_FOR_CONSUMER`.
If the options don't match, the client will not be connected to the server, similar to the behavior of publisher and subscriber.

#### Client Service Discovery
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To view this with rendered diagrams use the three dots on the right and select View file


The client is guided by the following state machine.

![client state machine](diagrams/request_response/client_state_machine.svg)

Contrary to the subscriber state machine, the client doesn't pass it's response queue with the `CONNECT` CaPro message but with the `HANDSHAKE` message.
The server will pass its request queue with the `OFFER` CaPro message.
This is done to have the same state transitions for the case when the server is already present
as well as when the server offers its service after the client initially tried to connect.

Following is a sequence diagram which shows all this cases

![client and server service discovery](diagrams/request_response/client_and_server_service_discovery.svg)

### Code example

## Open issues
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ inline void Iceoryx2DDSGateway<channel_t, gateway_t>::loadConfiguration(const co
template <typename channel_t, typename gateway_t>
inline void Iceoryx2DDSGateway<channel_t, gateway_t>::discover(const capro::CaproMessage& msg) noexcept
{
LogDebug() << "[Iceoryx2DDSGateway] <CaproMessage> "
<< capro::CaproMessageTypeString[static_cast<uint8_t>(msg.m_type)]
LogDebug() << "[Iceoryx2DDSGateway] <CaproMessage> " << capro::caproMessageTypeString(msg.m_type)
<< " { Service: " << msg.m_serviceDescription.getServiceIDString()
<< ", Instance: " << msg.m_serviceDescription.getInstanceIDString()
<< ", Event: " << msg.m_serviceDescription.getEventIDString() << " }";
Expand Down
4 changes: 2 additions & 2 deletions iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ enum class ConnectionState : uint32_t
{
NOT_CONNECTED = 0,
CONNECT_REQUESTED,
CONNECT_HANDSHAKE,
CONNECTED,
DISCONNECT_REQUESTED,
WAIT_FOR_OFFER
DISCONNECT_REQUESTED
};

// Default properties of ChunkDistributorData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ enum class CaproMessageType : uint8_t
STOP_OFFER,
SUB,
UNSUB,
CONNECT,
DISCONNECT,
HANDSHAKE,
ACK,
NACK,
PUB,
Expand All @@ -42,10 +45,7 @@ enum class CaproMessageType : uint8_t
MESSGAGE_TYPE_END
};

constexpr int32_t MAX_ENUM_STRING_SIZE = 64;
constexpr char CaproMessageTypeString[][MAX_ENUM_STRING_SIZE] = {
"NOTYPE", "FIND", "OFFER", "STOP_OFFER", "SUB", "UNSUB", "ACK", "NACK", "PUB", "REQ", "RES", "PING", "PONG"};

inline constexpr const char* caproMessageTypeString(CaproMessageType messageType) noexcept;

enum class CaproMessageSubType : uint8_t
{
Expand Down Expand Up @@ -83,4 +83,6 @@ class CaproMessage
} // namespace capro
} // namespace iox

#include "iceoryx_posh/internal/capro/capro_message.inl"

#endif // IOX_POSH_CAPRO_CAPRO_MESSAGE_HPP
66 changes: 66 additions & 0 deletions iceoryx_posh/include/iceoryx_posh/internal/capro/capro_message.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0


namespace iox
{
namespace capro
{
inline constexpr const char* caproMessageTypeString(CaproMessageType messageType) noexcept
{
switch (messageType)
{
case CaproMessageType::NOTYPE:
return "NOTYPE";
case CaproMessageType::FIND:
return "FIND";
case CaproMessageType::OFFER:
return "OFFER";
case CaproMessageType::STOP_OFFER:
return "STOP_OFFER";
case CaproMessageType::SUB:
return "SUB";
case CaproMessageType::UNSUB:
return "UNSUB";
case CaproMessageType::CONNECT:
return "CONNECT";
case CaproMessageType::DISCONNECT:
return "DISCONNECT";
case CaproMessageType::HANDSHAKE:
return "HANDSHAKE";
case CaproMessageType::ACK:
return "ACK";
case CaproMessageType::NACK:
return "NACK";
case CaproMessageType::PUB:
return "PUB";
case CaproMessageType::REQ:
return "REQ";
case CaproMessageType::RES:
return "RES";
case CaproMessageType::PING:
return "PING";
case CaproMessageType::PONG:
return "PONG";
case CaproMessageType::MESSGAGE_TYPE_END:
return "MESSGAGE_TYPE_END";
}

return "UNKNOWN_TYPE";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this into the switch case as default and you will earn a MISRA badge ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving this into default would mean we might miss a new message added to the enum. Without a default case, the compiler will complain. There is still the return after the switch, in order to catch errors when a dummy enum value was provided. In this case, it's clear that MISRA is for C type enums and not enum class from C++

Copy link
Contributor

@mossmaurice mossmaurice Jun 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, can you please double check the Axivion scan with our custom AUTOSAR ruleset?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahem, let's assume I'm a new contributor ... how would I do that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is describe in the CONTRIBUTING.md: Friendly ping one of the maintainers to get access to the dashboard ;)

@dkroenke will probably give everyone some heads-up before this goes live with every PR in a couple of weeks. I'd appreciate if you give it a try for this PR :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can find the config files with all the rules in here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mossmaurice according to dkroenke the dashboard currently only works with the master branch. We currently use this pattern (no default but return statement) in several places already, e.g. https://github.com/eclipse-iceoryx/iceoryx/blob/master/iceoryx_posh/source/popo/trigger.cpp#L32-L41.
Furthermore it is semantically the same as with the default case when all enum tags are handled and compiles down to the exact same assembly with the benefit of a compile time error instead of a silent fallback to default when the enum is extended.

Assuming our current rule set doesn't allow this, we need to change it anyway since it doesn't make sense and results in bad code where errors need to be catched by tests instead of the compiler.

}

} // namespace capro
} // namespace iox
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,20 @@ class ClientPortRouDi : public BasePort
public:
using MemberType_t = ClientPortData;

explicit ClientPortRouDi(cxx::not_null<MemberType_t* const> clientPortDataPtr) noexcept;
/// @brief Creates a ClientPortRouDi from ClientPortData which are shared with ClientPortUser
/// @param[in] clientPortData to be are accessed by the ClientPortRouDi interface
explicit ClientPortRouDi(MemberType_t& clientPortData) noexcept;

ClientPortRouDi(const ClientPortRouDi& other) = delete;
ClientPortRouDi& operator=(const ClientPortRouDi&) = delete;
ClientPortRouDi(ClientPortRouDi&& rhs) = default;
ClientPortRouDi& operator=(ClientPortRouDi&& rhs) = default;
~ClientPortRouDi() = default;

/// @brief Access to the configured responseQueueFullPolicy
/// @return the configured responseQueueFullPolicy
QueueFullPolicy2 getResponseQueueFullPolicy() const noexcept;

/// @brief get an optional CaPro message that requests changes to the desired connection state of the client
/// @return CaPro message with desired connection state, empty optional if no state change
cxx::optional<capro::CaproMessage> tryGetCaProMessage() noexcept;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class ClientPortUser : public BasePort
public:
using MemberType_t = ClientPortData;

/// @brief Creates a ClientPortUser from ClientPortData which are shared with ClientPortRouDi
/// @param[in] clientPortData to be are accessed by the ClientPortUser interface
explicit ClientPortUser(MemberType_t& clientPortData) noexcept;

ClientPortUser(const ClientPortUser& other) = delete;
Expand Down
Loading