1 // Copyright 2021 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 18 #include "pw_function/function.h" 19 #include "pw_rpc/client.h" 20 #include "pw_status/status.h" 21 22 namespace pw::rpc::integration_test { 23 24 // The RPC channel for integration test RPCs. 25 inline constexpr uint32_t kChannelId = 1; 26 27 // An injectable pipe interface that may manipulate packets before they're sent 28 // to the final destination. 29 // 30 // ``ChannelManipulator``s allow application-specific packet handling to be 31 // injected into the packet processing pipeline for an ingress or egress 32 // channel-like pathway. This is particularly useful for integration testing 33 // resilience to things like packet loss on a usually-reliable transport. RPC 34 // server integrations may provide an opportunity to inject a 35 // ``ChannelManipulator`` for this use case. 36 // 37 // A ``ChannelManipulator`` should not set send_packet_, as the consumer of a 38 // ``ChannelManipulator`` will use ``send_packet`` to insert the provided 39 // ``ChannelManipulator`` into a packet processing path. 40 class ChannelManipulator { 41 public: 42 // The expected function signature of the send callback used by a 43 // ChannelManipulator to forward packets to the final destination. 44 // 45 // The only argument is a byte span containing the RPC packet that should 46 // be sent. 47 // 48 // Returns: 49 // OK - Packet successfully sent. 50 // Other - Failed to send packet. 51 using SendCallback = Function<Status(span<const std::byte>)>; 52 ChannelManipulator()53 ChannelManipulator() 54 : send_packet_( 55 [](span<const std::byte>) { return Status::Unimplemented(); }) {} ~ChannelManipulator()56 virtual ~ChannelManipulator() {} 57 58 // Sets the true send callback that a ChannelManipulator will use to forward 59 // packets to the final destination. 60 // 61 // This should not be used by a ChannelManipulator. The consumer of a 62 // ChannelManipulator will set the send callback. set_send_packet(SendCallback && send)63 void set_send_packet(SendCallback&& send) { send_packet_ = std::move(send); } 64 65 // Processes an incoming packet before optionally sending it. 66 // 67 // Implementations of this method may send the processed packet, multiple 68 // packets, or no packets at all via the registered `send_packet()` 69 // handler. 70 virtual Status ProcessAndSend(span<const std::byte> packet) = 0; 71 72 protected: send_packet(span<const std::byte> payload)73 Status send_packet(span<const std::byte> payload) { 74 return send_packet_(payload); 75 } 76 77 private: 78 Function<Status(span<const std::byte>)> send_packet_; 79 }; 80 81 void SetEgressChannelManipulator(ChannelManipulator* new_channel_manipulator); 82 83 void SetIngressChannelManipulator(ChannelManipulator* new_channel_manipulator); 84 85 // Returns the global RPC client for integration test use. 86 Client& client(); 87 88 // Configure options for the socket associated with the client. 89 int SetClientSockOpt(int level, 90 int optname, 91 const void* optval, 92 unsigned int optlen); 93 94 // Initializes logging and the global RPC client for integration testing. Starts 95 // a background thread that processes incoming. 96 Status InitializeClient(int argc, 97 char* argv[], 98 const char* usage_args = "PORT"); 99 100 Status InitializeClient(int port); 101 102 // Terminates the client, joining the RPC dispatch thread. 103 void TerminateClient(); 104 105 } // namespace pw::rpc::integration_test 106