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/buffer.h" | 22 #include "webrtc/base/copyonwritebuffer.h" |
23 #include "webrtc/base/helpers.h" | 23 #include "webrtc/base/helpers.h" |
24 #include "webrtc/base/logging.h" | 24 #include "webrtc/base/logging.h" |
25 #include "webrtc/base/numerics/safe_conversions.h" | 25 #include "webrtc/base/numerics/safe_conversions.h" |
26 #include "webrtc/media/base/codec.h" | 26 #include "webrtc/media/base/codec.h" |
27 #include "webrtc/media/base/mediaconstants.h" | 27 #include "webrtc/media/base/mediaconstants.h" |
28 #include "webrtc/media/base/streamparams.h" | 28 #include "webrtc/media/base/streamparams.h" |
29 | 29 |
30 namespace { | 30 namespace { |
31 typedef cricket::SctpDataMediaChannel::StreamSet StreamSet; | 31 typedef cricket::SctpDataMediaChannel::StreamSet StreamSet; |
32 // Returns a comma-separated, human-readable list of the stream IDs in 's' | 32 // Returns a comma-separated, human-readable list of the stream IDs in 's' |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 } else { | 82 } else { |
83 result << array[i]; | 83 result << array[i]; |
84 } | 84 } |
85 } | 85 } |
86 return result.str(); | 86 return result.str(); |
87 } | 87 } |
88 } // namespace | 88 } // namespace |
89 | 89 |
90 namespace cricket { | 90 namespace cricket { |
91 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; | 91 typedef rtc::ScopedMessageData<SctpInboundPacket> InboundPacketMessage; |
92 typedef rtc::ScopedMessageData<rtc::Buffer> OutboundPacketMessage; | 92 typedef rtc::ScopedMessageData<rtc::CopyOnWriteBuffer> OutboundPacketMessage; |
93 | 93 |
94 // The biggest SCTP packet. Starting from a 'safe' wire MTU value of 1280, | 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. | 95 // take off 80 bytes for DTLS/TURN/TCP/IP overhead. |
96 static const size_t kSctpMtu = 1200; | 96 static const size_t kSctpMtu = 1200; |
97 | 97 |
98 // The size of the SCTP association send buffer. 256kB, the usrsctp default. | 98 // The size of the SCTP association send buffer. 256kB, the usrsctp default. |
99 static const int kSendBufferSize = 262144; | 99 static const int kSendBufferSize = 262144; |
100 enum { | 100 enum { |
101 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket | 101 MSG_SCTPINBOUNDPACKET = 1, // MessageData is SctpInboundPacket |
102 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer | 102 MSG_SCTPOUTBOUNDPACKET = 2, // MessageData is rtc:Buffer |
103 }; | 103 }; |
104 | 104 |
105 struct SctpInboundPacket { | 105 struct SctpInboundPacket { |
106 rtc::Buffer buffer; | 106 rtc::CopyOnWriteBuffer buffer; |
107 ReceiveDataParams params; | 107 ReceiveDataParams params; |
108 // The |flags| parameter is used by SCTP to distinguish notification packets | 108 // The |flags| parameter is used by SCTP to distinguish notification packets |
109 // from other types of packets. | 109 // from other types of packets. |
110 int flags; | 110 int flags; |
111 }; | 111 }; |
112 | 112 |
113 // Helper for logging SCTP messages. | 113 // Helper for logging SCTP messages. |
114 static void debug_sctp_printf(const char *format, ...) { | 114 static void debug_sctp_printf(const char *format, ...) { |
115 char s[255]; | 115 char s[255]; |
116 va_list ap; | 116 va_list ap; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 case SctpDataMediaChannel::PPID_NONE: | 158 case SctpDataMediaChannel::PPID_NONE: |
159 *dest = cricket::DMT_NONE; | 159 *dest = cricket::DMT_NONE; |
160 return true; | 160 return true; |
161 | 161 |
162 default: | 162 default: |
163 return false; | 163 return false; |
164 } | 164 } |
165 } | 165 } |
166 | 166 |
167 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. | 167 // Log the packet in text2pcap format, if log level is at LS_VERBOSE. |
168 static void VerboseLogPacket(void *data, size_t length, int direction) { | 168 static void VerboseLogPacket(const void *data, size_t length, int direction) { |
169 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { | 169 if (LOG_CHECK_LEVEL(LS_VERBOSE) && length > 0) { |
170 char *dump_buf; | 170 char *dump_buf; |
171 if ((dump_buf = usrsctp_dumppacket( | 171 if ((dump_buf = usrsctp_dumppacket( |
172 data, length, direction)) != NULL) { | 172 data, length, direction)) != NULL) { |
173 LOG(LS_VERBOSE) << dump_buf; | 173 LOG(LS_VERBOSE) << dump_buf; |
174 usrsctp_freedumpbuffer(dump_buf); | 174 usrsctp_freedumpbuffer(dump_buf); |
175 } | 175 } |
176 } | 176 } |
177 } | 177 } |
178 | 178 |
179 // This is the callback usrsctp uses when there's data to send on the network | 179 // This is the callback usrsctp uses when there's data to send on the network |
180 // that has been wrapped appropriatly for the SCTP protocol. | 180 // that has been wrapped appropriatly for the SCTP protocol. |
181 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, | 181 static int OnSctpOutboundPacket(void* addr, void* data, size_t length, |
182 uint8_t tos, uint8_t set_df) { | 182 uint8_t tos, uint8_t set_df) { |
183 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); | 183 SctpDataMediaChannel* channel = static_cast<SctpDataMediaChannel*>(addr); |
184 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" | 184 LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():" |
185 << "addr: " << addr << "; length: " << length | 185 << "addr: " << addr << "; length: " << length |
186 << "; tos: " << std::hex << static_cast<int>(tos) | 186 << "; tos: " << std::hex << static_cast<int>(tos) |
187 << "; set_df: " << std::hex << static_cast<int>(set_df); | 187 << "; set_df: " << std::hex << static_cast<int>(set_df); |
188 | 188 |
189 VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND); | 189 VerboseLogPacket(addr, length, SCTP_DUMP_OUTBOUND); |
190 // Note: We have to copy the data; the caller will delete it. | 190 // Note: We have to copy the data; the caller will delete it. |
191 auto* msg = new OutboundPacketMessage( | 191 auto* msg = new OutboundPacketMessage( |
192 new rtc::Buffer(reinterpret_cast<uint8_t*>(data), length)); | 192 new rtc::CopyOnWriteBuffer(reinterpret_cast<uint8_t*>(data), length)); |
193 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); | 193 channel->worker_thread()->Post(channel, MSG_SCTPOUTBOUNDPACKET, msg); |
194 return 0; | 194 return 0; |
195 } | 195 } |
196 | 196 |
197 // This is the callback called from usrsctp when data has been received, after | 197 // This is the callback called from usrsctp when data has been received, after |
198 // a packet has been interpreted and parsed by usrsctp and found to contain | 198 // a packet has been interpreted and parsed by usrsctp and found to contain |
199 // payload data. It is called by a usrsctp thread. It is assumed this function | 199 // payload data. It is called by a usrsctp thread. It is assumed this function |
200 // will free the memory used by 'data'. | 200 // will free the memory used by 'data'. |
201 static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr, | 201 static int OnSctpInboundPacket(struct socket* sock, union sctp_sockstore addr, |
202 void* data, size_t length, | 202 void* data, size_t length, |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 | 574 |
575 bool SctpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) { | 575 bool SctpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) { |
576 // SCTP DataChannels are always bi-directional and calling RemoveSendStream | 576 // SCTP DataChannels are always bi-directional and calling RemoveSendStream |
577 // will disable both sending and receiving on the stream. So RemoveRecvStream | 577 // will disable both sending and receiving on the stream. So RemoveRecvStream |
578 // is a no-op. | 578 // is a no-op. |
579 return true; | 579 return true; |
580 } | 580 } |
581 | 581 |
582 bool SctpDataMediaChannel::SendData( | 582 bool SctpDataMediaChannel::SendData( |
583 const SendDataParams& params, | 583 const SendDataParams& params, |
584 const rtc::Buffer& payload, | 584 const rtc::CopyOnWriteBuffer& payload, |
585 SendDataResult* result) { | 585 SendDataResult* result) { |
586 if (result) { | 586 if (result) { |
587 // Preset |result| to assume an error. If SendData succeeds, we'll | 587 // Preset |result| to assume an error. If SendData succeeds, we'll |
588 // overwrite |*result| once more at the end. | 588 // overwrite |*result| once more at the end. |
589 *result = SDR_ERROR; | 589 *result = SDR_ERROR; |
590 } | 590 } |
591 | 591 |
592 if (!sending_) { | 592 if (!sending_) { |
593 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " | 593 LOG(LS_WARNING) << debug_name_ << "->SendData(...): " |
594 << "Not sending packet with ssrc=" << params.ssrc | 594 << "Not sending packet with ssrc=" << params.ssrc |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 } | 644 } |
645 if (result) { | 645 if (result) { |
646 // Only way out now is success. | 646 // Only way out now is success. |
647 *result = SDR_SUCCESS; | 647 *result = SDR_SUCCESS; |
648 } | 648 } |
649 return true; | 649 return true; |
650 } | 650 } |
651 | 651 |
652 // Called by network interface when a packet has been received. | 652 // Called by network interface when a packet has been received. |
653 void SctpDataMediaChannel::OnPacketReceived( | 653 void SctpDataMediaChannel::OnPacketReceived( |
654 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { | 654 rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) { |
655 RTC_DCHECK(rtc::Thread::Current() == worker_thread_); | 655 RTC_DCHECK(rtc::Thread::Current() == worker_thread_); |
656 LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): " | 656 LOG(LS_VERBOSE) << debug_name_ << "->OnPacketReceived(...): " |
657 << " length=" << packet->size() << ", sending: " << sending_; | 657 << " length=" << packet->size() << ", sending: " << sending_; |
658 // Only give receiving packets to usrsctp after if connected. This enables two | 658 // Only give receiving packets to usrsctp after if connected. This enables two |
659 // peers to each make a connect call, but for them not to receive an INIT | 659 // peers to each make a connect call, but for them not to receive an INIT |
660 // packet before they have called connect; least the last receiver of the INIT | 660 // packet before they have called connect; least the last receiver of the INIT |
661 // packet will have called connect, and a connection will be established. | 661 // packet will have called connect, and a connection will be established. |
662 if (sending_) { | 662 if (sending_) { |
663 // Pass received packet to SCTP stack. Once processed by usrsctp, the data | 663 // Pass received packet to SCTP stack. Once processed by usrsctp, the data |
664 // will be will be given to the global OnSctpInboundData, and then, | 664 // will be will be given to the global OnSctpInboundData, and then, |
665 // marshalled by a Post and handled with OnMessage. | 665 // marshalled by a Post and handled with OnMessage. |
666 VerboseLogPacket(packet->data(), packet->size(), SCTP_DUMP_INBOUND); | 666 VerboseLogPacket(packet->cdata(), packet->size(), SCTP_DUMP_INBOUND); |
667 usrsctp_conninput(this, packet->data(), packet->size(), 0); | 667 usrsctp_conninput(this, packet->cdata(), packet->size(), 0); |
668 } else { | 668 } else { |
669 // TODO(ldixon): Consider caching the packet for very slightly better | 669 // TODO(ldixon): Consider caching the packet for very slightly better |
670 // reliability. | 670 // reliability. |
671 } | 671 } |
672 } | 672 } |
673 | 673 |
674 void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel( | 674 void SctpDataMediaChannel::OnInboundPacketFromSctpToChannel( |
675 SctpInboundPacket* packet) { | 675 SctpInboundPacket* packet) { |
676 LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): " | 676 LOG(LS_VERBOSE) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): " |
677 << "Received SCTP data:" | 677 << "Received SCTP data:" |
678 << " ssrc=" << packet->params.ssrc | 678 << " ssrc=" << packet->params.ssrc |
679 << " notification: " << (packet->flags & MSG_NOTIFICATION) | 679 << " notification: " << (packet->flags & MSG_NOTIFICATION) |
680 << " length=" << packet->buffer.size(); | 680 << " length=" << packet->buffer.size(); |
681 // Sending a packet with data == NULL (no data) is SCTPs "close the | 681 // Sending a packet with data == NULL (no data) is SCTPs "close the |
682 // connection" message. This sets sock_ = NULL; | 682 // connection" message. This sets sock_ = NULL; |
683 if (!packet->buffer.size() || !packet->buffer.data()) { | 683 if (!packet->buffer.size() || !packet->buffer.data()) { |
684 LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): " | 684 LOG(LS_INFO) << debug_name_ << "->OnInboundPacketFromSctpToChannel(...): " |
685 "No data, closing."; | 685 "No data, closing."; |
686 return; | 686 return; |
687 } | 687 } |
688 if (packet->flags & MSG_NOTIFICATION) { | 688 if (packet->flags & MSG_NOTIFICATION) { |
689 OnNotificationFromSctp(&packet->buffer); | 689 OnNotificationFromSctp(packet->buffer); |
690 } else { | 690 } else { |
691 OnDataFromSctpToChannel(packet->params, &packet->buffer); | 691 OnDataFromSctpToChannel(packet->params, packet->buffer); |
692 } | 692 } |
693 } | 693 } |
694 | 694 |
695 void SctpDataMediaChannel::OnDataFromSctpToChannel( | 695 void SctpDataMediaChannel::OnDataFromSctpToChannel( |
696 const ReceiveDataParams& params, rtc::Buffer* buffer) { | 696 const ReceiveDataParams& params, const rtc::CopyOnWriteBuffer& buffer) { |
697 if (receiving_) { | 697 if (receiving_) { |
698 LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): " | 698 LOG(LS_VERBOSE) << debug_name_ << "->OnDataFromSctpToChannel(...): " |
699 << "Posting with length: " << buffer->size() | 699 << "Posting with length: " << buffer.size() |
700 << " on stream " << params.ssrc; | 700 << " on stream " << params.ssrc; |
701 // Reports all received messages to upper layers, no matter whether the sid | 701 // Reports all received messages to upper layers, no matter whether the sid |
702 // is known. | 702 // is known. |
703 SignalDataReceived(params, buffer->data<char>(), buffer->size()); | 703 SignalDataReceived(params, buffer.data<char>(), buffer.size()); |
704 } else { | 704 } else { |
705 LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): " | 705 LOG(LS_WARNING) << debug_name_ << "->OnDataFromSctpToChannel(...): " |
706 << "Not receiving packet with sid=" << params.ssrc | 706 << "Not receiving packet with sid=" << params.ssrc |
707 << " len=" << buffer->size() << " before SetReceive(true)."; | 707 << " len=" << buffer.size() << " before SetReceive(true)."; |
708 } | 708 } |
709 } | 709 } |
710 | 710 |
711 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { | 711 bool SctpDataMediaChannel::AddStream(const StreamParams& stream) { |
712 if (!stream.has_ssrcs()) { | 712 if (!stream.has_ssrcs()) { |
713 return false; | 713 return false; |
714 } | 714 } |
715 | 715 |
716 const uint32_t ssrc = stream.first_ssrc(); | 716 const uint32_t ssrc = stream.first_ssrc(); |
717 if (ssrc >= cricket::kMaxSctpSid) { | 717 if (ssrc >= cricket::kMaxSctpSid) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 // SendQueuedStreamResets(). | 760 // SendQueuedStreamResets(). |
761 queued_reset_streams_.insert(ssrc); | 761 queued_reset_streams_.insert(ssrc); |
762 | 762 |
763 // Signal our stream-reset logic that it should try to send now, if it can. | 763 // Signal our stream-reset logic that it should try to send now, if it can. |
764 SendQueuedStreamResets(); | 764 SendQueuedStreamResets(); |
765 | 765 |
766 // The stream will actually get removed when we get the acknowledgment. | 766 // The stream will actually get removed when we get the acknowledgment. |
767 return true; | 767 return true; |
768 } | 768 } |
769 | 769 |
770 void SctpDataMediaChannel::OnNotificationFromSctp(rtc::Buffer* buffer) { | 770 void SctpDataMediaChannel::OnNotificationFromSctp( |
| 771 const rtc::CopyOnWriteBuffer& buffer) { |
771 const sctp_notification& notification = | 772 const sctp_notification& notification = |
772 reinterpret_cast<const sctp_notification&>(*buffer->data()); | 773 reinterpret_cast<const sctp_notification&>(*buffer.data()); |
773 ASSERT(notification.sn_header.sn_length == buffer->size()); | 774 ASSERT(notification.sn_header.sn_length == buffer.size()); |
774 | 775 |
775 // TODO(ldixon): handle notifications appropriately. | 776 // TODO(ldixon): handle notifications appropriately. |
776 switch (notification.sn_header.sn_type) { | 777 switch (notification.sn_header.sn_type) { |
777 case SCTP_ASSOC_CHANGE: | 778 case SCTP_ASSOC_CHANGE: |
778 LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE"; | 779 LOG(LS_VERBOSE) << "SCTP_ASSOC_CHANGE"; |
779 OnNotificationAssocChange(notification.sn_assoc_change); | 780 OnNotificationAssocChange(notification.sn_assoc_change); |
780 break; | 781 break; |
781 case SCTP_REMOTE_ERROR: | 782 case SCTP_REMOTE_ERROR: |
782 LOG(LS_INFO) << "SCTP_REMOTE_ERROR"; | 783 LOG(LS_INFO) << "SCTP_REMOTE_ERROR"; |
783 break; | 784 break; |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
956 &remote_port_); | 957 &remote_port_); |
957 } | 958 } |
958 | 959 |
959 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { | 960 bool SctpDataMediaChannel::SetRecvCodecs(const std::vector<DataCodec>& codecs) { |
960 return GetCodecIntParameter( | 961 return GetCodecIntParameter( |
961 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, | 962 codecs, kGoogleSctpDataCodecId, kGoogleSctpDataCodecName, kCodecParamPort, |
962 &local_port_); | 963 &local_port_); |
963 } | 964 } |
964 | 965 |
965 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( | 966 void SctpDataMediaChannel::OnPacketFromSctpToNetwork( |
966 rtc::Buffer* buffer) { | 967 rtc::CopyOnWriteBuffer* buffer) { |
967 // usrsctp seems to interpret the MTU we give it strangely -- it seems to | 968 // usrsctp seems to interpret the MTU we give it strangely -- it seems to |
968 // give us back packets bigger than that MTU, if only by a fixed amount. | 969 // give us back packets bigger than that MTU, if only by a fixed amount. |
969 // This is that amount that we've observed. | 970 // This is that amount that we've observed. |
970 const int kSctpOverhead = 76; | 971 const int kSctpOverhead = 76; |
971 if (buffer->size() > (kSctpOverhead + kSctpMtu)) { | 972 if (buffer->size() > (kSctpOverhead + kSctpMtu)) { |
972 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " | 973 LOG(LS_ERROR) << debug_name_ << "->OnPacketFromSctpToNetwork(...): " |
973 << "SCTP seems to have made a packet that is bigger " | 974 << "SCTP seems to have made a packet that is bigger " |
974 << "than its official MTU: " << buffer->size() | 975 << "than its official MTU: " << buffer->size() |
975 << " vs max of " << kSctpMtu | 976 << " vs max of " << kSctpMtu |
976 << " even after adding " << kSctpOverhead | 977 << " even after adding " << kSctpOverhead |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 } | 1030 } |
1030 case MSG_SCTPOUTBOUNDPACKET: { | 1031 case MSG_SCTPOUTBOUNDPACKET: { |
1031 std::unique_ptr<OutboundPacketMessage> pdata( | 1032 std::unique_ptr<OutboundPacketMessage> pdata( |
1032 static_cast<OutboundPacketMessage*>(msg->pdata)); | 1033 static_cast<OutboundPacketMessage*>(msg->pdata)); |
1033 OnPacketFromSctpToNetwork(pdata->data().get()); | 1034 OnPacketFromSctpToNetwork(pdata->data().get()); |
1034 break; | 1035 break; |
1035 } | 1036 } |
1036 } | 1037 } |
1037 } | 1038 } |
1038 } // namespace cricket | 1039 } // namespace cricket |
OLD | NEW |