sctptransport.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /**
  2. * Copyright (c) 2019 Paul-Louis Ageneau
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "sctptransport.hpp"
  19. #include <chrono>
  20. #include <exception>
  21. #include <iostream>
  22. #include <vector>
  23. #include <arpa/inet.h>
  24. using namespace std::chrono_literals;
  25. using namespace std::chrono;
  26. using std::shared_ptr;
  27. namespace rtc {
  28. std::mutex SctpTransport::GlobalMutex;
  29. int SctpTransport::InstancesCount = 0;
  30. void SctpTransport::GlobalInit() {
  31. std::lock_guard lock(GlobalMutex);
  32. if (InstancesCount++ == 0) {
  33. usrsctp_init(0, &SctpTransport::WriteCallback, nullptr);
  34. usrsctp_sysctl_set_sctp_ecn_enable(0);
  35. usrsctp_sysctl_set_sctp_init_rtx_max_default(5);
  36. usrsctp_sysctl_set_sctp_path_rtx_max_default(5);
  37. usrsctp_sysctl_set_sctp_assoc_rtx_max_default(5); // single path
  38. usrsctp_sysctl_set_sctp_rto_min_default(1 * 1000); // ms
  39. usrsctp_sysctl_set_sctp_rto_max_default(10 * 1000); // ms
  40. usrsctp_sysctl_set_sctp_rto_initial_default(1 * 1000); // ms
  41. usrsctp_sysctl_set_sctp_init_rto_max_default(10 * 1000); // ms
  42. usrsctp_sysctl_set_sctp_heartbeat_interval_default(10 * 1000); // ms
  43. }
  44. }
  45. void SctpTransport::GlobalCleanup() {
  46. std::lock_guard lock(GlobalMutex);
  47. if (--InstancesCount == 0) {
  48. usrsctp_finish();
  49. }
  50. }
  51. SctpTransport::SctpTransport(std::shared_ptr<Transport> lower, uint16_t port,
  52. message_callback recvCallback, amount_callback bufferedAmountCallback,
  53. state_callback stateChangeCallback)
  54. : Transport(lower), mPort(port), mSendQueue(0, message_size_func),
  55. mBufferedAmountCallback(std::move(bufferedAmountCallback)),
  56. mStateChangeCallback(std::move(stateChangeCallback)), mState(State::Disconnected) {
  57. onRecv(recvCallback);
  58. PLOG_DEBUG << "Initializing SCTP transport";
  59. GlobalInit();
  60. usrsctp_register_address(this);
  61. mSock = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, &SctpTransport::RecvCallback,
  62. &SctpTransport::SendCallback, 0, this);
  63. if (!mSock)
  64. throw std::runtime_error("Could not create SCTP socket, errno=" + std::to_string(errno));
  65. if (usrsctp_set_non_blocking(mSock, 1))
  66. throw std::runtime_error("Unable to set non-blocking mode, errno=" + std::to_string(errno));
  67. // SCTP must stop sending after the lower layer is shut down, so disable linger
  68. struct linger sol = {};
  69. sol.l_onoff = 1;
  70. sol.l_linger = 0;
  71. if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_LINGER, &sol, sizeof(sol)))
  72. throw std::runtime_error("Could not set socket option SO_LINGER, errno=" +
  73. std::to_string(errno));
  74. struct sctp_assoc_value av = {};
  75. av.assoc_id = SCTP_ALL_ASSOC;
  76. av.assoc_value = 1;
  77. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_ENABLE_STREAM_RESET, &av, sizeof(av)))
  78. throw std::runtime_error("Could not set socket option SCTP_ENABLE_STREAM_RESET, errno=" +
  79. std::to_string(errno));
  80. struct sctp_event se = {};
  81. se.se_assoc_id = SCTP_ALL_ASSOC;
  82. se.se_on = 1;
  83. se.se_type = SCTP_ASSOC_CHANGE;
  84. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se)))
  85. throw std::runtime_error("Could not subscribe to event SCTP_ASSOC_CHANGE, errno=" +
  86. std::to_string(errno));
  87. se.se_type = SCTP_SENDER_DRY_EVENT;
  88. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se)))
  89. throw std::runtime_error("Could not subscribe to event SCTP_SENDER_DRY_EVENT, errno=" +
  90. std::to_string(errno));
  91. se.se_type = SCTP_STREAM_RESET_EVENT;
  92. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se)))
  93. throw std::runtime_error("Could not subscribe to event SCTP_STREAM_RESET_EVENT, errno=" +
  94. std::to_string(errno));
  95. // The sender SHOULD disable the Nagle algorithm (see RFC1122) to minimize the latency.
  96. // See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6
  97. int nodelay = 1;
  98. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)))
  99. throw std::runtime_error("Could not set socket option SCTP_NODELAY, errno=" +
  100. std::to_string(errno));
  101. struct sctp_paddrparams spp = {};
  102. #ifdef __linux__
  103. // Linux UDP does path MTU discovery by default (setting DF and returning EMSGSIZE).
  104. // It should be safe to enable discovery for SCTP.
  105. spp.spp_flags = SPP_PMTUD_ENABLE;
  106. #else
  107. // Otherwise, fall back to a safe MTU value.
  108. spp.spp_flags = SPP_PMTUD_DISABLE;
  109. spp.spp_pathmtu = 1200; // Max safe value recommended by RFC 8261
  110. // See https://tools.ietf.org/html/rfc8261#section-5
  111. #endif
  112. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &spp, sizeof(spp)))
  113. throw std::runtime_error("Could not set socket option SCTP_PEER_ADDR_PARAMS, errno=" +
  114. std::to_string(errno));
  115. // The IETF draft recommends the number of streams negotiated during SCTP association to be
  116. // 65535. See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2
  117. struct sctp_initmsg sinit = {};
  118. sinit.sinit_num_ostreams = 65535;
  119. sinit.sinit_max_instreams = 65535;
  120. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_INITMSG, &sinit, sizeof(sinit)))
  121. throw std::runtime_error("Could not set socket option SCTP_INITMSG, errno=" +
  122. std::to_string(errno));
  123. // The default send and receive window size of usrsctp is 256KiB, which is too small for
  124. // realistic RTTs, therefore we increase it to 1MiB for better performance.
  125. // See https://bugzilla.mozilla.org/show_bug.cgi?id=1051685
  126. int bufSize = 1024 * 1024;
  127. if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize)))
  128. throw std::runtime_error("Could not set SCTP recv buffer size, errno=" +
  129. std::to_string(errno));
  130. if (usrsctp_setsockopt(mSock, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize)))
  131. throw std::runtime_error("Could not set SCTP send buffer size, errno=" +
  132. std::to_string(errno));
  133. connect();
  134. }
  135. SctpTransport::~SctpTransport() {
  136. stop();
  137. usrsctp_close(mSock);
  138. usrsctp_deregister_address(this);
  139. GlobalCleanup();
  140. }
  141. SctpTransport::State SctpTransport::state() const { return mState; }
  142. void SctpTransport::stop() {
  143. Transport::stop();
  144. onRecv(nullptr);
  145. if (!mShutdown.exchange(true)) {
  146. mSendQueue.stop();
  147. flush();
  148. shutdown();
  149. }
  150. }
  151. void SctpTransport::connect() {
  152. PLOG_DEBUG << "SCTP connect";
  153. changeState(State::Connecting);
  154. struct sockaddr_conn sconn = {};
  155. sconn.sconn_family = AF_CONN;
  156. sconn.sconn_port = htons(mPort);
  157. sconn.sconn_addr = this;
  158. #ifdef HAVE_SCONN_LEN
  159. sconn.sconn_len = sizeof(sconn);
  160. #endif
  161. if (usrsctp_bind(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn)))
  162. throw std::runtime_error("Could not bind usrsctp socket, errno=" + std::to_string(errno));
  163. // According to the IETF draft, both endpoints must initiate the SCTP association, in a
  164. // simultaneous-open manner, irrelevent to the SDP setup role.
  165. // See https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-9.3
  166. int ret = usrsctp_connect(mSock, reinterpret_cast<struct sockaddr *>(&sconn), sizeof(sconn));
  167. if (ret && errno != EINPROGRESS)
  168. throw std::runtime_error("Connection attempt failed, errno=" + std::to_string(errno));
  169. }
  170. void SctpTransport::shutdown() {
  171. PLOG_DEBUG << "SCTP shutdown";
  172. if (usrsctp_shutdown(mSock, SHUT_RDWR)) {
  173. PLOG_WARNING << "SCTP shutdown failed, errno=" << errno;
  174. }
  175. PLOG_INFO << "SCTP disconnected";
  176. changeState(State::Disconnected);
  177. mWrittenCondition.notify_all();
  178. }
  179. bool SctpTransport::send(message_ptr message) {
  180. std::lock_guard lock(mSendMutex);
  181. if (!message)
  182. return mSendQueue.empty();
  183. PLOG_VERBOSE << "Send size=" << message->size();
  184. // If nothing is pending, try to send directly
  185. if (mSendQueue.empty() && trySendMessage(message))
  186. return true;
  187. mSendQueue.push(message);
  188. updateBufferedAmount(message->stream, message_size_func(message));
  189. return false;
  190. }
  191. void SctpTransport::flush() {
  192. std::lock_guard lock(mSendMutex);
  193. trySendQueue();
  194. }
  195. void SctpTransport::reset(unsigned int stream) {
  196. PLOG_DEBUG << "SCTP resetting stream " << stream;
  197. std::unique_lock lock(mWriteMutex);
  198. mWritten = false;
  199. using srs_t = struct sctp_reset_streams;
  200. const size_t len = sizeof(srs_t) + sizeof(uint16_t);
  201. byte buffer[len] = {};
  202. srs_t &srs = *reinterpret_cast<srs_t *>(buffer);
  203. srs.srs_flags = SCTP_STREAM_RESET_OUTGOING;
  204. srs.srs_number_streams = 1;
  205. srs.srs_stream_list[0] = uint16_t(stream);
  206. if (usrsctp_setsockopt(mSock, IPPROTO_SCTP, SCTP_RESET_STREAMS, &srs, len) == 0) {
  207. mWrittenCondition.wait_for(lock, 1000ms,
  208. [&]() { return mWritten || mState != State::Connected; });
  209. } else {
  210. PLOG_WARNING << "SCTP reset stream " << stream << " failed, errno=" << errno;
  211. }
  212. }
  213. void SctpTransport::incoming(message_ptr message) {
  214. // There could be a race condition here where we receive the remote INIT before the local one is
  215. // sent, which would result in the connection being aborted. Therefore, we need to wait for data
  216. // to be sent on our side (i.e. the local INIT) before proceeding.
  217. {
  218. std::unique_lock lock(mWriteMutex);
  219. mWrittenCondition.wait(lock, [&]() { return mWrittenOnce || mState != State::Connected; });
  220. }
  221. if (message) {
  222. usrsctp_conninput(this, message->data(), message->size(), 0);
  223. } else {
  224. PLOG_INFO << "SCTP disconnected";
  225. changeState(State::Disconnected);
  226. recv(nullptr);
  227. }
  228. }
  229. void SctpTransport::changeState(State state) {
  230. if (mState.exchange(state) != state)
  231. mStateChangeCallback(state);
  232. }
  233. bool SctpTransport::trySendQueue() {
  234. // Requires mSendMutex to be locked
  235. while (auto next = mSendQueue.peek()) {
  236. auto message = *next;
  237. if (!trySendMessage(message))
  238. return false;
  239. mSendQueue.pop();
  240. updateBufferedAmount(message->stream, -message_size_func(message));
  241. }
  242. return true;
  243. }
  244. bool SctpTransport::trySendMessage(message_ptr message) {
  245. // Requires mSendMutex to be locked
  246. if (mState != State::Connected)
  247. return false;
  248. PLOG_VERBOSE << "SCTP try send size=" << message->size();
  249. // TODO: Implement SCTP ndata specification draft when supported everywhere
  250. // See https://tools.ietf.org/html/draft-ietf-tsvwg-sctp-ndata-08
  251. const Reliability reliability = message->reliability ? *message->reliability : Reliability();
  252. uint32_t ppid;
  253. switch (message->type) {
  254. case Message::String:
  255. ppid = !message->empty() ? PPID_STRING : PPID_STRING_EMPTY;
  256. break;
  257. case Message::Binary:
  258. ppid = !message->empty() ? PPID_BINARY : PPID_BINARY_EMPTY;
  259. break;
  260. default:
  261. ppid = PPID_CONTROL;
  262. break;
  263. }
  264. struct sctp_sendv_spa spa = {};
  265. // set sndinfo
  266. spa.sendv_flags |= SCTP_SEND_SNDINFO_VALID;
  267. spa.sendv_sndinfo.snd_sid = uint16_t(message->stream);
  268. spa.sendv_sndinfo.snd_ppid = htonl(ppid);
  269. spa.sendv_sndinfo.snd_flags |= SCTP_EOR; // implicit here
  270. // set prinfo
  271. spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
  272. if (reliability.unordered)
  273. spa.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
  274. switch (reliability.type) {
  275. case Reliability::TYPE_PARTIAL_RELIABLE_REXMIT:
  276. spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
  277. spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_RTX;
  278. spa.sendv_prinfo.pr_value = uint32_t(std::get<int>(reliability.rexmit));
  279. break;
  280. case Reliability::TYPE_PARTIAL_RELIABLE_TIMED:
  281. spa.sendv_flags |= SCTP_SEND_PRINFO_VALID;
  282. spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_TTL;
  283. spa.sendv_prinfo.pr_value = uint32_t(std::get<milliseconds>(reliability.rexmit).count());
  284. break;
  285. default:
  286. spa.sendv_prinfo.pr_policy = SCTP_PR_SCTP_NONE;
  287. break;
  288. }
  289. ssize_t ret;
  290. if (!message->empty()) {
  291. ret = usrsctp_sendv(mSock, message->data(), message->size(), nullptr, 0, &spa, sizeof(spa),
  292. SCTP_SENDV_SPA, 0);
  293. } else {
  294. const char zero = 0;
  295. ret = usrsctp_sendv(mSock, &zero, 1, nullptr, 0, &spa, sizeof(spa), SCTP_SENDV_SPA, 0);
  296. }
  297. if (ret >= 0) {
  298. PLOG_VERBOSE << "SCTP sent size=" << message->size();
  299. return true;
  300. } else if (errno == EWOULDBLOCK && errno == EAGAIN) {
  301. PLOG_VERBOSE << "SCTP sending not possible";
  302. return false;
  303. } else {
  304. PLOG_ERROR << "SCTP sending failed, errno=" << errno;
  305. throw std::runtime_error("Sending failed, errno=" + std::to_string(errno));
  306. }
  307. }
  308. void SctpTransport::updateBufferedAmount(uint16_t streamId, long delta) {
  309. // Requires mSendMutex to be locked
  310. auto it = mBufferedAmount.insert(std::make_pair(streamId, 0)).first;
  311. size_t amount = it->second;
  312. amount = size_t(std::max(long(amount) + delta, long(0)));
  313. if (amount == 0)
  314. mBufferedAmount.erase(it);
  315. mBufferedAmountCallback(streamId, amount);
  316. }
  317. int SctpTransport::handleRecv(struct socket *sock, union sctp_sockstore addr, const byte *data,
  318. size_t len, struct sctp_rcvinfo info, int flags) {
  319. try {
  320. if (!len)
  321. return -1;
  322. if (flags & MSG_EOR) {
  323. if (!mPartialRecv.empty()) {
  324. mPartialRecv.insert(mPartialRecv.end(), data, data + len);
  325. data = mPartialRecv.data();
  326. len = mPartialRecv.size();
  327. }
  328. // Message is complete, process it
  329. if (flags & MSG_NOTIFICATION)
  330. processNotification(reinterpret_cast<const union sctp_notification *>(data), len);
  331. else
  332. processData(data, len, info.rcv_sid, PayloadId(htonl(info.rcv_ppid)));
  333. mPartialRecv.clear();
  334. } else {
  335. // Message is not complete
  336. mPartialRecv.insert(mPartialRecv.end(), data, data + len);
  337. }
  338. } catch (const std::exception &e) {
  339. PLOG_ERROR << "SCTP recv: " << e.what();
  340. return -1;
  341. }
  342. return 0; // success
  343. }
  344. int SctpTransport::handleSend(size_t free) {
  345. try {
  346. std::lock_guard lock(mSendMutex);
  347. trySendQueue();
  348. } catch (const std::exception &e) {
  349. PLOG_ERROR << "SCTP send: " << e.what();
  350. return -1;
  351. }
  352. return 0; // success
  353. }
  354. int SctpTransport::handleWrite(byte *data, size_t len, uint8_t tos, uint8_t set_df) {
  355. try {
  356. std::unique_lock lock(mWriteMutex);
  357. if (!outgoing(make_message(data, data + len)))
  358. return -1;
  359. mWritten = true;
  360. mWrittenOnce = true;
  361. mWrittenCondition.notify_all();
  362. } catch (const std::exception &e) {
  363. PLOG_ERROR << "SCTP write: " << e.what();
  364. return -1;
  365. }
  366. return 0; // success
  367. }
  368. void SctpTransport::processData(const byte *data, size_t len, uint16_t sid, PayloadId ppid) {
  369. // The usage of the PPIDs "WebRTC String Partial" and "WebRTC Binary Partial" is deprecated.
  370. // See https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6
  371. // We handle them at reception for compatibility reasons but should never send them.
  372. switch (ppid) {
  373. case PPID_CONTROL:
  374. recv(make_message(data, data + len, Message::Control, sid));
  375. break;
  376. case PPID_STRING_PARTIAL: // deprecated
  377. mPartialStringData.insert(mPartialStringData.end(), data, data + len);
  378. break;
  379. case PPID_STRING:
  380. if (mPartialStringData.empty()) {
  381. recv(make_message(data, data + len, Message::String, sid));
  382. } else {
  383. mPartialStringData.insert(mPartialStringData.end(), data, data + len);
  384. recv(make_message(mPartialStringData.begin(), mPartialStringData.end(), Message::String,
  385. sid));
  386. mPartialStringData.clear();
  387. }
  388. break;
  389. case PPID_STRING_EMPTY:
  390. // This only accounts for when the partial data is empty
  391. recv(make_message(mPartialStringData.begin(), mPartialStringData.end(), Message::String,
  392. sid));
  393. mPartialStringData.clear();
  394. break;
  395. case PPID_BINARY_PARTIAL: // deprecated
  396. mPartialBinaryData.insert(mPartialBinaryData.end(), data, data + len);
  397. break;
  398. case PPID_BINARY:
  399. if (mPartialBinaryData.empty()) {
  400. recv(make_message(data, data + len, Message::Binary, sid));
  401. } else {
  402. mPartialBinaryData.insert(mPartialBinaryData.end(), data, data + len);
  403. recv(make_message(mPartialBinaryData.begin(), mPartialBinaryData.end(), Message::Binary,
  404. sid));
  405. mPartialBinaryData.clear();
  406. }
  407. break;
  408. case PPID_BINARY_EMPTY:
  409. // This only accounts for when the partial data is empty
  410. recv(make_message(mPartialBinaryData.begin(), mPartialBinaryData.end(), Message::Binary,
  411. sid));
  412. mPartialBinaryData.clear();
  413. break;
  414. default:
  415. // Unknown
  416. PLOG_WARNING << "Unknown PPID: " << uint32_t(ppid);
  417. return;
  418. }
  419. }
  420. void SctpTransport::processNotification(const union sctp_notification *notify, size_t len) {
  421. if (len != size_t(notify->sn_header.sn_length))
  422. return;
  423. switch (notify->sn_header.sn_type) {
  424. case SCTP_ASSOC_CHANGE: {
  425. const struct sctp_assoc_change &assoc_change = notify->sn_assoc_change;
  426. if (assoc_change.sac_state == SCTP_COMM_UP) {
  427. PLOG_INFO << "SCTP connected";
  428. changeState(State::Connected);
  429. } else {
  430. if (mState == State::Connecting) {
  431. PLOG_ERROR << "SCTP connection failed";
  432. changeState(State::Failed);
  433. } else {
  434. PLOG_INFO << "SCTP disconnected";
  435. changeState(State::Disconnected);
  436. }
  437. mWrittenCondition.notify_all();
  438. }
  439. }
  440. case SCTP_SENDER_DRY_EVENT: {
  441. // It not should be necessary since the send callback should have been called already,
  442. // but to be sure, let's try to send now.
  443. std::lock_guard lock(mSendMutex);
  444. trySendQueue();
  445. }
  446. case SCTP_STREAM_RESET_EVENT: {
  447. const struct sctp_stream_reset_event &reset_event = notify->sn_strreset_event;
  448. const int count = (reset_event.strreset_length - sizeof(reset_event)) / sizeof(uint16_t);
  449. const uint16_t flags = reset_event.strreset_flags;
  450. if (flags & SCTP_STREAM_RESET_OUTGOING_SSN) {
  451. for (int i = 0; i < count; ++i) {
  452. uint16_t streamId = reset_event.strreset_stream_list[i];
  453. reset(streamId);
  454. }
  455. }
  456. if (flags & SCTP_STREAM_RESET_INCOMING_SSN) {
  457. const byte dataChannelCloseMessage{0x04};
  458. for (int i = 0; i < count; ++i) {
  459. uint16_t streamId = reset_event.strreset_stream_list[i];
  460. recv(make_message(&dataChannelCloseMessage, &dataChannelCloseMessage + 1,
  461. Message::Control, streamId));
  462. }
  463. }
  464. break;
  465. }
  466. default:
  467. // Ignore
  468. break;
  469. }
  470. }
  471. int SctpTransport::RecvCallback(struct socket *sock, union sctp_sockstore addr, void *data,
  472. size_t len, struct sctp_rcvinfo recv_info, int flags, void *ptr) {
  473. int ret = static_cast<SctpTransport *>(ptr)->handleRecv(
  474. sock, addr, static_cast<const byte *>(data), len, recv_info, flags);
  475. free(data);
  476. return ret;
  477. }
  478. int SctpTransport::SendCallback(struct socket *sock, uint32_t sb_free) {
  479. struct sctp_paddrinfo paddrinfo = {};
  480. socklen_t len = sizeof(paddrinfo);
  481. if (usrsctp_getsockopt(sock, IPPROTO_SCTP, SCTP_GET_PEER_ADDR_INFO, &paddrinfo, &len))
  482. return -1;
  483. auto sconn = reinterpret_cast<struct sockaddr_conn *>(&paddrinfo.spinfo_address);
  484. void *ptr = sconn->sconn_addr;
  485. return static_cast<SctpTransport *>(ptr)->handleSend(size_t(sb_free));
  486. }
  487. int SctpTransport::WriteCallback(void *ptr, void *data, size_t len, uint8_t tos, uint8_t set_df) {
  488. return static_cast<SctpTransport *>(ptr)->handleWrite(static_cast<byte *>(data), len, tos,
  489. set_df);
  490. }
  491. } // namespace rtc