blob: 97d9d20e4de78bc454c7f693cc9785be1465c66e [file] [log] [blame]
Austin Schuhe84c3ed2019-12-14 15:29:48 -08001#ifndef AOS_NETWORK_SCTP_LIB_H_
2#define AOS_NETWORK_SCTP_LIB_H_
3
4#include <arpa/inet.h>
Adam Snaiderbe263512023-05-18 20:40:23 -07005#include <linux/sctp.h>
Adam Snaider96a0f4b2023-05-18 20:41:19 -07006#include <linux/version.h>
Austin Schuhe84c3ed2019-12-14 15:29:48 -08007
8#include <memory>
Austin Schuh507f7582021-07-31 20:39:55 -07009#include <optional>
Austin Schuhe84c3ed2019-12-14 15:29:48 -080010#include <string>
11#include <string_view>
Austin Schuha705d782021-07-31 20:40:00 -070012#include <vector>
Austin Schuhe84c3ed2019-12-14 15:29:48 -080013
Austin Schuh99f7c6a2024-06-25 22:07:44 -070014#include "absl/log/check.h"
15#include "absl/log/log.h"
Adam Snaider9bb33442023-06-26 16:31:37 -070016#include "absl/types/span.h"
Austin Schuhe84c3ed2019-12-14 15:29:48 -080017
Philipp Schrader790cb542023-07-05 21:06:52 -070018#include "aos/unique_malloc_ptr.h"
19
Adam Snaider96a0f4b2023-05-18 20:41:19 -070020#define HAS_SCTP_AUTH LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
21
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080022namespace aos::message_bridge {
Austin Schuhe84c3ed2019-12-14 15:29:48 -080023
Adam Snaider9bb33442023-06-26 16:31:37 -070024constexpr bool HasSctpAuth() { return HAS_SCTP_AUTH; }
25
Austin Schuh0a0a8272021-12-08 13:19:32 -080026// Check if ipv6 is enabled.
27// If we don't try IPv6, and omit AI_ADDRCONFIG when resolving addresses, the
28// library will happily resolve nodes to IPv6 IPs that can't be used. If we add
29// AI_ADDRCONFIG, the unit tests no longer work because they only have loopback
30// addresses available.
31bool Ipv6Enabled();
32
Austin Schuhe84c3ed2019-12-14 15:29:48 -080033// Resolves a socket and returns the address. This can be either an ipv4 or
34// ipv6 address.
Austin Schuh0a0a8272021-12-08 13:19:32 -080035struct sockaddr_storage ResolveSocket(std::string_view host, int port,
36 bool use_ipv6);
Austin Schuhe84c3ed2019-12-14 15:29:48 -080037
38// Returns a formatted version of the address.
39std::string Address(const struct sockaddr_storage &sockaddr);
40// Returns a formatted version of the address family.
41std::string_view Family(const struct sockaddr_storage &sockaddr);
42
43// Message received.
44// This message is malloced bigger than needed and the extra space after it is
45// the data.
46struct Message {
47 // Struct to let us force data to be well aligned.
48 struct OveralignedChar {
49 uint8_t data alignas(32);
50 };
51
52 // Headers.
53 struct {
54 struct sctp_rcvinfo rcvinfo;
55 } header;
56
57 // Address of the sender.
58 struct sockaddr_storage sin;
59
60 // Data type. Is it a block of data, or is it a struct sctp_notification?
Austin Schuh89f23e32023-05-15 17:06:43 -070061 enum MessageType {
62 // Block of data?
63 kMessage,
64 // struct sctp_notification?
65 kNotification,
66 // Client sent too large a message and was disconnected.
67 kOverflow,
68 } message_type;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080069
70 size_t size = 0u;
71 uint8_t *mutable_data() {
72 return reinterpret_cast<uint8_t *>(&actual_data[0].data);
73 }
74 const uint8_t *data() const {
75 return reinterpret_cast<const uint8_t *>(&actual_data[0].data);
76 }
77
Austin Schuhc4202572021-03-31 21:06:55 -070078 uint32_t partial_deliveries = 0;
79
Austin Schuhe84c3ed2019-12-14 15:29:48 -080080 // Returns a human readable peer IP address.
81 std::string PeerAddress() const;
82
83 // Prints out the RcvInfo structure.
84 void LogRcvInfo() const;
85
86 // The start of the data.
87 OveralignedChar actual_data[];
88};
89
90void PrintNotification(const Message *msg);
91
92std::string GetHostname();
93
94// Gets and logs the contents of the sctp_status message.
95void LogSctpStatus(int fd, sctp_assoc_t assoc_id);
96
Adam Snaider9bb33442023-06-26 16:31:37 -070097// Authentication method used for the SCTP socket.
98enum class SctpAuthMethod {
99 // Use unauthenticated sockets.
100 kNoAuth,
101 // Use RFC4895 authentication for SCTP.
102 kAuth,
103};
104
Austin Schuh507f7582021-07-31 20:39:55 -0700105// Manages reading and writing SCTP messages.
106class SctpReadWrite {
107 public:
Adam Snaider9bb33442023-06-26 16:31:37 -0700108 // When `requested_authentication` is kAuth, it will use SCTP authentication
109 // if it's provided by the kernel. Note that this will ignore the value of
110 // `requested_authentication` if the kernel is too old and will fall back to
111 // an unauthenticated channel.
112 SctpReadWrite(
113 SctpAuthMethod requested_authentication = SctpAuthMethod::kNoAuth)
114 : sctp_authentication_(HasSctpAuth() ? requested_authentication ==
115 SctpAuthMethod::kAuth
116 : false) {
117 LOG_IF(WARNING,
118 requested_authentication == SctpAuthMethod::kAuth && !HasSctpAuth())
119 << "SCTP authentication requested but not provided by the kernel... "
120 "You may need a newer kernel";
121 }
Austin Schuh507f7582021-07-31 20:39:55 -0700122 ~SctpReadWrite() { CloseSocket(); }
123
124 // Opens a new socket.
125 void OpenSocket(const struct sockaddr_storage &sockaddr_local);
126
127 // Sends a message to the kernel.
128 // Returns true for success. Will not send a partial message on failure.
129 bool SendMessage(int stream, std::string_view data, int time_to_live,
130 std::optional<struct sockaddr_storage> sockaddr_remote,
131 sctp_assoc_t snd_assoc_id);
132
133 // Reads from the kernel until a complete message is received or it blocks.
134 // Returns nullptr if the kernel blocks before returning a complete message.
135 aos::unique_c_ptr<Message> ReadMessage();
136
Sarah Newman80e955e2022-04-13 11:19:36 -0700137 // Send an abort message for the given association.
138 bool Abort(sctp_assoc_t snd_assoc_id);
139
Austin Schuh507f7582021-07-31 20:39:55 -0700140 int fd() const { return fd_; }
141
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700142 void SetMaxReadSize(size_t max_size) {
Austin Schuha705d782021-07-31 20:40:00 -0700143 CHECK(partial_messages_.empty())
144 << ": May not update size with queued fragments because we do not "
145 "track individual message sizes";
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700146 max_read_size_ = max_size;
147 if (fd_ != -1) {
148 DoSetMaxSize();
149 }
150 }
151
152 void SetMaxWriteSize(size_t max_size) {
153 CHECK(partial_messages_.empty())
154 << ": May not update size with queued fragments because we do not "
155 "track individual message sizes";
156 max_write_size_ = max_size;
Austin Schuh507f7582021-07-31 20:39:55 -0700157 if (fd_ != -1) {
158 DoSetMaxSize();
159 }
160 }
161
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700162 // Returns a message returned from ReadMessage back to the pool.
163 void FreeMessage(aos::unique_c_ptr<Message> &&message);
164
165 // Allocates messages for the pool. SetMaxSize must be set first.
166 void SetPoolSize(size_t pool_size);
167
Adam Snaider9bb33442023-06-26 16:31:37 -0700168 // Set the active authentication key to `auth_key`.
169 void SetAuthKey(absl::Span<const uint8_t> auth_key);
170
Austin Schuh507f7582021-07-31 20:39:55 -0700171 private:
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700172 aos::unique_c_ptr<Message> AcquireMessage();
173
Austin Schuh507f7582021-07-31 20:39:55 -0700174 void CloseSocket();
175 void DoSetMaxSize();
176
Austin Schuha705d782021-07-31 20:40:00 -0700177 // Examines a notification message for ones we handle here.
178 // Returns true if the notification was handled by this class.
179 bool ProcessNotification(const Message *message);
180
Austin Schuh507f7582021-07-31 20:39:55 -0700181 int fd_ = -1;
182
183 // We use this as a unique identifier that just increments for each message.
184 uint32_t send_ppid_ = 0;
185
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700186 size_t max_read_size_ = 1000;
187 size_t max_write_size_ = 1000;
Austin Schuha705d782021-07-31 20:40:00 -0700188
189 std::vector<aos::unique_c_ptr<Message>> partial_messages_;
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700190
191 bool use_pool_ = false;
192 std::vector<aos::unique_c_ptr<Message>> free_messages_;
Adam Snaider96a0f4b2023-05-18 20:41:19 -0700193
Adam Snaider9bb33442023-06-26 16:31:37 -0700194 // Use SCTP authentication (RFC4895).
195 bool sctp_authentication_;
196 std::vector<uint8_t> current_key_;
Austin Schuh507f7582021-07-31 20:39:55 -0700197};
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800198
Austin Schuh2fe4b712020-03-15 14:21:45 -0700199// Returns the max network buffer available for reading for a socket.
200size_t ReadRMemMax();
201// Returns the max network buffer available for writing for a socket.
202size_t ReadWMemMax();
203
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800204} // namespace aos::message_bridge
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800205
206#endif // AOS_NETWORK_SCTP_LIB_H_