OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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, ¶ms, | 464 if (usrsctp_setsockopt(sock_, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |