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