blob: b82c1ebe2d3a705fda9dcfdd59a6df27af587b5c [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: {
137 const struct sctp_stream_change_event *sce =
138 &snp->sn_strchange_event;
139 LOG(INFO) << " SCTP_STREAM_CHANGE_EVENT";
140 VLOG(1) << "\t\t(stream_change_event: flags=" << sce->strchange_flags
141 << ", assoc_id=" << sce->strchange_assoc_id
142 << ", instrms=" << sce->strchange_instrms
143 << ", outstrms=" << sce->strchange_outstrms << " )";
144 } break;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800145 case SCTP_SHUTDOWN_EVENT: {
146 LOG(INFO) << " SCTP_SHUTDOWN_EVENT";
147 } break;
148 default:
149 LOG(INFO) << " Unknown type: " << snp->sn_header.sn_type;
150 break;
151 }
152}
153
154std::string GetHostname() {
155 char buf[256];
156 buf[sizeof(buf) - 1] = '\0';
157 PCHECK(gethostname(buf, sizeof(buf) - 1) == 0);
158 return buf;
159}
160
161std::string Message::PeerAddress() const { return Address(sin); }
162
163void LogSctpStatus(int fd, sctp_assoc_t assoc_id) {
164 struct sctp_status status;
165 memset(&status, 0, sizeof(status));
166 status.sstat_assoc_id = assoc_id;
167
168 socklen_t size = sizeof(status);
169 PCHECK(getsockopt(fd, SOL_SCTP, SCTP_STATUS,
170 reinterpret_cast<void *>(&status), &size) == 0);
171
172 LOG(INFO) << "sctp_status) sstat_assoc_id:" << status.sstat_assoc_id
173 << " sstat_state:" << status.sstat_state
174 << " sstat_rwnd:" << status.sstat_rwnd
175 << " sstat_unackdata:" << status.sstat_unackdata
176 << " sstat_penddata:" << status.sstat_penddata
177 << " sstat_instrms:" << status.sstat_instrms
178 << " sstat_outstrms:" << status.sstat_outstrms
179 << " sstat_fragmentation_point:" << status.sstat_fragmentation_point
180 << " sstat_primary.spinfo_srtt:" << status.sstat_primary.spinfo_srtt
181 << " sstat_primary.spinfo_rto:" << status.sstat_primary.spinfo_rto;
182}
183
184aos::unique_c_ptr<Message> ReadSctpMessage(int fd, int max_size) {
185 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
186 struct iovec iov;
187 struct msghdr inmessage;
188
189 memset(&inmessage, 0, sizeof(struct msghdr));
190
191 aos::unique_c_ptr<Message> result(
Austin Schuh7bc59052020-02-16 23:48:33 -0800192 reinterpret_cast<Message *>(malloc(sizeof(Message) + max_size + 1)));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800193
Austin Schuh7bc59052020-02-16 23:48:33 -0800194 iov.iov_len = max_size + 1;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800195 iov.iov_base = result->mutable_data();
196
197 inmessage.msg_iov = &iov;
198 inmessage.msg_iovlen = 1;
199
200 inmessage.msg_control = incmsg;
201 inmessage.msg_controllen = sizeof(incmsg);
202
203 inmessage.msg_namelen = sizeof(struct sockaddr_storage);
204 inmessage.msg_name = &result->sin;
205
206 ssize_t size;
207 PCHECK((size = recvmsg(fd, &inmessage, 0)) > 0);
208
209 result->size = size;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800210 if ((MSG_NOTIFICATION & inmessage.msg_flags)) {
211 result->message_type = Message::kNotification;
212 } else {
213 result->message_type = Message::kMessage;
214 }
215
216 for (struct cmsghdr *scmsg = CMSG_FIRSTHDR(&inmessage); scmsg != NULL;
217 scmsg = CMSG_NXTHDR(&inmessage, scmsg)) {
218 switch (scmsg->cmsg_type) {
219 case SCTP_RCVINFO: {
220 struct sctp_rcvinfo *data = (struct sctp_rcvinfo *)CMSG_DATA(scmsg);
221 result->header.rcvinfo = *data;
222 } break;
223 default:
224 LOG(INFO) << "\tUnknown type: " << scmsg->cmsg_type;
225 break;
226 }
227 }
228
Austin Schuh2fe4b712020-03-15 14:21:45 -0700229 CHECK_LE(size, max_size) << ": Message overflowed buffer on stream "
230 << result->header.rcvinfo.rcv_sid << ".";
231
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800232 return result;
233}
234
235void Message::LogRcvInfo() const {
236 LOG(INFO) << "\tSNDRCV (stream=" << header.rcvinfo.rcv_sid
237 << " ssn=" << header.rcvinfo.rcv_ssn
238 << " tsn=" << header.rcvinfo.rcv_tsn << " flags=0x" << std::hex
239 << header.rcvinfo.rcv_flags << std::dec
240 << " ppid=" << header.rcvinfo.rcv_ppid
241 << " cumtsn=" << header.rcvinfo.rcv_cumtsn << ")";
242}
243
Austin Schuh2fe4b712020-03-15 14:21:45 -0700244size_t ReadRMemMax() {
245 struct stat current_stat;
246 if (stat("/proc/sys/net/core/rmem_max", &current_stat) != -1) {
247 return static_cast<size_t>(
248 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/rmem_max")));
249 } else {
250 LOG(WARNING) << "/proc/sys/net/core/rmem_max doesn't exist. Are you in a "
251 "container?";
252 return 212992;
253 }
254}
255
256size_t ReadWMemMax() {
257 struct stat current_stat;
258 if (stat("/proc/sys/net/core/wmem_max", &current_stat) != -1) {
259 return static_cast<size_t>(
260 std::stoi(util::ReadFileToStringOrDie("/proc/sys/net/core/wmem_max")));
261 } else {
262 LOG(WARNING) << "/proc/sys/net/core/wmem_max doesn't exist. Are you in a "
263 "container?";
264 return 212992;
265 }
266}
267
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800268} // namespace message_bridge
269} // namespace aos