blob: 0d319245187a90666aba63d9fc98b0bec30d0f8a [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
183aos::unique_c_ptr<Message> ReadSctpMessage(int fd, int max_size) {
184 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
185 struct iovec iov;
186 struct msghdr inmessage;
187
188 memset(&inmessage, 0, sizeof(struct msghdr));
189
190 aos::unique_c_ptr<Message> result(
Austin Schuh7bc59052020-02-16 23:48:33 -0800191 reinterpret_cast<Message *>(malloc(sizeof(Message) + max_size + 1)));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800192
Austin Schuh7bc59052020-02-16 23:48:33 -0800193 iov.iov_len = max_size + 1;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800194 iov.iov_base = result->mutable_data();
195
196 inmessage.msg_iov = &iov;
197 inmessage.msg_iovlen = 1;
198
199 inmessage.msg_control = incmsg;
200 inmessage.msg_controllen = sizeof(incmsg);
201
202 inmessage.msg_namelen = sizeof(struct sockaddr_storage);
203 inmessage.msg_name = &result->sin;
204
205 ssize_t size;
206 PCHECK((size = recvmsg(fd, &inmessage, 0)) > 0);
207
208 result->size = size;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800209 if ((MSG_NOTIFICATION & inmessage.msg_flags)) {
210 result->message_type = Message::kNotification;
211 } else {
212 result->message_type = Message::kMessage;
213 }
214
215 for (struct cmsghdr *scmsg = CMSG_FIRSTHDR(&inmessage); scmsg != NULL;
216 scmsg = CMSG_NXTHDR(&inmessage, scmsg)) {
217 switch (scmsg->cmsg_type) {
218 case SCTP_RCVINFO: {
219 struct sctp_rcvinfo *data = (struct sctp_rcvinfo *)CMSG_DATA(scmsg);
220 result->header.rcvinfo = *data;
221 } break;
222 default:
223 LOG(INFO) << "\tUnknown type: " << scmsg->cmsg_type;
224 break;
225 }
226 }
227
Austin Schuh2fe4b712020-03-15 14:21:45 -0700228 CHECK_LE(size, max_size) << ": Message overflowed buffer on stream "
229 << result->header.rcvinfo.rcv_sid << ".";
230
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800231 return result;
232}
233
234void Message::LogRcvInfo() const {
235 LOG(INFO) << "\tSNDRCV (stream=" << header.rcvinfo.rcv_sid
236 << " ssn=" << header.rcvinfo.rcv_ssn
237 << " tsn=" << header.rcvinfo.rcv_tsn << " flags=0x" << std::hex
238 << header.rcvinfo.rcv_flags << std::dec
239 << " ppid=" << header.rcvinfo.rcv_ppid
240 << " cumtsn=" << header.rcvinfo.rcv_cumtsn << ")";
241}
242
Austin Schuh2fe4b712020-03-15 14:21:45 -0700243size_t ReadRMemMax() {
244 struct stat current_stat;
245 if (stat("/proc/sys/net/core/rmem_max", &current_stat) != -1) {
246 return static_cast<size_t>(
247 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/rmem_max")));
248 } else {
249 LOG(WARNING) << "/proc/sys/net/core/rmem_max doesn't exist. Are you in a "
250 "container?";
251 return 212992;
252 }
253}
254
255size_t ReadWMemMax() {
256 struct stat current_stat;
257 if (stat("/proc/sys/net/core/wmem_max", &current_stat) != -1) {
258 return static_cast<size_t>(
259 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/wmem_max")));
260 } else {
261 LOG(WARNING) << "/proc/sys/net/core/wmem_max doesn't exist. Are you in a "
262 "container?";
263 return 212992;
264 }
265}
266
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800267} // namespace message_bridge
268} // namespace aos