| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/media/sctp/sctpdataengine.h" | 11 #include "webrtc/media/sctp/sctpdataengine.h" |
| 12 | 12 |
| 13 #include <stdarg.h> | 13 #include <stdarg.h> |
| 14 #include <stdio.h> | 14 #include <stdio.h> |
| 15 | 15 |
| 16 #include <memory> | 16 #include <memory> |
| 17 #include <sstream> | 17 #include <sstream> |
| 18 #include <vector> | 18 #include <vector> |
| 19 | 19 |
| 20 #include "usrsctplib/usrsctp.h" | 20 #include "usrsctplib/usrsctp.h" |
| 21 #include "webrtc/base/arraysize.h" | 21 #include "webrtc/base/arraysize.h" |
| 22 #include "webrtc/base/copyonwritebuffer.h" | 22 #include "webrtc/base/copyonwritebuffer.h" |
| 23 #include "webrtc/base/criticalsection.h" |
| 23 #include "webrtc/base/helpers.h" | 24 #include "webrtc/base/helpers.h" |
| 24 #include "webrtc/base/logging.h" | 25 #include "webrtc/base/logging.h" |
| 25 #include "webrtc/base/safe_conversions.h" | 26 #include "webrtc/base/safe_conversions.h" |
| 26 #include "webrtc/media/base/codec.h" | 27 #include "webrtc/media/base/codec.h" |
| 27 #include "webrtc/media/base/mediaconstants.h" | 28 #include "webrtc/media/base/mediaconstants.h" |
| 28 #include "webrtc/media/base/streamparams.h" | 29 #include "webrtc/media/base/streamparams.h" |
| 29 | 30 |
| 31 namespace cricket { |
| 32 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, |
| 33 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. |
| 34 static const size_t kSctpMtu = 1200; |
| 35 |
| 36 // The size of the SCTP association send buffer. 256kB, the usrsctp default. |
| 37 static const int kSendBufferSize = 262144; |
| 38 |
| 39 struct SctpInboundPacket { |
| 40 rtc::CopyOnWriteBuffer buffer; |
| 41 ReceiveDataParams params; |
| 42 // The |flags| parameter is used by SCTP to distinguish notification packets |
| 43 // from other types of packets. |
| 44 int flags; |
| 45 }; |
| 46 |
| 30 namespace { | 47 namespace { |
| 31 typedef cricket::SctpDataMediaChannel::StreamSet StreamSet; | 48 // Set the initial value of the static SCTP Data Engines reference count. |
| 49 int g_usrsctp_usage_count = 0; |
| 50 rtc::GlobalLockPod g_usrsctp_lock_; |
| 51 |
| 52 typedef SctpDataMediaChannel::StreamSet StreamSet; |
| 53 |
| 32 // Returns a comma-separated, human-readable list of the stream IDs in 's' | 54 // Returns a comma-separated, human-readable list of the stream IDs in 's' |
| 33 std::string ListStreams(const StreamSet& s) { | 55 std::string ListStreams(const StreamSet& s) { |
| 34 std::stringstream result; | 56 std::stringstream result; |
| 35 bool first = true; | 57 bool first = true; |
| 36 for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) { | 58 for (StreamSet::const_iterator it = s.begin(); it != s.end(); ++it) { |
| 37 if (!first) { | 59 if (!first) { |
| 38 result << ", " << *it; | 60 result << ", " << *it; |
| 39 } else { | 61 } else { |
| 40 result << *it; | 62 result << *it; |
| 41 first = false; | 63 first = false; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 std::stringstream result; | 100 std::stringstream result; |
| 79 for (int i = 0; i < num_elems; ++i) { | 101 for (int i = 0; i < num_elems; ++i) { |
| 80 if (i) { | 102 if (i) { |
| 81 result << ", " << array[i]; | 103 result << ", " << array[i]; |
| 82 } else { | 104 } else { |
| 83 result << array[i]; | 105 result << array[i]; |
| 84 } | 106 } |
| 85 } | 107 } |
| 86 return result.str(); | 108 return result.str(); |
| 87 } | 109 } |
| 88 } // namespace | |
| 89 | 110 |
| 90 namespace cricket { | |
| 91 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; | 111 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; |
| 92 typedef rtc::ScopedMessageData<rtc::CopyOnWriteBuffer> OutboundPacketMessage; | 112 typedef rtc::ScopedMessageData<rtc::CopyOnWriteBuffer> OutboundPacketMessage; |
| 93 | 113 |
| 94 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, | |
| 95 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. | |
| 96 static const size_t kSctpMtu = 1200; | |
| 97 | |
| 98 // The size of the SCTP association send buffer. 256kB, the usrsctp default. | |
| 99 static const int kSendBufferSize = 262144; | |
| 100 enum { | 114 enum { |
| 101 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket | 115 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket |
| 102 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer | 116 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer |
| 103 }; | 117 }; |
| 104 | 118 |
| 105 struct SctpInboundPacket { | |
| 106 rtc::CopyOnWriteBuffer buffer; | |
| 107 ReceiveDataParams params; | |
| 108 // The |flags| parameter is used by SCTP to distinguish notification packets | |
| 109 // from other types of packets. | |
| 110 int flags; | |
| 111 }; | |
| 112 | |
| 113 // Helper for logging SCTP messages. | 119 // Helper for logging SCTP messages. |
| 114 static void debug_sctp_printf(const char *format, ...) { | 120 void DebugSctpPrintf(const char* format, ...) { |
| 121 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) |
| 115 char s[255]; | 122 char s[255]; |
| 116 va_list ap; | 123 va_list ap; |
| 117 va_start(ap, format); | 124 va_start(ap, format); |
| 118 vsnprintf(s, sizeof(s), format, ap); | 125 vsnprintf(s, sizeof(s), format, ap); |
| 119 LOG(LS_INFO) << "SCTP: " << s; | 126 LOG(LS_INFO) << "SCTP: " << s; |
| 120 va_end(ap); | 127 va_end(ap); |
| 128 #endif |
| 121 } | 129 } |
| 122 | 130 |
| 123 // Get the PPID to use for the terminating fragment of this type. | 131 // Get the PPID to use for the terminating fragment of this type. |
| 124 static SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid( | 132 SctpDataMediaChannel::PayloadProtocolIdentifier GetPpid(DataMessageType type) { |
| 125 cricket::DataMessageType type) { | |
| 126 switch (type) { | 133 switch (type) { |
| 127 default: | 134 default: |
| 128 case cricket::DMT_NONE: | 135 case DMT_NONE: |
| 129 return SctpDataMediaChannel::PPID_NONE; | 136 return SctpDataMediaChannel::PPID_NONE; |
| 130 case cricket::DMT_CONTROL: | 137 case DMT_CONTROL: |
| 131 return SctpDataMediaChannel::PPID_CONTROL; | 138 return SctpDataMediaChannel::PPID_CONTROL; |
| 132 case cricket::DMT_BINARY: | 139 case DMT_BINARY: |
| 133 return SctpDataMediaChannel::PPID_BINARY_LAST; | 140 return SctpDataMediaChannel::PPID_BINARY_LAST; |
| 134 case cricket::DMT_TEXT: | 141 case DMT_TEXT: |
| 135 return SctpDataMediaChannel::PPID_TEXT_LAST; | 142 return SctpDataMediaChannel::PPID_TEXT_LAST; |
| 136 }; | 143 }; |
| 137 } | 144 } |
| 138 | 145 |
| 139 static bool GetDataMediaType( | 146 bool GetDataMediaType(SctpDataMediaChannel::PayloadProtocolIdentifier ppid, |
| 140 SctpDataMediaChannel::PayloadProtocolIdentifier ppid, | 147 DataMessageType* dest) { |
| 141 cricket::DataMessageType *dest) { | |
| 142 ASSERT(dest != NULL); | 148 ASSERT(dest != NULL); |
| 143 switch (ppid) { | 149 switch (ppid) { |
| 144 case SctpDataMediaChannel::PPID_BINARY_PARTIAL: | 150 case SctpDataMediaChannel::PPID_BINARY_PARTIAL: |
| 145 case SctpDataMediaChannel::PPID_BINARY_LAST: | 151 case SctpDataMediaChannel::PPID_BINARY_LAST: |
| 146 *dest = cricket::DMT_BINARY; | 152 *dest = DMT_BINARY; |
| 147 return true; | 153 return true; |
| 148 | 154 |
| 149 case SctpDataMediaChannel::PPID_TEXT_PARTIAL: | 155 case SctpDataMediaChannel::PPID_TEXT_PARTIAL: |
| 150 case SctpDataMediaChannel::PPID_TEXT_LAST: | 156 case SctpDataMediaChannel::PPID_TEXT_LAST: |
| 151 *dest = cricket::DMT_TEXT; | 157 *dest = DMT_TEXT; |
| 152 return true; | 158 return true; |
| 153 | 159 |
| 154 case SctpDataMediaChannel::PPID_CONTROL: | 160 case SctpDataMediaChannel::PPID_CONTROL: |
| 155 *dest = cricket::DMT_CONTROL; | 161 *dest = DMT_CONTROL; |
| 156 return true; | 162 return true; |
| 157 | 163 |
| 158 case SctpDataMediaChannel::PPID_NONE: | 164 case SctpDataMediaChannel::PPID_NONE: |
| 159 *dest = cricket::DMT_NONE; | 165 *dest = DMT_NONE; |
| 160 return true; | 166 return true; |
| 161 | 167 |
| 162 default: | 168 default: |
| 163 return false; | 169 return false; |
| 164 } | 170 } |
| 165 } | 171 } |
| 166 | 172 |
| 167 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. | 173 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. |
| 168 static void VerboseLogPacket(const void *data, size_t length, int direction) { | 174 void VerboseLogPacket(const void* data, size_t length, int direction) { |
| 169 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { | 175 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { |
| 170 char *dump_buf; | 176 char *dump_buf; |
| 171 // Some downstream project uses an older version of usrsctp that expects | 177 // Some downstream project uses an older version of usrsctp that expects |
| 172 // a non-const "void*" as first parameter when dumping the packet, so we | 178 // a non-const "void*" as first parameter when dumping the packet, so we |
| 173 // need to cast the const away here to avoid a compiler error. | 179 // need to cast the const away here to avoid a compiler error. |
| 174 if ((dump_buf = usrsctp_dumppacket( | 180 if ((dump_buf = usrsctp_dumppacket( |
| 175 const_cast<void*>(data), length, direction)) != NULL) { | 181 const_cast<void*>(data), length, direction)) != NULL) { |
| 176 LOG(LS_VERBOSE) << dump_buf; | 182 LOG(LS_VERBOSE) << dump_buf; |
| 177 usrsctp_freedumpbuffer(dump_buf); | 183 usrsctp_freedumpbuffer(dump_buf); |
| 178 } | 184 } |
| 179 } | 185 } |
| 180 } | 186 } |
| 181 | 187 |
| 182 // This is the callback usrsctp uses when there's data to send on the network | 188 // This is the callback usrsctp uses when there's data to send on the network |
| 183 // that has been wrapped appropriatly for the SCTP protocol. | 189 // that has been wrapped appropriatly for the SCTP protocol. |
| 184 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, | 190 int OnSctpOutboundPacket(void* addr, |
| 185 uint8_t tos, uint8_t set_df) { | 191 void* data, |
| 192 size_t length, |
| 193 uint8_t tos, |
| 194 uint8_t set_df) { |
| 186 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); | 195 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); |
| 187 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" | 196 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" |
| 188 << "addr: " << addr << "; length: " << length | 197 << "addr: " << addr << "; length: " << length |
| 189 << "; tos: " << std::hex << static_cast<int>(tos) | 198 << "; tos: " << std::hex << static_cast<int>(tos) |
| 190 << "; set_df: " << std::hex << static_cast<int>(set_df); | 199 << "; set_df: " << std::hex << static_cast<int>(set_df); |
| 191 | 200 |
| 192 VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND); | 201 VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND); |
| 193 // Note: We have to copy the data; the caller will delete it. | 202 // Note: We have to copy the data; the caller will delete it. |
| 194 auto* msg = new OutboundPacketMessage( | 203 auto* msg = new OutboundPacketMessage( |
| 195 new rtc::CopyOnWriteBuffer(reinterpret_cast<uint8_t*>(data), length)); | 204 new rtc::CopyOnWriteBuffer(reinterpret_cast<uint8_t*>(data), length)); |
| 196 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); | 205 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); |
| 197 return 0; | 206 return 0; |
| 198 } | 207 } |
| 199 | 208 |
| 200 // This is the callback called from usrsctp when data has been received, after | 209 // This is the callback called from usrsctp when data has been received, after |
| 201 // a packet has been interpreted and parsed by usrsctp and found to contain | 210 // a packet has been interpreted and parsed by usrsctp and found to contain |
| 202 // payload data. It is called by a usrsctp thread. It is assumed this function | 211 // payload data. It is called by a usrsctp thread. It is assumed this function |
| 203 // will free the memory used by 'data'. | 212 // will free the memory used by 'data'. |
| 204 static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr, | 213 int OnSctpInboundPacket(struct socket* sock, |
| 205 void* data, size_t length, | 214 union sctp_sockstore addr, |
| 206 struct sctp_rcvinfo rcv, int flags, | 215 void* data, |
| 207 void* ulp_info) { | 216 size_t length, |
| 217 struct sctp_rcvinfo rcv, |
| 218 int flags, |
| 219 void* ulp_info) { |
| 208 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info); | 220 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(ulp_info); |
| 209 // Post data to the channel's receiver thread (copying it). | 221 // Post data to the channel's receiver thread (copying it). |
| 210 // TODO(ldixon): Unclear if copy is needed as this method is responsible for | 222 // TODO(ldixon): Unclear if copy is needed as this method is responsible for |
| 211 // memory cleanup. But this does simplify code. | 223 // memory cleanup. But this does simplify code. |
| 212 const SctpDataMediaChannel::PayloadProtocolIdentifier ppid = | 224 const SctpDataMediaChannel::PayloadProtocolIdentifier ppid = |
| 213 static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>( | 225 static_cast<SctpDataMediaChannel::PayloadProtocolIdentifier>( |
| 214 rtc::HostToNetwork32(rcv.rcv_ppid)); | 226 rtc::HostToNetwork32(rcv.rcv_ppid)); |
| 215 cricket::DataMessageType type = cricket::DMT_NONE; | 227 DataMessageType type = DMT_NONE; |
| 216 if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) { | 228 if (!GetDataMediaType(ppid, &type) && !(flags & MSG_NOTIFICATION)) { |
| 217 // It's neither a notification nor a recognized data packet. Drop it. | 229 // It's neither a notification nor a recognized data packet. Drop it. |
| 218 LOG(LS_ERROR) << "Received an unknown PPID " << ppid | 230 LOG(LS_ERROR) << "Received an unknown PPID " << ppid |
| 219 << " on an SCTP packet. Dropping."; | 231 << " on an SCTP packet. Dropping."; |
| 220 } else { | 232 } else { |
| 221 SctpInboundPacket* packet = new SctpInboundPacket; | 233 SctpInboundPacket* packet = new SctpInboundPacket; |
| 222 packet->buffer.SetData(reinterpret_cast<uint8_t*>(data), length); | 234 packet->buffer.SetData(reinterpret_cast<uint8_t*>(data), length); |
| 223 packet->params.ssrc = rcv.rcv_sid; | 235 packet->params.ssrc = rcv.rcv_sid; |
| 224 packet->params.seq_num = rcv.rcv_ssn; | 236 packet->params.seq_num = rcv.rcv_ssn; |
| 225 packet->params.timestamp = rcv.rcv_tsn; | 237 packet->params.timestamp = rcv.rcv_tsn; |
| 226 packet->params.type = type; | 238 packet->params.type = type; |
| 227 packet->flags = flags; | 239 packet->flags = flags; |
| 228 // The ownership of |packet| transfers to |msg|. | 240 // The ownership of |packet| transfers to |msg|. |
| 229 InboundPacketMessage* msg = new InboundPacketMessage(packet); | 241 InboundPacketMessage* msg = new InboundPacketMessage(packet); |
| 230 channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg); | 242 channel->worker_thread()->Post(channel, MSG_SCTPINBOUNDPACKET, msg); |
| 231 } | 243 } |
| 232 free(data); | 244 free(data); |
| 233 return 1; | 245 return 1; |
| 234 } | 246 } |
| 235 | 247 |
| 236 // Set the initial value of the static SCTP Data Engines reference count. | 248 void InitializeUsrSctp() { |
| 237 int SctpDataEngine::usrsctp_engines_count = 0; | 249 LOG(LS_INFO) << __FUNCTION__; |
| 250 // First argument is udp_encapsulation_port, which is not releveant for our |
| 251 // AF_CONN use of sctp. |
| 252 usrsctp_init(0, &OnSctpOutboundPacket, &DebugSctpPrintf); |
| 238 | 253 |
| 239 SctpDataEngine::SctpDataEngine() { | 254 // To turn on/off detailed SCTP debugging. You will also need to have the |
| 240 if (usrsctp_engines_count == 0) { | 255 // SCTP_DEBUG cpp defines flag. |
| 241 // First argument is udp_encapsulation_port, which is not releveant for our | 256 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); |
| 242 // AF_CONN use of sctp. | |
| 243 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); | |
| 244 | 257 |
| 245 // To turn on/off detailed SCTP debugging. You will also need to have the | 258 // TODO(ldixon): Consider turning this on/off. |
| 246 // SCTP_DEBUG cpp defines flag. | 259 usrsctp_sysctl_set_sctp_ecn_enable(0); |
| 247 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); | |
| 248 | 260 |
| 249 // TODO(ldixon): Consider turning this on/off. | 261 // This is harmless, but we should find out when the library default |
| 250 usrsctp_sysctl_set_sctp_ecn_enable(0); | 262 // changes. |
| 263 int send_size = usrsctp_sysctl_get_sctp_sendspace(); |
| 264 if (send_size != kSendBufferSize) { |
| 265 LOG(LS_ERROR) << "Got different send size than expected: " << send_size; |
| 266 } |
| 251 | 267 |
| 252 // This is harmless, but we should find out when the library default | 268 // TODO(ldixon): Consider turning this on/off. |
| 253 // changes. | 269 // This is not needed right now (we don't do dynamic address changes): |
| 254 int send_size = usrsctp_sysctl_get_sctp_sendspace(); | 270 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically |
| 255 if (send_size != kSendBufferSize) { | 271 // when a new address is added or removed. This feature is enabled by |
| 256 LOG(LS_ERROR) << "Got different send size than expected: " << send_size; | 272 // default. |
| 273 // usrsctp_sysctl_set_sctp_auto_asconf(0); |
| 274 |
| 275 // TODO(ldixon): Consider turning this on/off. |
| 276 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs |
| 277 // being sent in response to INITs, setting it to 2 results |
| 278 // in no ABORTs being sent for received OOTB packets. |
| 279 // This is similar to the TCP sysctl. |
| 280 // |
| 281 // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html |
| 282 // See: http://svnweb.freebsd.org/base?view=revision&revision=229805 |
| 283 // usrsctp_sysctl_set_sctp_blackhole(2); |
| 284 |
| 285 // Set the number of default outgoing streams. This is the number we'll |
| 286 // send in the SCTP INIT message. The 'appropriate default' in the |
| 287 // second paragraph of |
| 288 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2 |
| 289 // is kMaxSctpSid. |
| 290 usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(kMaxSctpSid); |
| 291 } |
| 292 |
| 293 void UninitializeUsrSctp() { |
| 294 LOG(LS_INFO) << __FUNCTION__; |
| 295 // usrsctp_finish() may fail if it's called too soon after the channels are |
| 296 // closed. Wait and try again until it succeeds for up to 3 seconds. |
| 297 for (size_t i = 0; i < 300; ++i) { |
| 298 if (usrsctp_finish() == 0) { |
| 299 return; |
| 257 } | 300 } |
| 258 | 301 |
| 259 // TODO(ldixon): Consider turning this on/off. | 302 rtc::Thread::SleepMs(10); |
| 260 // This is not needed right now (we don't do dynamic address changes): | |
| 261 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically | |
| 262 // when a new address is added or removed. This feature is enabled by | |
| 263 // default. | |
| 264 // usrsctp_sysctl_set_sctp_auto_asconf(0); | |
| 265 | |
| 266 // TODO(ldixon): Consider turning this on/off. | |
| 267 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs | |
| 268 // being sent in response to INITs, setting it to 2 results | |
| 269 // in no ABORTs being sent for received OOTB packets. | |
| 270 // This is similar to the TCP sysctl. | |
| 271 // | |
| 272 // See: http://lakerest.net/pipermail/sctp-coders/2012-January/009438.html | |
| 273 // See: http://svnweb.freebsd.org/base?view=revision&revision=229805 | |
| 274 // usrsctp_sysctl_set_sctp_blackhole(2); | |
| 275 | |
| 276 // Set the number of default outgoing streams. This is the number we'll | |
| 277 // send in the SCTP INIT message. The 'appropriate default' in the | |
| 278 // second paragraph of | |
| 279 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2 | |
| 280 // is cricket::kMaxSctpSid. | |
| 281 usrsctp_sysctl_set_sctp_nr_outgoing_streams_default( | |
| 282 cricket::kMaxSctpSid); | |
| 283 } | 303 } |
| 284 usrsctp_engines_count++; | 304 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; |
| 285 | |
| 286 cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName); | |
| 287 codec.SetParam(kCodecParamPort, kSctpDefaultPort); | |
| 288 codecs_.push_back(codec); | |
| 289 } | 305 } |
| 290 | 306 |
| 291 SctpDataEngine::~SctpDataEngine() { | 307 void IncrementUsrSctpUsageCount() { |
| 292 usrsctp_engines_count--; | 308 rtc::GlobalLockScope lock(&g_usrsctp_lock_); |
| 293 LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count; | 309 if (!g_usrsctp_usage_count) { |
| 310 InitializeUsrSctp(); |
| 311 } |
| 312 ++g_usrsctp_usage_count; |
| 313 } |
| 294 | 314 |
| 295 if (usrsctp_engines_count == 0) { | 315 void DecrementUsrSctpUsageCount() { |
| 296 // usrsctp_finish() may fail if it's called too soon after the channels are | 316 rtc::GlobalLockScope lock(&g_usrsctp_lock_); |
| 297 // closed. Wait and try again until it succeeds for up to 3 seconds. | 317 --g_usrsctp_usage_count; |
| 298 for (size_t i = 0; i < 300; ++i) { | 318 if (!g_usrsctp_usage_count) { |
| 299 if (usrsctp_finish() == 0) | 319 UninitializeUsrSctp(); |
| 300 return; | |
| 301 | |
| 302 rtc::Thread::SleepMs(10); | |
| 303 } | |
| 304 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; | |
| 305 } | 320 } |
| 306 } | 321 } |
| 307 | 322 |
| 323 DataCodec GetSctpDataCodec() { |
| 324 DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName); |
| 325 codec.SetParam(kCodecParamPort, kSctpDefaultPort); |
| 326 return codec; |
| 327 } |
| 328 |
| 329 } // namespace |
| 330 |
| 331 SctpDataEngine::SctpDataEngine() : codecs_(1, GetSctpDataCodec()) {} |
| 332 |
| 333 SctpDataEngine::~SctpDataEngine() {} |
| 334 |
| 335 // Called on the worker thread. |
| 308 DataMediaChannel* SctpDataEngine::CreateChannel( | 336 DataMediaChannel* SctpDataEngine::CreateChannel( |
| 309 DataChannelType data_channel_type) { | 337 DataChannelType data_channel_type) { |
| 310 if (data_channel_type != DCT_SCTP) { | 338 if (data_channel_type != DCT_SCTP) { |
| 311 return NULL; | 339 return NULL; |
| 312 } | 340 } |
| 313 return new SctpDataMediaChannel(rtc::Thread::Current()); | 341 return new SctpDataMediaChannel(rtc::Thread::Current()); |
| 314 } | 342 } |
| 315 | 343 |
| 316 // static | 344 // static |
| 317 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket( | 345 SctpDataMediaChannel* SctpDataMediaChannel::GetChannelFromSocket( |
| 318 struct socket* sock) { | 346 struct socket* sock) { |
| 319 struct sockaddr* addrs = nullptr; | 347 struct sockaddr* addrs = nullptr; |
| 320 int naddrs = usrsctp_getladdrs(sock, 0, &addrs); | 348 int naddrs = usrsctp_getladdrs(sock, 0, &addrs); |
| 321 if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) { | 349 if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) { |
| 322 return nullptr; | 350 return nullptr; |
| 323 } | 351 } |
| 324 // usrsctp_getladdrs() returns the addresses bound to this socket, which | 352 // usrsctp_getladdrs() returns the addresses bound to this socket, which |
| 325 // contains the SctpDataMediaChannel* as sconn_addr. Read the pointer, | 353 // contains the SctpDataMediaChannel* as sconn_addr. Read the pointer, |
| 326 // then free the list of addresses once we have the pointer. We only open | 354 // then free the list of addresses once we have the pointer. We only open |
| 327 // AF_CONN sockets, and they should all have the sconn_addr set to the | 355 // AF_CONN sockets, and they should all have the sconn_addr set to the |
| 328 // pointer that created them, so [0] is as good as any other. | 356 // pointer that created them, so [0] is as good as any other. |
| 329 struct sockaddr_conn* sconn = | 357 struct sockaddr_conn* sconn = |
| 330 reinterpret_cast<struct sockaddr_conn*>(&addrs[0]); | 358 reinterpret_cast<struct sockaddr_conn*>(&addrs[0]); |
| 331 SctpDataMediaChannel* channel = | 359 SctpDataMediaChannel* channel = |
| 332 reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr); | 360 reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr); |
| 333 usrsctp_freeladdrs(addrs); | 361 usrsctp_freeladdrs(addrs); |
| 334 | 362 |
| 335 return channel; | 363 return channel; |
| 336 } | 364 } |
| 337 | 365 |
| 338 // static | 366 // static |
| 339 int SctpDataEngine::SendThresholdCallback(struct socket* sock, | 367 int SctpDataMediaChannel::SendThresholdCallback(struct socket* sock, |
| 340 uint32_t sb_free) { | 368 uint32_t sb_free) { |
| 341 // Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets | 369 // Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets |
| 342 // a packet containing acknowledgments, which goes into usrsctp_conninput, | 370 // a packet containing acknowledgments, which goes into usrsctp_conninput, |
| 343 // and then back here. | 371 // and then back here. |
| 344 SctpDataMediaChannel* channel = GetChannelFromSocket(sock); | 372 SctpDataMediaChannel* channel = GetChannelFromSocket(sock); |
| 345 if (!channel) { | 373 if (!channel) { |
| 346 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " | 374 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " |
| 347 << sock; | 375 << sock; |
| 348 return 0; | 376 return 0; |
| 349 } | 377 } |
| 350 channel->OnSendThresholdCallback(); | 378 channel->OnSendThresholdCallback(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 return sconn; | 410 return sconn; |
| 383 } | 411 } |
| 384 | 412 |
| 385 bool SctpDataMediaChannel::OpenSctpSocket() { | 413 bool SctpDataMediaChannel::OpenSctpSocket() { |
| 386 if (sock_) { | 414 if (sock_) { |
| 387 LOG(LS_VERBOSE) << debug_name_ | 415 LOG(LS_VERBOSE) << debug_name_ |
| 388 << "->Ignoring attempt to re-create existing socket."; | 416 << "->Ignoring attempt to re-create existing socket."; |
| 389 return false; | 417 return false; |
| 390 } | 418 } |
| 391 | 419 |
| 420 IncrementUsrSctpUsageCount(); |
| 421 |
| 392 // If kSendBufferSize isn't reflective of reality, we log an error, but we | 422 // If kSendBufferSize isn't reflective of reality, we log an error, but we |
| 393 // still have to do something reasonable here. Look up what the buffer's | 423 // still have to do something reasonable here. Look up what the buffer's |
| 394 // real size is and set our threshold to something reasonable. | 424 // real size is and set our threshold to something reasonable. |
| 395 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2; | 425 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2; |
| 396 | 426 |
| 397 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, | 427 sock_ = usrsctp_socket( |
| 398 cricket::OnSctpInboundPacket, | 428 AF_CONN, SOCK_STREAM, IPPROTO_SCTP, OnSctpInboundPacket, |
| 399 &SctpDataEngine::SendThresholdCallback, | 429 &SctpDataMediaChannel::SendThresholdCallback, kSendThreshold, this); |
| 400 kSendThreshold, this); | |
| 401 if (!sock_) { | 430 if (!sock_) { |
| 402 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; | 431 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; |
| 432 DecrementUsrSctpUsageCount(); |
| 403 return false; | 433 return false; |
| 404 } | 434 } |
| 405 | 435 |
| 406 // Make the socket non-blocking. Connect, close, shutdown etc will not block | 436 // Make the socket non-blocking. Connect, close, shutdown etc will not block |
| 407 // the thread waiting for the socket operation to complete. | 437 // the thread waiting for the socket operation to complete. |
| 408 if (usrsctp_set_non_blocking(sock_, 1) < 0) { | 438 if (usrsctp_set_non_blocking(sock_, 1) < 0) { |
| 409 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; | 439 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; |
| 410 return false; | 440 return false; |
| 411 } | 441 } |
| 412 | 442 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 481 | 511 |
| 482 void SctpDataMediaChannel::CloseSctpSocket() { | 512 void SctpDataMediaChannel::CloseSctpSocket() { |
| 483 sending_ = false; | 513 sending_ = false; |
| 484 if (sock_) { | 514 if (sock_) { |
| 485 // We assume that SO_LINGER option is set to close the association when | 515 // We assume that SO_LINGER option is set to close the association when |
| 486 // close is called. This means that any pending packets in usrsctp will be | 516 // close is called. This means that any pending packets in usrsctp will be |
| 487 // discarded instead of being sent. | 517 // discarded instead of being sent. |
| 488 usrsctp_close(sock_); | 518 usrsctp_close(sock_); |
| 489 sock_ = NULL; | 519 sock_ = NULL; |
| 490 usrsctp_deregister_address(this); | 520 usrsctp_deregister_address(this); |
| 521 |
| 522 DecrementUsrSctpUsageCount(); |
| 491 } | 523 } |
| 492 } | 524 } |
| 493 | 525 |
| 494 bool SctpDataMediaChannel::Connect() { | 526 bool SctpDataMediaChannel::Connect() { |
| 495 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; | 527 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; |
| 496 | 528 |
| 497 // If we already have a socket connection, just return. | 529 // If we already have a socket connection, just return. |
| 498 if (sock_) { | 530 if (sock_) { |
| 499 LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket " | 531 LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket " |
| 500 "is already established."; | 532 "is already established."; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 *result = SDR_ERROR; | 624 *result = SDR_ERROR; |
| 593 } | 625 } |
| 594 | 626 |
| 595 if (!sending_) { | 627 if (!sending_) { |
| 596 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " | 628 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " |
| 597 << "Not sending packet with ssrc=" << params.ssrc | 629 << "Not sending packet with ssrc=" << params.ssrc |
| 598 << " len=" << payload.size() << " before SetSend(true)."; | 630 << " len=" << payload.size() << " before SetSend(true)."; |
| 599 return false; | 631 return false; |
| 600 } | 632 } |
| 601 | 633 |
| 602 if (params.type != cricket::DMT_CONTROL && | 634 if (params.type != DMT_CONTROL && |
| 603 open_streams_.find(params.ssrc) == open_streams_.end()) { | 635 open_streams_.find(params.ssrc) == open_streams_.end()) { |
| 604 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " | 636 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " |
| 605 << "Not sending data because ssrc is unknown: " | 637 << "Not sending data because ssrc is unknown: " |
| 606 << params.ssrc; | 638 << params.ssrc; |
| 607 return false; | 639 return false; |
| 608 } | 640 } |
| 609 | 641 |
| 610 // | 642 // |
| 611 // Send data using SCTP. | 643 // Send data using SCTP. |
| 612 ssize_t send_res = 0; // result from usrsctp_sendv. | 644 ssize_t send_res = 0; // result from usrsctp_sendv. |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 << " len=" << buffer.size() << " before SetReceive(true)."; | 742 << " len=" << buffer.size() << " before SetReceive(true)."; |
| 711 } | 743 } |
| 712 } | 744 } |
| 713 | 745 |
| 714 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { | 746 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { |
| 715 if (!stream.has_ssrcs()) { | 747 if (!stream.has_ssrcs()) { |
| 716 return false; | 748 return false; |
| 717 } | 749 } |
| 718 | 750 |
| 719 const uint32_t ssrc = stream.first_ssrc(); | 751 const uint32_t ssrc = stream.first_ssrc(); |
| 720 if (ssrc >= cricket::kMaxSctpSid) { | 752 if (ssrc >= kMaxSctpSid) { |
| 721 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " | 753 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " |
| 722 << "Not adding data stream '" << stream.id | 754 << "Not adding data stream '" << stream.id |
| 723 << "' with ssrc=" << ssrc | 755 << "' with ssrc=" << ssrc |
| 724 << " because stream ssrc is too high."; | 756 << " because stream ssrc is too high."; |
| 725 return false; | 757 return false; |
| 726 } else if (open_streams_.find(ssrc) != open_streams_.end()) { | 758 } else if (open_streams_.find(ssrc) != open_streams_.end()) { |
| 727 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " | 759 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " |
| 728 << "Not adding data stream '" << stream.id | 760 << "Not adding data stream '" << stream.id |
| 729 << "' with ssrc=" << ssrc | 761 << "' with ssrc=" << ssrc |
| 730 << " because stream is already open."; | 762 << " because stream is already open."; |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 << "SCTP seems to have made a packet that is bigger " | 1009 << "SCTP seems to have made a packet that is bigger " |
| 978 << "than its official MTU: " << buffer->size() | 1010 << "than its official MTU: " << buffer->size() |
| 979 << " vs max of " << kSctpMtu | 1011 << " vs max of " << kSctpMtu |
| 980 << " even after adding " << kSctpOverhead | 1012 << " even after adding " << kSctpOverhead |
| 981 << " extra SCTP overhead"; | 1013 << " extra SCTP overhead"; |
| 982 } | 1014 } |
| 983 MediaChannel::SendPacket(buffer, rtc::PacketOptions()); | 1015 MediaChannel::SendPacket(buffer, rtc::PacketOptions()); |
| 984 } | 1016 } |
| 985 | 1017 |
| 986 bool SctpDataMediaChannel::SendQueuedStreamResets() { | 1018 bool SctpDataMediaChannel::SendQueuedStreamResets() { |
| 987 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) | 1019 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) { |
| 988 return true; | 1020 return true; |
| 1021 } |
| 989 | 1022 |
| 990 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" | 1023 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" |
| 991 << ListStreams(queued_reset_streams_) << "], Open: [" | 1024 << ListStreams(queued_reset_streams_) << "], Open: [" |
| 992 << ListStreams(open_streams_) << "], Sent: [" | 1025 << ListStreams(open_streams_) << "], Sent: [" |
| 993 << ListStreams(sent_reset_streams_) << "]"; | 1026 << ListStreams(sent_reset_streams_) << "]"; |
| 994 | 1027 |
| 995 const size_t num_streams = queued_reset_streams_.size(); | 1028 const size_t num_streams = queued_reset_streams_.size(); |
| 996 const size_t num_bytes = | 1029 const size_t num_bytes = |
| 997 sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t)); | 1030 sizeof(struct sctp_reset_streams) + (num_streams * sizeof(uint16_t)); |
| 998 | 1031 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 } | 1066 } |
| 1034 case MSG_SCTPOUTBOUNDPACKET: { | 1067 case MSG_SCTPOUTBOUNDPACKET: { |
| 1035 std::unique_ptr<OutboundPacketMessage> pdata( | 1068 std::unique_ptr<OutboundPacketMessage> pdata( |
| 1036 static_cast<OutboundPacketMessage*>(msg->pdata)); | 1069 static_cast<OutboundPacketMessage*>(msg->pdata)); |
| 1037 OnPacketFromSctpToNetwork(pdata->data().get()); | 1070 OnPacketFromSctpToNetwork(pdata->data().get()); |
| 1038 break; | 1071 break; |
| 1039 } | 1072 } |
| 1040 } | 1073 } |
| 1041 } | 1074 } |
| 1042 } // namespace cricket | 1075 } // namespace cricket |
| OLD | NEW |