blob: 327f5a0464a28dd2087bc9c3adf698fa3a46b751 [file] [log] [blame]
Austin Schuhe84c3ed2019-12-14 15:29:48 -08001#include "aos/network/sctp_server.h"
2
3#include <arpa/inet.h>
4#include <net/if.h>
5#include <netdb.h>
6#include <netinet/in.h>
7#include <netinet/sctp.h>
Austin Schuhe84c3ed2019-12-14 15:29:48 -08008#include <sys/socket.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07009
10#include <cstdio>
11#include <cstdlib>
12#include <cstring>
Austin Schuhe84c3ed2019-12-14 15:29:48 -080013#include <memory>
Austin Schuh387b7de2020-03-15 14:28:07 -070014#include <thread>
Austin Schuhe84c3ed2019-12-14 15:29:48 -080015
16#include "aos/network/sctp_lib.h"
17#include "aos/unique_malloc_ptr.h"
18#include "glog/logging.h"
19
20namespace aos {
21namespace message_bridge {
22
23SctpServer::SctpServer(std::string_view local_host, int local_port)
Austin Schuh387b7de2020-03-15 14:28:07 -070024 : sockaddr_local_(ResolveSocket(local_host, local_port)) {
25 while (true) {
Austin Schuh507f7582021-07-31 20:39:55 -070026 sctp_.OpenSocket(sockaddr_local_);
Austin Schuhe84c3ed2019-12-14 15:29:48 -080027
Austin Schuh387b7de2020-03-15 14:28:07 -070028 {
29 struct sctp_event_subscribe subscribe;
30 memset(&subscribe, 0, sizeof(subscribe));
Austin Schuh387b7de2020-03-15 14:28:07 -070031 subscribe.sctp_association_event = 1;
32 subscribe.sctp_send_failure_event = 1;
33 subscribe.sctp_partial_delivery_event = 1;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080034
Austin Schuh507f7582021-07-31 20:39:55 -070035 PCHECK(setsockopt(fd(), SOL_SCTP, SCTP_EVENTS, (char *)&subscribe,
Austin Schuh387b7de2020-03-15 14:28:07 -070036 sizeof(subscribe)) == 0);
37 }
38 {
Austin Schuh387b7de2020-03-15 14:28:07 -070039 // Turn off the NAGLE algorithm.
40 int on = 1;
Austin Schuh507f7582021-07-31 20:39:55 -070041 PCHECK(setsockopt(fd(), IPPROTO_SCTP, SCTP_NODELAY, &on, sizeof(int)) ==
Austin Schuh387b7de2020-03-15 14:28:07 -070042 0);
43 }
44
Austin Schuhf6ed4522020-12-13 16:40:38 -080045 {
46 int on = 1;
Austin Schuh507f7582021-07-31 20:39:55 -070047 LOG(INFO) << "setsockopt(" << fd()
48 << ", SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)";
49 PCHECK(setsockopt(fd(), SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) == 0);
Austin Schuhf6ed4522020-12-13 16:40:38 -080050 }
51
Austin Schuh387b7de2020-03-15 14:28:07 -070052 // And go!
Austin Schuh507f7582021-07-31 20:39:55 -070053 if (bind(fd(), (struct sockaddr *)&sockaddr_local_,
Austin Schuh387b7de2020-03-15 14:28:07 -070054 sockaddr_local_.ss_family == AF_INET6
55 ? sizeof(struct sockaddr_in6)
56 : sizeof(struct sockaddr_in)) != 0) {
57 PLOG(ERROR) << "Failed to bind, retrying";
Austin Schuh507f7582021-07-31 20:39:55 -070058 close(fd());
Austin Schuh387b7de2020-03-15 14:28:07 -070059 std::this_thread::sleep_for(std::chrono::seconds(5));
60 continue;
61 }
Austin Schuh507f7582021-07-31 20:39:55 -070062 LOG(INFO) << "bind(" << fd() << ", " << Address(sockaddr_local_) << ")";
Austin Schuh387b7de2020-03-15 14:28:07 -070063
Austin Schuh507f7582021-07-31 20:39:55 -070064 PCHECK(listen(fd(), 100) == 0);
Austin Schuh387b7de2020-03-15 14:28:07 -070065
66 SetMaxSize(1000);
67 break;
Austin Schuhe84c3ed2019-12-14 15:29:48 -080068 }
Austin Schuhe84c3ed2019-12-14 15:29:48 -080069}
70
Austin Schuh4889b182020-11-18 19:11:56 -080071bool SctpServer::Abort(sctp_assoc_t snd_assoc_id) {
72 // Use the assoc_id for the destination instead of the msg_name.
73 struct msghdr outmsg;
74 outmsg.msg_namelen = 0;
75
76 outmsg.msg_iovlen = 0;
77
78 // Build up the sndinfo message.
79 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
80 outmsg.msg_control = outcmsg;
81 outmsg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
82 outmsg.msg_flags = 0;
83
84 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&outmsg);
85 cmsg->cmsg_level = IPPROTO_SCTP;
86 cmsg->cmsg_type = SCTP_SNDRCV;
87 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
88
89 struct sctp_sndrcvinfo *sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
90 memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
Austin Schuh4889b182020-11-18 19:11:56 -080091 sinfo->sinfo_stream = 0;
92 sinfo->sinfo_flags = SCTP_ABORT;
93 sinfo->sinfo_assoc_id = snd_assoc_id;
94
95 // And send.
Austin Schuh507f7582021-07-31 20:39:55 -070096 const ssize_t size = sendmsg(fd(), &outmsg, MSG_NOSIGNAL | MSG_DONTWAIT);
Austin Schuh4889b182020-11-18 19:11:56 -080097 if (size == -1) {
98 if (errno == EPIPE || errno == EAGAIN || errno == ESHUTDOWN) {
99 return false;
100 }
101 return false;
102 } else {
103 CHECK_EQ(0, size);
104 return true;
105 }
106}
107
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800108void SctpServer::SetPriorityScheduler(sctp_assoc_t assoc_id) {
109 struct sctp_assoc_value scheduler;
110 memset(&scheduler, 0, sizeof(scheduler));
111 scheduler.assoc_id = assoc_id;
112 scheduler.assoc_value = SCTP_SS_PRIO;
113 if (setsockopt(fd(), IPPROTO_SCTP, SCTP_STREAM_SCHEDULER, &scheduler,
114 sizeof(scheduler)) != 0) {
115 PLOG(WARNING) << "Failed to set scheduler";
116 }
117}
118
119void SctpServer::SetStreamPriority(sctp_assoc_t assoc_id, int stream_id,
120 uint16_t priority) {
121 struct sctp_stream_value sctp_priority;
122 memset(&sctp_priority, 0, sizeof(sctp_priority));
123 sctp_priority.assoc_id = assoc_id;
124 sctp_priority.stream_id = stream_id;
125 sctp_priority.stream_value = priority;
126 if (setsockopt(fd(), IPPROTO_SCTP, SCTP_STREAM_SCHEDULER_VALUE,
127 &sctp_priority, sizeof(sctp_priority)) != 0) {
128 PLOG(WARNING) << "Failed to set scheduler";
129 }
130}
131
132} // namespace message_bridge
133} // namespace aos