blob: 7e32bb43939ef6d753904b112a3f93f0fa005d83 [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>
7
8#include <string_view>
9
10DEFINE_string(interface, "", "ipv6 interface");
11
12namespace aos {
13namespace message_bridge {
14
15namespace {
16const char *sac_state_tbl[] = {"COMMUNICATION_UP", "COMMUNICATION_LOST",
17 "RESTART", "SHUTDOWN_COMPLETE",
18 "CANT_START_ASSOCICATION"};
19
20typedef union {
21 struct sctp_initmsg init;
22 struct sctp_sndrcvinfo sndrcvinfo;
23} _sctp_cmsg_data_t;
24
25} // namespace
26
27struct sockaddr_storage ResolveSocket(std::string_view host, int port) {
28 struct sockaddr_storage result;
29 struct addrinfo *addrinfo_result;
30 struct sockaddr_in *t_addr = (struct sockaddr_in *)&result;
31 struct sockaddr_in6 *t_addr6 = (struct sockaddr_in6 *)&result;
32
Austin Schuh6d227942020-02-22 13:29:57 -080033 PCHECK(getaddrinfo(std::string(host).c_str(), 0, NULL, &addrinfo_result) == 0)
34 << ": Failed to look up " << host;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080035
36 switch (addrinfo_result->ai_family) {
37 case AF_INET:
38 memcpy(t_addr, addrinfo_result->ai_addr, addrinfo_result->ai_addrlen);
39 t_addr->sin_family = addrinfo_result->ai_family;
40 t_addr->sin_port = htons(port);
41
42 break;
43 case AF_INET6:
44 memcpy(t_addr6, addrinfo_result->ai_addr, addrinfo_result->ai_addrlen);
45 t_addr6->sin6_family = addrinfo_result->ai_family;
46 t_addr6->sin6_port = htons(port);
47
48 if (FLAGS_interface.size() > 0) {
49 t_addr6->sin6_scope_id = if_nametoindex(FLAGS_interface.c_str());
50 }
51
52 break;
53 }
54
55 // Now print it back out nicely.
56 char host_string[NI_MAXHOST];
57 char service_string[NI_MAXSERV];
58
59 int error = getnameinfo((struct sockaddr *)&result,
60 addrinfo_result->ai_addrlen, host_string, NI_MAXHOST,
61 service_string, NI_MAXSERV, NI_NUMERICHOST);
62
63 if (error) {
64 LOG(ERROR) << "Reverse lookup failed ... " << gai_strerror(error);
65 }
66
67 LOG(INFO) << "remote:addr=" << host_string << ", port=" << service_string
68 << ", family=" << addrinfo_result->ai_family;
69
70 freeaddrinfo(addrinfo_result);
71
72 return result;
73}
74
75std::string_view Family(const struct sockaddr_storage &sockaddr) {
76 if (sockaddr.ss_family == AF_INET) {
77 return "AF_INET";
78 } else if (sockaddr.ss_family == AF_INET6) {
79 return "AF_INET6";
80 } else {
81 return "unknown";
82 }
83}
84std::string Address(const struct sockaddr_storage &sockaddr) {
85 char addrbuf[INET6_ADDRSTRLEN];
86 if (sockaddr.ss_family == AF_INET) {
87 const struct sockaddr_in *sin = (const struct sockaddr_in *)&sockaddr;
88 return std::string(
89 inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN));
90 } else {
91 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)&sockaddr;
92 return std::string(
93 inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN));
94 }
95}
96
97void PrintNotification(const Message *msg) {
98 const union sctp_notification *snp =
99 (const union sctp_notification *)msg->data();
100
101 LOG(INFO) << "Notification:";
102
103 switch (snp->sn_header.sn_type) {
104 case SCTP_ASSOC_CHANGE: {
105 const struct sctp_assoc_change *sac = &snp->sn_assoc_change;
106 LOG(INFO) << "SCTP_ASSOC_CHANGE(" << sac_state_tbl[sac->sac_state] << ")";
107 VLOG(1) << " (assoc_change: state=" << sac->sac_state
108 << ", error=" << sac->sac_error
109 << ", instr=" << sac->sac_inbound_streams
110 << " outstr=" << sac->sac_outbound_streams
111 << ", assoc=" << sac->sac_assoc_id << ")";
112 } break;
113 case SCTP_PEER_ADDR_CHANGE: {
114 const struct sctp_paddr_change *spc = &snp->sn_paddr_change;
115 LOG(INFO) << " SlCTP_PEER_ADDR_CHANGE";
116 VLOG(1) << "\t\t(peer_addr_change: " << Address(spc->spc_aaddr)
117 << " state=" << spc->spc_state << ", error=" << spc->spc_error
118 << ")";
119 } break;
120 case SCTP_SEND_FAILED: {
121 const struct sctp_send_failed *ssf = &snp->sn_send_failed;
122 LOG(INFO) << " SCTP_SEND_FAILED";
123 VLOG(1) << "\t\t(sendfailed: len=" << ssf->ssf_length
124 << " err=" << ssf->ssf_error << ")";
125 } break;
126 case SCTP_REMOTE_ERROR: {
127 const struct sctp_remote_error *sre = &snp->sn_remote_error;
128 LOG(INFO) << " SCTP_REMOTE_ERROR";
129 VLOG(1) << "\t\t(remote_error: err=" << ntohs(sre->sre_error) << ")";
130 } break;
131 case SCTP_SHUTDOWN_EVENT: {
132 LOG(INFO) << " SCTP_SHUTDOWN_EVENT";
133 } break;
134 default:
135 LOG(INFO) << " Unknown type: " << snp->sn_header.sn_type;
136 break;
137 }
138}
139
140std::string GetHostname() {
141 char buf[256];
142 buf[sizeof(buf) - 1] = '\0';
143 PCHECK(gethostname(buf, sizeof(buf) - 1) == 0);
144 return buf;
145}
146
147std::string Message::PeerAddress() const { return Address(sin); }
148
149void LogSctpStatus(int fd, sctp_assoc_t assoc_id) {
150 struct sctp_status status;
151 memset(&status, 0, sizeof(status));
152 status.sstat_assoc_id = assoc_id;
153
154 socklen_t size = sizeof(status);
155 PCHECK(getsockopt(fd, SOL_SCTP, SCTP_STATUS,
156 reinterpret_cast<void *>(&status), &size) == 0);
157
158 LOG(INFO) << "sctp_status) sstat_assoc_id:" << status.sstat_assoc_id
159 << " sstat_state:" << status.sstat_state
160 << " sstat_rwnd:" << status.sstat_rwnd
161 << " sstat_unackdata:" << status.sstat_unackdata
162 << " sstat_penddata:" << status.sstat_penddata
163 << " sstat_instrms:" << status.sstat_instrms
164 << " sstat_outstrms:" << status.sstat_outstrms
165 << " sstat_fragmentation_point:" << status.sstat_fragmentation_point
166 << " sstat_primary.spinfo_srtt:" << status.sstat_primary.spinfo_srtt
167 << " sstat_primary.spinfo_rto:" << status.sstat_primary.spinfo_rto;
168}
169
170aos::unique_c_ptr<Message> ReadSctpMessage(int fd, int max_size) {
171 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
172 struct iovec iov;
173 struct msghdr inmessage;
174
175 memset(&inmessage, 0, sizeof(struct msghdr));
176
177 aos::unique_c_ptr<Message> result(
Austin Schuh7bc59052020-02-16 23:48:33 -0800178 reinterpret_cast<Message *>(malloc(sizeof(Message) + max_size + 1)));
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800179
Austin Schuh7bc59052020-02-16 23:48:33 -0800180 iov.iov_len = max_size + 1;
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800181 iov.iov_base = result->mutable_data();
182
183 inmessage.msg_iov = &iov;
184 inmessage.msg_iovlen = 1;
185
186 inmessage.msg_control = incmsg;
187 inmessage.msg_controllen = sizeof(incmsg);
188
189 inmessage.msg_namelen = sizeof(struct sockaddr_storage);
190 inmessage.msg_name = &result->sin;
191
192 ssize_t size;
193 PCHECK((size = recvmsg(fd, &inmessage, 0)) > 0);
194
195 result->size = size;
Austin Schuh7bc59052020-02-16 23:48:33 -0800196 CHECK_LE(size, max_size) << ": Message overflowed buffer.";
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800197
198 if ((MSG_NOTIFICATION & inmessage.msg_flags)) {
199 result->message_type = Message::kNotification;
200 } else {
201 result->message_type = Message::kMessage;
202 }
203
204 for (struct cmsghdr *scmsg = CMSG_FIRSTHDR(&inmessage); scmsg != NULL;
205 scmsg = CMSG_NXTHDR(&inmessage, scmsg)) {
206 switch (scmsg->cmsg_type) {
207 case SCTP_RCVINFO: {
208 struct sctp_rcvinfo *data = (struct sctp_rcvinfo *)CMSG_DATA(scmsg);
209 result->header.rcvinfo = *data;
210 } break;
211 default:
212 LOG(INFO) << "\tUnknown type: " << scmsg->cmsg_type;
213 break;
214 }
215 }
216
217 return result;
218}
219
220void Message::LogRcvInfo() const {
221 LOG(INFO) << "\tSNDRCV (stream=" << header.rcvinfo.rcv_sid
222 << " ssn=" << header.rcvinfo.rcv_ssn
223 << " tsn=" << header.rcvinfo.rcv_tsn << " flags=0x" << std::hex
224 << header.rcvinfo.rcv_flags << std::dec
225 << " ppid=" << header.rcvinfo.rcv_ppid
226 << " cumtsn=" << header.rcvinfo.rcv_cumtsn << ")";
227}
228
229} // namespace message_bridge
230} // namespace aos