Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(121)

Side by Side Diff: webrtc/media/sctp/sctpdataengine.cc

Issue 1995993002: Only initialize usrsctp when it's used and uninitialize when it's not being used. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Remove thread checker and add {}'s. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/media/sctp/sctpdataengine.h ('k') | webrtc/media/sctp/sctpdataengine_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « webrtc/media/sctp/sctpdataengine.h ('k') | webrtc/media/sctp/sctpdataengine_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698