blob: f78934af10d87860333fb975cdc61e2fea26d7f4 [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 Schuhe84c3ed2019-12-14 15:29:48 -080014#include "gflags/gflags.h"
15#include "glog/logging.h"
16
Philipp Schrader790cb542023-07-05 21:06:52 -070017#include "aos/unique_malloc_ptr.h"
18
Adam Snaider96a0f4b2023-05-18 20:41:19 -070019#define HAS_SCTP_AUTH LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
20
Austin Schuhe84c3ed2019-12-14 15:29:48 -080021namespace aos {
22namespace message_bridge {
23
Austin Schuh0a0a8272021-12-08 13:19:32 -080024// Check if ipv6 is enabled.
25// If we don't try IPv6, and omit AI_ADDRCONFIG when resolving addresses, the
26// library will happily resolve nodes to IPv6 IPs that can't be used. If we add
27// AI_ADDRCONFIG, the unit tests no longer work because they only have loopback
28// addresses available.
29bool Ipv6Enabled();
30
Austin Schuhe84c3ed2019-12-14 15:29:48 -080031// Resolves a socket and returns the address. This can be either an ipv4 or
32// ipv6 address.
Austin Schuh0a0a8272021-12-08 13:19:32 -080033struct sockaddr_storage ResolveSocket(std::string_view host, int port,
34 bool use_ipv6);
Austin Schuhe84c3ed2019-12-14 15:29:48 -080035
36// Returns a formatted version of the address.
37std::string Address(const struct sockaddr_storage &sockaddr);
38// Returns a formatted version of the address family.
39std::string_view Family(const struct sockaddr_storage &sockaddr);
40
41// Message received.
42// This message is malloced bigger than needed and the extra space after it is
43// the data.
44struct Message {
45 // Struct to let us force data to be well aligned.
46 struct OveralignedChar {
47 uint8_t data alignas(32);
48 };
49
50 // Headers.
51 struct {
52 struct sctp_rcvinfo rcvinfo;
53 } header;
54
55 // Address of the sender.
56 struct sockaddr_storage sin;
57
58 // Data type. Is it a block of data, or is it a struct sctp_notification?
Austin Schuh89f23e32023-05-15 17:06:43 -070059 enum MessageType {
60 // Block of data?
61 kMessage,
62 // struct sctp_notification?
63 kNotification,
64 // Client sent too large a message and was disconnected.
65 kOverflow,
66 } message_type;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080067
68 size_t size = 0u;
69 uint8_t *mutable_data() {
70 return reinterpret_cast<uint8_t *>(&actual_data[0].data);
71 }
72 const uint8_t *data() const {
73 return reinterpret_cast<const uint8_t *>(&actual_data[0].data);
74 }
75
Austin Schuhc4202572021-03-31 21:06:55 -070076 uint32_t partial_deliveries = 0;
77
Austin Schuhe84c3ed2019-12-14 15:29:48 -080078 // Returns a human readable peer IP address.
79 std::string PeerAddress() const;
80
81 // Prints out the RcvInfo structure.
82 void LogRcvInfo() const;
83
84 // The start of the data.
85 OveralignedChar actual_data[];
86};
87
88void PrintNotification(const Message *msg);
89
90std::string GetHostname();
91
92// Gets and logs the contents of the sctp_status message.
93void LogSctpStatus(int fd, sctp_assoc_t assoc_id);
94
Austin Schuh507f7582021-07-31 20:39:55 -070095// Manages reading and writing SCTP messages.
96class SctpReadWrite {
97 public:
Adam Snaider96a0f4b2023-05-18 20:41:19 -070098 SctpReadWrite(std::vector<uint8_t> auth_key = {});
Austin Schuh507f7582021-07-31 20:39:55 -070099 ~SctpReadWrite() { CloseSocket(); }
100
101 // Opens a new socket.
102 void OpenSocket(const struct sockaddr_storage &sockaddr_local);
103
104 // Sends a message to the kernel.
105 // Returns true for success. Will not send a partial message on failure.
106 bool SendMessage(int stream, std::string_view data, int time_to_live,
107 std::optional<struct sockaddr_storage> sockaddr_remote,
108 sctp_assoc_t snd_assoc_id);
109
110 // Reads from the kernel until a complete message is received or it blocks.
111 // Returns nullptr if the kernel blocks before returning a complete message.
112 aos::unique_c_ptr<Message> ReadMessage();
113
Sarah Newman80e955e2022-04-13 11:19:36 -0700114 // Send an abort message for the given association.
115 bool Abort(sctp_assoc_t snd_assoc_id);
116
Austin Schuh507f7582021-07-31 20:39:55 -0700117 int fd() const { return fd_; }
118
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700119 void SetMaxReadSize(size_t max_size) {
Austin Schuha705d782021-07-31 20:40:00 -0700120 CHECK(partial_messages_.empty())
121 << ": May not update size with queued fragments because we do not "
122 "track individual message sizes";
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700123 max_read_size_ = max_size;
124 if (fd_ != -1) {
125 DoSetMaxSize();
126 }
127 }
128
129 void SetMaxWriteSize(size_t max_size) {
130 CHECK(partial_messages_.empty())
131 << ": May not update size with queued fragments because we do not "
132 "track individual message sizes";
133 max_write_size_ = max_size;
Austin Schuh507f7582021-07-31 20:39:55 -0700134 if (fd_ != -1) {
135 DoSetMaxSize();
136 }
137 }
138
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700139 // Returns a message returned from ReadMessage back to the pool.
140 void FreeMessage(aos::unique_c_ptr<Message> &&message);
141
142 // Allocates messages for the pool. SetMaxSize must be set first.
143 void SetPoolSize(size_t pool_size);
144
Austin Schuh507f7582021-07-31 20:39:55 -0700145 private:
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700146 aos::unique_c_ptr<Message> AcquireMessage();
147
Austin Schuh507f7582021-07-31 20:39:55 -0700148 void CloseSocket();
149 void DoSetMaxSize();
150
Austin Schuha705d782021-07-31 20:40:00 -0700151 // Examines a notification message for ones we handle here.
152 // Returns true if the notification was handled by this class.
153 bool ProcessNotification(const Message *message);
154
Austin Schuh507f7582021-07-31 20:39:55 -0700155 int fd_ = -1;
156
157 // We use this as a unique identifier that just increments for each message.
158 uint32_t send_ppid_ = 0;
159
Austin Schuh89e1e9c2023-05-15 14:38:44 -0700160 size_t max_read_size_ = 1000;
161 size_t max_write_size_ = 1000;
Austin Schuha705d782021-07-31 20:40:00 -0700162
163 std::vector<aos::unique_c_ptr<Message>> partial_messages_;
Austin Schuhf95a6ab2023-05-15 14:34:57 -0700164
165 bool use_pool_ = false;
166 std::vector<aos::unique_c_ptr<Message>> free_messages_;
Adam Snaider96a0f4b2023-05-18 20:41:19 -0700167
168 std::vector<uint8_t> auth_key_;
Austin Schuh507f7582021-07-31 20:39:55 -0700169};
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800170
Austin Schuh2fe4b712020-03-15 14:21:45 -0700171// Returns the max network buffer available for reading for a socket.
172size_t ReadRMemMax();
173// Returns the max network buffer available for writing for a socket.
174size_t ReadWMemMax();
175
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800176} // namespace message_bridge
177} // namespace aos
178
179#endif // AOS_NETWORK_SCTP_LIB_H_