blob: b52285195085b714f13e86845f33dc2c077fbac6 [file] [log] [blame]
Austin Schuhe84c3ed2019-12-14 15:29:48 -08001#include "aos/network/sctp_lib.h"
2
3#include <arpa/inet.h>
4#include <net/if.h>
5#include <netdb.h>
6#include <netinet/sctp.h>
Austin Schuh2fe4b712020-03-15 14:21:45 -07007#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
Austin Schuhe84c3ed2019-12-14 15:29:48 -080010
11#include <string_view>
12
Austin Schuh2fe4b712020-03-15 14:21:45 -070013#include "aos/util/file.h"
14
Austin Schuhe84c3ed2019-12-14 15:29:48 -080015DEFINE_string(interface, "", "ipv6 interface");
16
17namespace aos {
18namespace message_bridge {
19
20namespace {
21const char *sac_state_tbl[] = {"COMMUNICATION_UP", "COMMUNICATION_LOST",
22 "RESTART", "SHUTDOWN_COMPLETE",
23 "CANT_START_ASSOCICATION"};
24
25typedef union {
26 struct sctp_initmsg init;
27 struct sctp_sndrcvinfo sndrcvinfo;
28} _sctp_cmsg_data_t;
29
30} // namespace
31
32struct sockaddr_storage ResolveSocket(std::string_view host, int port) {
33 struct sockaddr_storage result;
34 struct addrinfo *addrinfo_result;
35 struct sockaddr_in *t_addr = (struct sockaddr_in *)&result;
36 struct sockaddr_in6 *t_addr6 = (struct sockaddr_in6 *)&result;
37
Austin Schuh6d227942020-02-22 13:29:57 -080038 PCHECK(getaddrinfo(std::string(host).c_str(), 0, NULL, &addrinfo_result) == 0)
39 << ": Failed to look up " << host;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080040
41 switch (addrinfo_result->ai_family) {
42 case AF_INET:
43 memcpy(t_addr, addrinfo_result->ai_addr, addrinfo_result->ai_addrlen);
44 t_addr->sin_family = addrinfo_result->ai_family;
45 t_addr->sin_port = htons(port);
46
47 break;
48 case AF_INET6:
49 memcpy(t_addr6, addrinfo_result->ai_addr, addrinfo_result->ai_addrlen);
50 t_addr6->sin6_family = addrinfo_result->ai_family;
51 t_addr6->sin6_port = htons(port);
52
53 if (FLAGS_interface.size() > 0) {
54 t_addr6->sin6_scope_id = if_nametoindex(FLAGS_interface.c_str());
55 }
56
57 break;
58 }
59
60 // Now print it back out nicely.
61 char host_string[NI_MAXHOST];
62 char service_string[NI_MAXSERV];
63
64 int error = getnameinfo((struct sockaddr *)&result,
65 addrinfo_result->ai_addrlen, host_string, NI_MAXHOST,
66 service_string, NI_MAXSERV, NI_NUMERICHOST);
67
68 if (error) {
69 LOG(ERROR) << "Reverse lookup failed ... " << gai_strerror(error);
70 }
71
72 LOG(INFO) << "remote:addr=" << host_string << ", port=" << service_string
73 << ", family=" << addrinfo_result->ai_family;
74
75 freeaddrinfo(addrinfo_result);
76
77 return result;
78}
79
80std::string_view Family(const struct sockaddr_storage &sockaddr) {
81 if (sockaddr.ss_family == AF_INET) {
82 return "AF_INET";
83 } else if (sockaddr.ss_family == AF_INET6) {
84 return "AF_INET6";
85 } else {
86 return "unknown";
87 }
88}
89std::string Address(const struct sockaddr_storage &sockaddr) {
90 char addrbuf[INET6_ADDRSTRLEN];
91 if (sockaddr.ss_family == AF_INET) {
92 const struct sockaddr_in *sin = (const struct sockaddr_in *)&sockaddr;
93 return std::string(
94 inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN));
95 } else {
96 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)&sockaddr;
97 return std::string(
98 inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN));
99 }
100}
101
102void PrintNotification(const Message *msg) {
103 const union sctp_notification *snp =
104 (const union sctp_notification *)msg->data();
105
106 LOG(INFO) << "Notification:";
107
108 switch (snp->sn_header.sn_type) {
109 case SCTP_ASSOC_CHANGE: {
110 const struct sctp_assoc_change *sac = &snp->sn_assoc_change;
111 LOG(INFO) << "SCTP_ASSOC_CHANGE(" << sac_state_tbl[sac->sac_state] << ")";
112 VLOG(1) << " (assoc_change: state=" << sac->sac_state
113 << ", error=" << sac->sac_error
114 << ", instr=" << sac->sac_inbound_streams
115 << " outstr=" << sac->sac_outbound_streams
116 << ", assoc=" << sac->sac_assoc_id << ")";
117 } break;
118 case SCTP_PEER_ADDR_CHANGE: {
119 const struct sctp_paddr_change *spc = &snp->sn_paddr_change;
120 LOG(INFO) << " SlCTP_PEER_ADDR_CHANGE";
121 VLOG(1) << "\t\t(peer_addr_change: " << Address(spc->spc_aaddr)
122 << " state=" << spc->spc_state << ", error=" << spc->spc_error
123 << ")";
124 } break;
125 case SCTP_SEND_FAILED: {
126 const struct sctp_send_failed *ssf = &snp->sn_send_failed;
127 LOG(INFO) << " SCTP_SEND_FAILED";
128 VLOG(1) << "\t\t(sendfailed: len=" << ssf->ssf_length
129 << " err=" << ssf->ssf_error << ")";
130 } break;
131 case SCTP_REMOTE_ERROR: {
132 const struct sctp_remote_error *sre = &snp->sn_remote_error;
133 LOG(INFO) << " SCTP_REMOTE_ERROR";
134 VLOG(1) << "\t\t(remote_error: err=" << ntohs(sre->sre_error) << ")";
135 } break;
Austin Schuhf7777002020-09-01 18:41:28 -0700136 case SCTP_STREAM_CHANGE_EVENT: {
Austin Schuh62a0c272021-03-31 21:04:53 -0700137 const struct sctp_stream_change_event *sce = &snp->sn_strchange_event;
Austin Schuhf7777002020-09-01 18:41:28 -0700138 LOG(INFO) << " SCTP_STREAM_CHANGE_EVENT";
139 VLOG(1) << "\t\t(stream_change_event: flags=" << sce->strchange_flags
140 << ", assoc_id=" << sce->strchange_assoc_id
141 << ", instrms=" << sce->strchange_instrms
142 << ", outstrms=" << sce->strchange_outstrms << " )";
143 } break;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800144 case SCTP_SHUTDOWN_EVENT: {
145 LOG(INFO) << " SCTP_SHUTDOWN_EVENT";
146 } break;
147 default:
148 LOG(INFO) << " Unknown type: " << snp->sn_header.sn_type;
149 break;
150 }
151}
152
153std::string GetHostname() {
154 char buf[256];
155 buf[sizeof(buf) - 1] = '\0';
156 PCHECK(gethostname(buf, sizeof(buf) - 1) == 0);
157 return buf;
158}
159
160std::string Message::PeerAddress() const { return Address(sin); }
161
162void LogSctpStatus(int fd, sctp_assoc_t assoc_id) {
163 struct sctp_status status;
164 memset(&status, 0, sizeof(status));
165 status.sstat_assoc_id = assoc_id;
166
167 socklen_t size = sizeof(status);
168 PCHECK(getsockopt(fd, SOL_SCTP, SCTP_STATUS,
169 reinterpret_cast<void *>(&status), &size) == 0);
170
171 LOG(INFO) << "sctp_status) sstat_assoc_id:" << status.sstat_assoc_id
172 << " sstat_state:" << status.sstat_state
173 << " sstat_rwnd:" << status.sstat_rwnd
174 << " sstat_unackdata:" << status.sstat_unackdata
175 << " sstat_penddata:" << status.sstat_penddata
176 << " sstat_instrms:" << status.sstat_instrms
177 << " sstat_outstrms:" << status.sstat_outstrms
178 << " sstat_fragmentation_point:" << status.sstat_fragmentation_point
179 << " sstat_primary.spinfo_srtt:" << status.sstat_primary.spinfo_srtt
180 << " sstat_primary.spinfo_rto:" << status.sstat_primary.spinfo_rto;
181}
182
Austin Schuhc4202572021-03-31 21:06:55 -0700183aos::unique_c_ptr<Message> ReadSctpMessage(int fd, size_t max_size) {
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800184 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
185 struct iovec iov;
186 struct msghdr inmessage;
187
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800188 aos::unique_c_ptr<Message> result(
Austin Schuh7bc59052020-02-16 23:48:33 -0800189 reinterpret_cast<Message *>(malloc(sizeof(Message) + max_size + 1)));
Austin Schuhc4202572021-03-31 21:06:55 -0700190 result->size = 0;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800191
Austin Schuhc4202572021-03-31 21:06:55 -0700192 int count = 0;
193 int last_flags = 0;
194 for (count = 0; !(last_flags & MSG_EOR); count++) {
195 memset(&inmessage, 0, sizeof(struct msghdr));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800196
Austin Schuhc4202572021-03-31 21:06:55 -0700197 iov.iov_len = max_size + 1 - result->size;
198 iov.iov_base = result->mutable_data() + result->size;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800199
Austin Schuhc4202572021-03-31 21:06:55 -0700200 inmessage.msg_iov = &iov;
201 inmessage.msg_iovlen = 1;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800202
Austin Schuhc4202572021-03-31 21:06:55 -0700203 inmessage.msg_control = incmsg;
204 inmessage.msg_controllen = sizeof(incmsg);
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800205
Austin Schuhc4202572021-03-31 21:06:55 -0700206 inmessage.msg_namelen = sizeof(struct sockaddr_storage);
207 inmessage.msg_name = &result->sin;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800208
Austin Schuhc4202572021-03-31 21:06:55 -0700209 ssize_t size;
210 PCHECK((size = recvmsg(fd, &inmessage, 0)) > 0);
211
212 if (count > 0) {
213 VLOG(1) << "Count: " << count;
214 VLOG(1) << "Last msg_flags: " << last_flags;
215 VLOG(1) << "msg_flags: " << inmessage.msg_flags;
216 VLOG(1) << "Current size: " << result->size;
217 VLOG(1) << "Received size: " << size;
218 CHECK_EQ(MSG_NOTIFICATION & inmessage.msg_flags, MSG_NOTIFICATION & last_flags);
219 }
220
221 result->size += size;
222 last_flags = inmessage.msg_flags;
223
224 for (struct cmsghdr *scmsg = CMSG_FIRSTHDR(&inmessage); scmsg != NULL;
225 scmsg = CMSG_NXTHDR(&inmessage, scmsg)) {
226 switch (scmsg->cmsg_type) {
227 case SCTP_RCVINFO: {
228 struct sctp_rcvinfo *data = reinterpret_cast<struct sctp_rcvinfo *>(CMSG_DATA(scmsg));
229 if (count > 0) {
230 VLOG(1) << "Got sctp_rcvinfo on continued packet";
231 CHECK_EQ(result->header.rcvinfo.rcv_sid, data->rcv_sid);
232 CHECK_EQ(result->header.rcvinfo.rcv_ssn, data->rcv_ssn);
233 CHECK_EQ(result->header.rcvinfo.rcv_ppid, data->rcv_ppid);
234 CHECK_EQ(result->header.rcvinfo.rcv_assoc_id, data->rcv_assoc_id);
235 }
236 result->header.rcvinfo = *data;
237 } break;
238 default:
239 LOG(INFO) << "\tUnknown type: " << scmsg->cmsg_type;
240 break;
241 }
242 }
243
244 CHECK_NE(inmessage.msg_flags & MSG_CTRUNC, MSG_CTRUNC)
245 << ": Control message truncated.";
246
247 CHECK_LE(result->size, max_size) << ": Message overflowed buffer on stream "
248 << result->header.rcvinfo.rcv_sid << ".";
249 }
250
251 result->partial_deliveries = count - 1;
252 if (count > 1) {
253 VLOG(1) << "Final count: " << count;
254 VLOG(1) << "Final size: " << result->size;
255 }
256
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800257 if ((MSG_NOTIFICATION & inmessage.msg_flags)) {
258 result->message_type = Message::kNotification;
259 } else {
260 result->message_type = Message::kMessage;
261 }
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800262 return result;
263}
264
265void Message::LogRcvInfo() const {
266 LOG(INFO) << "\tSNDRCV (stream=" << header.rcvinfo.rcv_sid
267 << " ssn=" << header.rcvinfo.rcv_ssn
268 << " tsn=" << header.rcvinfo.rcv_tsn << " flags=0x" << std::hex
269 << header.rcvinfo.rcv_flags << std::dec
270 << " ppid=" << header.rcvinfo.rcv_ppid
271 << " cumtsn=" << header.rcvinfo.rcv_cumtsn << ")";
272}
273
Austin Schuh2fe4b712020-03-15 14:21:45 -0700274size_t ReadRMemMax() {
275 struct stat current_stat;
276 if (stat("/proc/sys/net/core/rmem_max", &current_stat) != -1) {
277 return static_cast<size_t>(
278 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/rmem_max")));
279 } else {
280 LOG(WARNING) << "/proc/sys/net/core/rmem_max doesn't exist. Are you in a "
281 "container?";
282 return 212992;
283 }
284}
285
286size_t ReadWMemMax() {
287 struct stat current_stat;
288 if (stat("/proc/sys/net/core/wmem_max", &current_stat) != -1) {
289 return static_cast<size_t>(
290 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/wmem_max")));
291 } else {
292 LOG(WARNING) << "/proc/sys/net/core/wmem_max doesn't exist. Are you in a "
293 "container?";
294 return 212992;
295 }
296}
297
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800298} // namespace message_bridge
299} // namespace aos