Chromium Code Reviews| 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. |
| 257 } | 273 // usrsctp_sysctl_set_sctp_auto_asconf(0); |
| 258 | 274 |
| 259 // TODO(ldixon): Consider turning this on/off. | 275 // TODO(ldixon): Consider turning this on/off. |
| 260 // This is not needed right now (we don't do dynamic address changes): | 276 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs |
| 261 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically | 277 // being sent in response to INITs, setting it to 2 results |
| 262 // when a new address is added or removed. This feature is enabled by | 278 // in no ABORTs being sent for received OOTB packets. |
| 263 // default. | 279 // This is similar to the TCP sysctl. |
| 264 // usrsctp_sysctl_set_sctp_auto_asconf(0); | 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); | |
| 265 | 284 |
| 266 // TODO(ldixon): Consider turning this on/off. | 285 // Set the number of default outgoing streams. This is the number we'll |
| 267 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs | 286 // send in the SCTP INIT message. The 'appropriate default' in the |
| 268 // being sent in response to INITs, setting it to 2 results | 287 // second paragraph of |
| 269 // in no ABORTs being sent for received OOTB packets. | 288 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-05#section-6.2 |
| 270 // This is similar to the TCP sysctl. | 289 // is kMaxSctpSid. |
| 271 // | 290 usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(kMaxSctpSid); |
| 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 } | |
| 284 usrsctp_engines_count++; | |
| 285 | |
| 286 cricket::DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName); | |
| 287 codec.SetParam(kCodecParamPort, kSctpDefaultPort); | |
| 288 codecs_.push_back(codec); | |
| 289 } | 291 } |
| 290 | 292 |
| 291 SctpDataEngine::~SctpDataEngine() { | 293 void UninitializeUsrSctp() { |
| 292 usrsctp_engines_count--; | 294 LOG(LS_INFO) << __FUNCTION__; |
| 293 LOG(LS_VERBOSE) << "usrsctp_engines_count:" << usrsctp_engines_count; | 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; | |
| 294 | 300 |
| 295 if (usrsctp_engines_count == 0) { | 301 rtc::Thread::SleepMs(10); |
| 296 // usrsctp_finish() may fail if it's called too soon after the channels are | |
| 297 // closed. Wait and try again until it succeeds for up to 3 seconds. | |
| 298 for (size_t i = 0; i < 300; ++i) { | |
| 299 if (usrsctp_finish() == 0) | |
| 300 return; | |
| 301 | |
| 302 rtc::Thread::SleepMs(10); | |
| 303 } | |
| 304 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; | |
| 305 } | 302 } |
| 303 LOG(LS_ERROR) << "Failed to shutdown usrsctp."; | |
| 306 } | 304 } |
| 307 | 305 |
| 306 void IncrementUsrSctpUsageCount() { | |
| 307 rtc::GlobalLockScope lock(&g_usrsctp_lock_); | |
| 308 if (!g_usrsctp_usage_count) | |
|
Taylor Brandstetter
2016/05/19 15:53:13
nit: We use {}s even for 1-line if statements.
tommi
2016/05/19 16:54:12
Done. (here and in a couple of other places)
| |
| 309 InitializeUsrSctp(); | |
| 310 ++g_usrsctp_usage_count; | |
| 311 } | |
| 312 | |
| 313 void DecrementUsrSctpUsageCount() { | |
| 314 rtc::GlobalLockScope lock(&g_usrsctp_lock_); | |
| 315 --g_usrsctp_usage_count; | |
| 316 if (!g_usrsctp_usage_count) | |
| 317 UninitializeUsrSctp(); | |
| 318 } | |
| 319 | |
| 320 DataCodec GetSctpDataCodec() { | |
| 321 DataCodec codec(kGoogleSctpDataCodecId, kGoogleSctpDataCodecName); | |
| 322 codec.SetParam(kCodecParamPort, kSctpDefaultPort); | |
| 323 return codec; | |
| 324 } | |
| 325 | |
| 326 } // namespace | |
| 327 | |
| 328 SctpDataEngine::SctpDataEngine() : codecs_(1, GetSctpDataCodec()) {} | |
| 329 | |
| 330 SctpDataEngine::~SctpDataEngine() {} | |
| 331 | |
| 332 // Called on the worker thread. | |
| 308 DataMediaChannel* SctpDataEngine::CreateChannel( | 333 DataMediaChannel* SctpDataEngine::CreateChannel( |
| 309 DataChannelType data_channel_type) { | 334 DataChannelType data_channel_type) { |
| 310 if (data_channel_type != DCT_SCTP) { | 335 if (data_channel_type != DCT_SCTP) { |
| 311 return NULL; | 336 return NULL; |
| 312 } | 337 } |
| 313 return new SctpDataMediaChannel(rtc::Thread::Current()); | 338 return new SctpDataMediaChannel(rtc::Thread::Current()); |
| 314 } | 339 } |
| 315 | 340 |
| 341 const std::vector<DataCodec>& SctpDataEngine::data_codecs() { | |
| 342 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
|
Taylor Brandstetter
2016/05/19 15:53:13
Is this the only place thread_checker_ is used? Co
tommi
2016/05/19 16:54:12
I've removed the thread checker now and moved the
| |
| 343 return codecs_; | |
| 344 } | |
| 345 | |
| 316 // static | 346 // static |
| 317 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket( | 347 SctpDataMediaChannel* SctpDataMediaChannel::GetChannelFromSocket( |
| 318 struct socket* sock) { | 348 struct socket* sock) { |
| 319 struct sockaddr* addrs = nullptr; | 349 struct sockaddr* addrs = nullptr; |
| 320 int naddrs = usrsctp_getladdrs(sock, 0, &addrs); | 350 int naddrs = usrsctp_getladdrs(sock, 0, &addrs); |
| 321 if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) { | 351 if (naddrs <= 0 || addrs[0].sa_family != AF_CONN) { |
| 322 return nullptr; | 352 return nullptr; |
| 323 } | 353 } |
| 324 // usrsctp_getladdrs() returns the addresses bound to this socket, which | 354 // usrsctp_getladdrs() returns the addresses bound to this socket, which |
| 325 // contains the SctpDataMediaChannel* as sconn_addr. Read the pointer, | 355 // contains the SctpDataMediaChannel* as sconn_addr. Read the pointer, |
| 326 // then free the list of addresses once we have the pointer. We only open | 356 // 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 | 357 // 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. | 358 // pointer that created them, so [0] is as good as any other. |
| 329 struct sockaddr_conn* sconn = | 359 struct sockaddr_conn* sconn = |
| 330 reinterpret_cast<struct sockaddr_conn*>(&addrs[0]); | 360 reinterpret_cast<struct sockaddr_conn*>(&addrs[0]); |
| 331 SctpDataMediaChannel* channel = | 361 SctpDataMediaChannel* channel = |
| 332 reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr); | 362 reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr); |
| 333 usrsctp_freeladdrs(addrs); | 363 usrsctp_freeladdrs(addrs); |
| 334 | 364 |
| 335 return channel; | 365 return channel; |
| 336 } | 366 } |
| 337 | 367 |
| 338 // static | 368 // static |
| 339 int SctpDataEngine::SendThresholdCallback(struct socket* sock, | 369 int SctpDataMediaChannel::SendThresholdCallback(struct socket* sock, |
| 340 uint32_t sb_free) { | 370 uint32_t sb_free) { |
| 341 // Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets | 371 // Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets |
| 342 // a packet containing acknowledgments, which goes into usrsctp_conninput, | 372 // a packet containing acknowledgments, which goes into usrsctp_conninput, |
| 343 // and then back here. | 373 // and then back here. |
| 344 SctpDataMediaChannel* channel = GetChannelFromSocket(sock); | 374 SctpDataMediaChannel* channel = GetChannelFromSocket(sock); |
| 345 if (!channel) { | 375 if (!channel) { |
| 346 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " | 376 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket " |
| 347 << sock; | 377 << sock; |
| 348 return 0; | 378 return 0; |
| 349 } | 379 } |
| 350 channel->OnSendThresholdCallback(); | 380 channel->OnSendThresholdCallback(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 return sconn; | 412 return sconn; |
| 383 } | 413 } |
| 384 | 414 |
| 385 bool SctpDataMediaChannel::OpenSctpSocket() { | 415 bool SctpDataMediaChannel::OpenSctpSocket() { |
| 386 if (sock_) { | 416 if (sock_) { |
| 387 LOG(LS_VERBOSE) << debug_name_ | 417 LOG(LS_VERBOSE) << debug_name_ |
| 388 << "->Ignoring attempt to re-create existing socket."; | 418 << "->Ignoring attempt to re-create existing socket."; |
| 389 return false; | 419 return false; |
| 390 } | 420 } |
| 391 | 421 |
| 422 IncrementUsrSctpUsageCount(); | |
| 423 | |
| 392 // If kSendBufferSize isn't reflective of reality, we log an error, but we | 424 // 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 | 425 // still have to do something reasonable here. Look up what the buffer's |
| 394 // real size is and set our threshold to something reasonable. | 426 // real size is and set our threshold to something reasonable. |
| 395 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2; | 427 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2; |
| 396 | 428 |
| 397 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, | 429 sock_ = usrsctp_socket( |
| 398 cricket::OnSctpInboundPacket, | 430 AF_CONN, SOCK_STREAM, IPPROTO_SCTP, OnSctpInboundPacket, |
| 399 &SctpDataEngine::SendThresholdCallback, | 431 &SctpDataMediaChannel::SendThresholdCallback, kSendThreshold, this); |
| 400 kSendThreshold, this); | |
| 401 if (!sock_) { | 432 if (!sock_) { |
| 402 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; | 433 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; |
| 434 DecrementUsrSctpUsageCount(); | |
| 403 return false; | 435 return false; |
| 404 } | 436 } |
| 405 | 437 |
| 406 // Make the socket non-blocking. Connect, close, shutdown etc will not block | 438 // Make the socket non-blocking. Connect, close, shutdown etc will not block |
| 407 // the thread waiting for the socket operation to complete. | 439 // the thread waiting for the socket operation to complete. |
| 408 if (usrsctp_set_non_blocking(sock_, 1) < 0) { | 440 if (usrsctp_set_non_blocking(sock_, 1) < 0) { |
| 409 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; | 441 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; |
| 410 return false; | 442 return false; |
| 411 } | 443 } |
| 412 | 444 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 481 | 513 |
| 482 void SctpDataMediaChannel::CloseSctpSocket() { | 514 void SctpDataMediaChannel::CloseSctpSocket() { |
| 483 sending_ = false; | 515 sending_ = false; |
| 484 if (sock_) { | 516 if (sock_) { |
| 485 // We assume that SO_LINGER option is set to close the association when | 517 // 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 | 518 // close is called. This means that any pending packets in usrsctp will be |
| 487 // discarded instead of being sent. | 519 // discarded instead of being sent. |
| 488 usrsctp_close(sock_); | 520 usrsctp_close(sock_); |
| 489 sock_ = NULL; | 521 sock_ = NULL; |
| 490 usrsctp_deregister_address(this); | 522 usrsctp_deregister_address(this); |
| 523 | |
| 524 DecrementUsrSctpUsageCount(); | |
| 491 } | 525 } |
| 492 } | 526 } |
| 493 | 527 |
| 494 bool SctpDataMediaChannel::Connect() { | 528 bool SctpDataMediaChannel::Connect() { |
| 495 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; | 529 LOG(LS_VERBOSE) << debug_name_ << "->Connect()."; |
| 496 | 530 |
| 497 // If we already have a socket connection, just return. | 531 // If we already have a socket connection, just return. |
| 498 if (sock_) { | 532 if (sock_) { |
| 499 LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket " | 533 LOG(LS_WARNING) << debug_name_ << "->Connect(): Ignored as socket " |
| 500 "is already established."; | 534 "is already established."; |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 592 *result = SDR_ERROR; | 626 *result = SDR_ERROR; |
| 593 } | 627 } |
| 594 | 628 |
| 595 if (!sending_) { | 629 if (!sending_) { |
| 596 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " | 630 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " |
| 597 << "Not sending packet with ssrc=" << params.ssrc | 631 << "Not sending packet with ssrc=" << params.ssrc |
| 598 << " len=" << payload.size() << " before SetSend(true)."; | 632 << " len=" << payload.size() << " before SetSend(true)."; |
| 599 return false; | 633 return false; |
| 600 } | 634 } |
| 601 | 635 |
| 602 if (params.type != cricket::DMT_CONTROL && | 636 if (params.type != DMT_CONTROL && |
| 603 open_streams_.find(params.ssrc) == open_streams_.end()) { | 637 open_streams_.find(params.ssrc) == open_streams_.end()) { |
| 604 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " | 638 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " |
| 605 << "Not sending data because ssrc is unknown: " | 639 << "Not sending data because ssrc is unknown: " |
| 606 << params.ssrc; | 640 << params.ssrc; |
| 607 return false; | 641 return false; |
| 608 } | 642 } |
| 609 | 643 |
| 610 // | 644 // |
| 611 // Send data using SCTP. | 645 // Send data using SCTP. |
| 612 ssize_t send_res = 0; // result from usrsctp_sendv. | 646 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)."; | 744 << " len=" << buffer.size() << " before SetReceive(true)."; |
| 711 } | 745 } |
| 712 } | 746 } |
| 713 | 747 |
| 714 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { | 748 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { |
| 715 if (!stream.has_ssrcs()) { | 749 if (!stream.has_ssrcs()) { |
| 716 return false; | 750 return false; |
| 717 } | 751 } |
| 718 | 752 |
| 719 const uint32_t ssrc = stream.first_ssrc(); | 753 const uint32_t ssrc = stream.first_ssrc(); |
| 720 if (ssrc >= cricket::kMaxSctpSid) { | 754 if (ssrc >= kMaxSctpSid) { |
| 721 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " | 755 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " |
| 722 << "Not adding data stream '" << stream.id | 756 << "Not adding data stream '" << stream.id |
| 723 << "' with ssrc=" << ssrc | 757 << "' with ssrc=" << ssrc |
| 724 << " because stream ssrc is too high."; | 758 << " because stream ssrc is too high."; |
| 725 return false; | 759 return false; |
| 726 } else if (open_streams_.find(ssrc) != open_streams_.end()) { | 760 } else if (open_streams_.find(ssrc) != open_streams_.end()) { |
| 727 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " | 761 LOG(LS_WARNING) << debug_name_ << "->Add(Send|Recv)Stream(...): " |
| 728 << "Not adding data stream '" << stream.id | 762 << "Not adding data stream '" << stream.id |
| 729 << "' with ssrc=" << ssrc | 763 << "' with ssrc=" << ssrc |
| 730 << " because stream is already open."; | 764 << " because stream is already open."; |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1033 } | 1067 } |
| 1034 case MSG_SCTPOUTBOUNDPACKET: { | 1068 case MSG_SCTPOUTBOUNDPACKET: { |
| 1035 std::unique_ptr<OutboundPacketMessage> pdata( | 1069 std::unique_ptr<OutboundPacketMessage> pdata( |
| 1036 static_cast<OutboundPacketMessage*>(msg->pdata)); | 1070 static_cast<OutboundPacketMessage*>(msg->pdata)); |
| 1037 OnPacketFromSctpToNetwork(pdata->data().get()); | 1071 OnPacketFromSctpToNetwork(pdata->data().get()); |
| 1038 break; | 1072 break; |
| 1039 } | 1073 } |
| 1040 } | 1074 } |
| 1041 } | 1075 } |
| 1042 } // namespace cricket | 1076 } // namespace cricket |
| OLD | NEW |