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

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

Issue 1304063006: (try 2) Added send-thresholding and fixed text packet dumping (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Post tommi@ comments. Created 5 years, 3 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 | « talk/media/sctp/sctpdataengine.h ('k') | talk/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 * libjingle 2 * libjingle
3 * Copyright 2012 Google Inc. and Robin Seggelmann 3 * Copyright 2012 Google Inc. and Robin Seggelmann
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 } // namespace 102 } // namespace
103 103
104 namespace cricket { 104 namespace cricket {
105 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; 105 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage;
106 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage; 106 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage;
107 107
108 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, 108 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280,
109 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. 109 // take off 80 bytes for DTLS/TURN/TCP/IP overhead.
110 static const size_t kSctpMtu = 1200; 110 static const size_t kSctpMtu = 1200;
111 111
112 // The size of the SCTP association send buffer. 256kB, the usrsctp default.
113 static const int kSendBufferSize = 262144;
112 enum { 114 enum {
113 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket 115 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket
114 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer 116 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer
115 }; 117 };
116 118
117 struct SctpInboundPacket { 119 struct SctpInboundPacket {
118 rtc::Buffer buffer; 120 rtc::Buffer buffer;
119 ReceiveDataParams params; 121 ReceiveDataParams params;
120 // The |flags| parameter is used by SCTP to distinguish notification packets 122 // The |flags| parameter is used by SCTP to distinguish notification packets
121 // from other types of packets. 123 // from other types of packets.
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 case SctpDataMediaChannel::PPID_NONE: 172 case SctpDataMediaChannel::PPID_NONE:
171 *dest = cricket::DMT_NONE; 173 *dest = cricket::DMT_NONE;
172 return true; 174 return true;
173 175
174 default: 176 default:
175 return false; 177 return false;
176 } 178 }
177 } 179 }
178 180
179 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. 181 // Log the packet in text2pcap format, if log level is at LS_VERBOSE.
180 static void VerboseLogPacket(void *addr, size_t length, int direction) { 182 static void VerboseLogPacket(void *data, size_t length, int direction) {
181 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { 183 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) {
182 char *dump_buf; 184 char *dump_buf;
183 if ((dump_buf = usrsctp_dumppacket( 185 if ((dump_buf = usrsctp_dumppacket(
184 addr, length, direction)) != NULL) { 186 data, length, direction)) != NULL) {
185 LOG(LS_VERBOSE) << dump_buf; 187 LOG(LS_VERBOSE) << dump_buf;
186 usrsctp_freedumpbuffer(dump_buf); 188 usrsctp_freedumpbuffer(dump_buf);
187 } 189 }
188 } 190 }
189 } 191 }
190 192
191 // This is the callback usrsctp uses when there's data to send on the network 193 // This is the callback usrsctp uses when there's data to send on the network
192 // that has been wrapped appropriatly for the SCTP protocol. 194 // that has been wrapped appropriatly for the SCTP protocol.
193 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, 195 static int OnSctpOutboundPacket(void* addr, void* data, size_t length,
194 uint8_t tos, uint8_t set_df) { 196 uint8_t tos, uint8_t set_df) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 // AF_CONN use of sctp. 253 // AF_CONN use of sctp.
252 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf); 254 usrsctp_init(0, cricket::OnSctpOutboundPacket, debug_sctp_printf);
253 255
254 // To turn on/off detailed SCTP debugging. You will also need to have the 256 // To turn on/off detailed SCTP debugging. You will also need to have the
255 // SCTP_DEBUG cpp defines flag. 257 // SCTP_DEBUG cpp defines flag.
256 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL); 258 // usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
257 259
258 // TODO(ldixon): Consider turning this on/off. 260 // TODO(ldixon): Consider turning this on/off.
259 usrsctp_sysctl_set_sctp_ecn_enable(0); 261 usrsctp_sysctl_set_sctp_ecn_enable(0);
260 262
263 // This is harmless, but we should find out when the library default
tommi 2015/08/28 18:12:32 move to error scope?
lally1 2015/08/28 18:53:11 I changed the comment a little (s/happens/changes/
264 // happens.
265 int send_size = usrsctp_sysctl_get_sctp_sendspace();
266 if (send_size != kSendBufferSize) {
267 LOG(LS_ERROR) << "Got different send size than expected: " << send_size;
268 }
269
261 // TODO(ldixon): Consider turning this on/off. 270 // TODO(ldixon): Consider turning this on/off.
262 // This is not needed right now (we don't do dynamic address changes): 271 // This is not needed right now (we don't do dynamic address changes):
263 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically 272 // If SCTP Auto-ASCONF is enabled, the peer is informed automatically
264 // when a new address is added or removed. This feature is enabled by 273 // when a new address is added or removed. This feature is enabled by
265 // default. 274 // default.
266 // usrsctp_sysctl_set_sctp_auto_asconf(0); 275 // usrsctp_sysctl_set_sctp_auto_asconf(0);
267 276
268 // TODO(ldixon): Consider turning this on/off. 277 // TODO(ldixon): Consider turning this on/off.
269 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs 278 // Add a blackhole sysctl. Setting it to 1 results in no ABORTs
270 // being sent in response to INITs, setting it to 2 results 279 // being sent in response to INITs, setting it to 2 results
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 } 317 }
309 318
310 DataMediaChannel* SctpDataEngine::CreateChannel( 319 DataMediaChannel* SctpDataEngine::CreateChannel(
311 DataChannelType data_channel_type) { 320 DataChannelType data_channel_type) {
312 if (data_channel_type != DCT_SCTP) { 321 if (data_channel_type != DCT_SCTP) {
313 return NULL; 322 return NULL;
314 } 323 }
315 return new SctpDataMediaChannel(rtc::Thread::Current()); 324 return new SctpDataMediaChannel(rtc::Thread::Current());
316 } 325 }
317 326
327 // static
328 SctpDataMediaChannel* SctpDataEngine::GetChannelFromSocket(
329 struct socket* sock) {
330 struct sockaddr* addrs = nullptr;
331 int naddrs = usrsctp_getladdrs(sock, 0, &addrs);
332 DCHECK(naddrs > 0);
tommi 2015/08/28 18:12:32 Generally in chromium (the guidelines webrtc follo
pthatcher2 2015/08/28 18:36:59 if (naddrs < 0) { ASSERT(false); return nullpt
pthatcher2 2015/08/28 18:38:15 Actually, in this case, I'd rather not have GetCha
lally1 2015/08/28 18:53:11 I took out the DCHECKs and merged the if()s a bit.
333 if (naddrs < 0) {
334 return nullptr;
335 }
336 SctpDataMediaChannel* channel = nullptr;
337 if (naddrs > 0) {
pthatcher2 2015/08/28 18:40:44 Huh? Why check naddrs so many times? if (naddrs <
lally1 2015/08/28 18:53:11 Acknowledged.
338 // We only open AF_CONN sockets, and they should all have the
339 // sconn_addr set to the pointer that created them, so [0] is as good
340 // as any other.
341 DCHECK(addrs[0].sa_family == AF_CONN);
342 if (addrs[0].sa_family == AF_CONN) {
pthatcher2 2015/08/28 18:44:49 In this case, I'm fine with a DCHECK with no if st
lally1 2015/08/28 18:53:11 Acknowledged.
343 struct sockaddr_conn* sconn =
344 reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
tommi 2015/08/28 18:12:32 nit: 4 space indent
lally1 2015/08/28 18:53:11 Acknowledged.
345 channel = reinterpret_cast<SctpDataMediaChannel*>(sconn->sconn_addr);
346 }
347 usrsctp_freeladdrs(addrs);
pthatcher2 2015/08/28 18:44:49 Can you put a little comment about what this does?
348 }
349
350 return channel;
351 }
352
353 // static
354 int SctpDataEngine::SendThresholdCallback(struct socket* sock,
355 uint32_t sb_free) {
356 // Fired on our I/O thread. SctpDataMediaChannel::OnPacketReceived() gets
357 // a packet containing acknowledgments, which goes into usrsctp_conninput,
358 // and then back here.
tommi 2015/08/28 18:12:32 nice
359 SctpDataMediaChannel* channel = GetChannelFromSocket(sock);
360 if (!channel) {
361 LOG(LS_ERROR) << "SendThresholdCallback: Failed to get channel for socket "
362 << sock;
363 return 0;
364 }
365 channel->OnSendThresholdCallback();
366 return 0;
367 }
368
318 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread) 369 SctpDataMediaChannel::SctpDataMediaChannel(rtc::Thread* thread)
319 : worker_thread_(thread), 370 : worker_thread_(thread),
320 local_port_(kSctpDefaultPort), 371 local_port_(kSctpDefaultPort),
321 remote_port_(kSctpDefaultPort), 372 remote_port_(kSctpDefaultPort),
322 sock_(NULL), 373 sock_(NULL),
323 sending_(false), 374 sending_(false),
324 receiving_(false), 375 receiving_(false),
325 debug_name_("SctpDataMediaChannel") { 376 debug_name_("SctpDataMediaChannel") {
326 } 377 }
327 378
328 SctpDataMediaChannel::~SctpDataMediaChannel() { 379 SctpDataMediaChannel::~SctpDataMediaChannel() {
329 CloseSctpSocket(); 380 CloseSctpSocket();
330 } 381 }
331 382
383 void SctpDataMediaChannel::OnSendThresholdCallback() {
384 DCHECK(rtc::Thread::Current() == worker_thread_);
tommi 2015/08/28 18:12:32 thanks!
385 SignalReadyToSend(true);
386 }
387
332 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) { 388 sockaddr_conn SctpDataMediaChannel::GetSctpSockAddr(int port) {
333 sockaddr_conn sconn = {0}; 389 sockaddr_conn sconn = {0};
334 sconn.sconn_family = AF_CONN; 390 sconn.sconn_family = AF_CONN;
335 #ifdef HAVE_SCONN_LEN 391 #ifdef HAVE_SCONN_LEN
336 sconn.sconn_len = sizeof(sockaddr_conn); 392 sconn.sconn_len = sizeof(sockaddr_conn);
337 #endif 393 #endif
338 // Note: conversion from int to uint16_t happens here. 394 // Note: conversion from int to uint16_t happens here.
339 sconn.sconn_port = rtc::HostToNetwork16(port); 395 sconn.sconn_port = rtc::HostToNetwork16(port);
340 sconn.sconn_addr = this; 396 sconn.sconn_addr = this;
341 return sconn; 397 return sconn;
342 } 398 }
343 399
344 bool SctpDataMediaChannel::OpenSctpSocket() { 400 bool SctpDataMediaChannel::OpenSctpSocket() {
345 if (sock_) { 401 if (sock_) {
346 LOG(LS_VERBOSE) << debug_name_ 402 LOG(LS_VERBOSE) << debug_name_
347 << "->Ignoring attempt to re-create existing socket."; 403 << "->Ignoring attempt to re-create existing socket.";
348 return false; 404 return false;
349 } 405 }
406
407 // If kSendBufferSize isn't reflective of reality, we log an error, but we
408 // still have to do something reasonable here. Look up what the buffer's
409 // real size is and set our threshold to something reasonable.
410 const static int kSendThreshold = usrsctp_sysctl_get_sctp_sendspace() / 2;
411
350 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP, 412 sock_ = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
351 cricket::OnSctpInboundPacket, NULL, 0, this); 413 cricket::OnSctpInboundPacket,
414 &SctpDataEngine::SendThresholdCallback,
415 kSendThreshold, this);
352 if (!sock_) { 416 if (!sock_) {
353 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket."; 417 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to create SCTP socket.";
354 return false; 418 return false;
355 } 419 }
356 420
357 // Make the socket non-blocking. Connect, close, shutdown etc will not block 421 // Make the socket non-blocking. Connect, close, shutdown etc will not block
358 // the thread waiting for the socket operation to complete. 422 // the thread waiting for the socket operation to complete.
359 if (usrsctp_set_non_blocking(sock_, 1) < 0) { 423 if (usrsctp_set_non_blocking(sock_, 1) < 0) {
360 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking."; 424 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP to non blocking.";
361 return false; 425 return false;
(...skipping 24 matching lines...) Expand all
386 450
387 // Nagle. 451 // Nagle.
388 uint32_t nodelay = 1; 452 uint32_t nodelay = 1;
389 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, 453 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_NODELAY, &nodelay,
390 sizeof(nodelay))) { 454 sizeof(nodelay))) {
391 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY."; 455 LOG_ERRNO(LS_ERROR) << debug_name_ << "Failed to set SCTP_NODELAY.";
392 return false; 456 return false;
393 } 457 }
394 458
395 // Disable MTU discovery 459 // Disable MTU discovery
396 struct sctp_paddrparams params = {{0}}; 460 sctp_paddrparams params = {{0}};
397 params.spp_assoc_id = 0; 461 params.spp_assoc_id = 0;
398 params.spp_flags = SPP_PMTUD_DISABLE; 462 params.spp_flags = SPP_PMTUD_DISABLE;
399 params.spp_pathmtu = kSctpMtu; 463 params.spp_pathmtu = kSctpMtu;
400 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params, 464 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &params,
401 sizeof(params))) { 465 sizeof(params))) {
402 LOG_ERRNO(LS_ERROR) << debug_name_ 466 LOG_ERRNO(LS_ERROR) << debug_name_
403 << "Failed to set SCTP_PEER_ADDR_PARAMS."; 467 << "Failed to set SCTP_PEER_ADDR_PARAMS.";
404 return false; 468 return false;
405 } 469 }
406 470
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): " 665 LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): "
602 << " length=" << packet->size() << ", sending: " << sending_; 666 << " length=" << packet->size() << ", sending: " << sending_;
603 // Only give receiving packets to usrsctp after if connected. This enables two 667 // Only give receiving packets to usrsctp after if connected. This enables two
604 // peers to each make a connect call, but for them not to receive an INIT 668 // peers to each make a connect call, but for them not to receive an INIT
605 // packet before they have called connect; least the last receiver of the INIT 669 // packet before they have called connect; least the last receiver of the INIT
606 // packet will have called connect, and a connection will be established. 670 // packet will have called connect, and a connection will be established.
607 if (sending_) { 671 if (sending_) {
608 // Pass received packet to SCTP stack. Once processed by usrsctp, the data 672 // Pass received packet to SCTP stack. Once processed by usrsctp, the data
609 // will be will be given to the global OnSctpInboundData, and then, 673 // will be will be given to the global OnSctpInboundData, and then,
610 // marshalled by a Post and handled with OnMessage. 674 // marshalled by a Post and handled with OnMessage.
611 675 DCHECK(rtc::Thread::Current() == worker_thread_);
pthatcher2 2015/08/28 18:44:49 Why not just put this at the top of the method?
lally1 2015/08/28 18:53:11 Done.
612 VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND); 676 VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND);
613 usrsctp_conninput(this, packet->data(), packet->size(), 0); 677 usrsctp_conninput(this, packet->data(), packet->size(), 0);
614 } else { 678 } else {
615 // TODO(ldixon): Consider caching the packet for very slightly better 679 // TODO(ldixon): Consider caching the packet for very slightly better
616 // reliability. 680 // reliability.
617 } 681 }
618 } 682 }
619 683
620 void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel( 684 void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel(
621 SctpInboundPacket* packet) { 685 SctpInboundPacket* packet) {
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 } 961 }
898 962
899 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { 963 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) {
900 return GetCodecIntParameter( 964 return GetCodecIntParameter(
901 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, 965 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort,
902 &local_port_); 966 &local_port_);
903 } 967 }
904 968
905 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( 969 void SctpDataMediaChannel::OnPacketFromSctpToNetwork(
906 rtc::Buffer* buffer) { 970 rtc::Buffer* buffer) {
907 if (buffer->size() > kSctpMtu) { 971 // usrsctp seems to interpret the MTU we give it strangely -- it seems to
972 // give us back packets bigger than that MTU, if only by a fixed amount.
973 // This is that amount that we've observed.
974 const int kSctpOverhead = 76;
975 if (buffer->size() > (kSctpOverhead + kSctpMtu)) {
908 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " 976 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): "
909 << "SCTP seems to have made a packet that is bigger " 977 << "SCTP seems to have made a packet that is bigger "
910 "than its official MTU."; 978 << "than its official MTU: " << buffer->size()
979 << " vs max of " << kSctpMtu
980 << " even after adding " << kSctpOverhead
981 << " extra SCTP overhead";
911 } 982 }
912 MediaChannel::SendPacket(buffer); 983 MediaChannel::SendPacket(buffer);
913 } 984 }
914 985
915 bool SctpDataMediaChannel::SendQueuedStreamResets() { 986 bool SctpDataMediaChannel::SendQueuedStreamResets() {
916 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty()) 987 if (!sent_reset_streams_.empty() || queued_reset_streams_.empty())
917 return true; 988 return true;
918 989
919 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending [" 990 LOG(LS_VERBOSE) << "SendQueuedStreamResets[" << debug_name_ << "]: Sending ["
920 << ListStreams(queued_reset_streams_) << "], Open: [" 991 << ListStreams(queued_reset_streams_) << "], Open: ["
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
962 } 1033 }
963 case MSG_SCTPOUTBOUNDPACKET: { 1034 case MSG_SCTPOUTBOUNDPACKET: {
964 rtc::scoped_ptr<OutboundPacketMessage> pdata( 1035 rtc::scoped_ptr<OutboundPacketMessage> pdata(
965 static_cast<OutboundPacketMessage*>(msg->pdata)); 1036 static_cast<OutboundPacketMessage*>(msg->pdata));
966 OnPacketFromSctpToNetwork(pdata->data().get()); 1037 OnPacketFromSctpToNetwork(pdata->data().get());
967 break; 1038 break;
968 } 1039 }
969 } 1040 }
970 } 1041 }
971 } // namespace cricket 1042 } // namespace cricket
OLDNEW
« no previous file with comments | « talk/media/sctp/sctpdataengine.h ('k') | talk/media/sctp/sctpdataengine_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698