xref: /aosp_15_r20/external/webrtc/pc/srtp_transport.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "pc/srtp_transport.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <string.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker #include <vector>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/match.h"
20*d9f75844SAndroid Build Coastguard Worker #include "media/base/rtp_utils.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_util.h"
22*d9f75844SAndroid Build Coastguard Worker #include "pc/rtp_transport.h"
23*d9f75844SAndroid Build Coastguard Worker #include "pc/srtp_session.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/async_packet_socket.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/copy_on_write_buffer.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/ssl_stream_adapter.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/third_party/base64/base64.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/zero_memory.h"
33*d9f75844SAndroid Build Coastguard Worker 
34*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
35*d9f75844SAndroid Build Coastguard Worker 
SrtpTransport(bool rtcp_mux_enabled,const FieldTrialsView & field_trials)36*d9f75844SAndroid Build Coastguard Worker SrtpTransport::SrtpTransport(bool rtcp_mux_enabled,
37*d9f75844SAndroid Build Coastguard Worker                              const FieldTrialsView& field_trials)
38*d9f75844SAndroid Build Coastguard Worker     : RtpTransport(rtcp_mux_enabled), field_trials_(field_trials) {}
39*d9f75844SAndroid Build Coastguard Worker 
SetSrtpSendKey(const cricket::CryptoParams & params)40*d9f75844SAndroid Build Coastguard Worker RTCError SrtpTransport::SetSrtpSendKey(const cricket::CryptoParams& params) {
41*d9f75844SAndroid Build Coastguard Worker   if (send_params_) {
42*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(
43*d9f75844SAndroid Build Coastguard Worker         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
44*d9f75844SAndroid Build Coastguard Worker         "Setting the SRTP send key twice is currently unsupported.");
45*d9f75844SAndroid Build Coastguard Worker   }
46*d9f75844SAndroid Build Coastguard Worker   if (recv_params_ && recv_params_->cipher_suite != params.cipher_suite) {
47*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(
48*d9f75844SAndroid Build Coastguard Worker         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
49*d9f75844SAndroid Build Coastguard Worker         "The send key and receive key must have the same cipher suite.");
50*d9f75844SAndroid Build Coastguard Worker   }
51*d9f75844SAndroid Build Coastguard Worker 
52*d9f75844SAndroid Build Coastguard Worker   send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
53*d9f75844SAndroid Build Coastguard Worker   if (*send_cipher_suite_ == rtc::kSrtpInvalidCryptoSuite) {
54*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
55*d9f75844SAndroid Build Coastguard Worker                     "Invalid SRTP crypto suite");
56*d9f75844SAndroid Build Coastguard Worker   }
57*d9f75844SAndroid Build Coastguard Worker 
58*d9f75844SAndroid Build Coastguard Worker   int send_key_len, send_salt_len;
59*d9f75844SAndroid Build Coastguard Worker   if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
60*d9f75844SAndroid Build Coastguard Worker                                      &send_salt_len)) {
61*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
62*d9f75844SAndroid Build Coastguard Worker                     "Could not get lengths for crypto suite(s):"
63*d9f75844SAndroid Build Coastguard Worker                     " send cipher_suite ");
64*d9f75844SAndroid Build Coastguard Worker   }
65*d9f75844SAndroid Build Coastguard Worker 
66*d9f75844SAndroid Build Coastguard Worker   send_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(send_key_len + send_salt_len);
67*d9f75844SAndroid Build Coastguard Worker   if (!ParseKeyParams(params.key_params, send_key_.data(), send_key_.size())) {
68*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
69*d9f75844SAndroid Build Coastguard Worker                     "Failed to parse the crypto key params");
70*d9f75844SAndroid Build Coastguard Worker   }
71*d9f75844SAndroid Build Coastguard Worker 
72*d9f75844SAndroid Build Coastguard Worker   if (!MaybeSetKeyParams()) {
73*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
74*d9f75844SAndroid Build Coastguard Worker                     "Failed to set the crypto key params");
75*d9f75844SAndroid Build Coastguard Worker   }
76*d9f75844SAndroid Build Coastguard Worker   send_params_ = params;
77*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
78*d9f75844SAndroid Build Coastguard Worker }
79*d9f75844SAndroid Build Coastguard Worker 
SetSrtpReceiveKey(const cricket::CryptoParams & params)80*d9f75844SAndroid Build Coastguard Worker RTCError SrtpTransport::SetSrtpReceiveKey(const cricket::CryptoParams& params) {
81*d9f75844SAndroid Build Coastguard Worker   if (recv_params_) {
82*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(
83*d9f75844SAndroid Build Coastguard Worker         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
84*d9f75844SAndroid Build Coastguard Worker         "Setting the SRTP send key twice is currently unsupported.");
85*d9f75844SAndroid Build Coastguard Worker   }
86*d9f75844SAndroid Build Coastguard Worker   if (send_params_ && send_params_->cipher_suite != params.cipher_suite) {
87*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(
88*d9f75844SAndroid Build Coastguard Worker         webrtc::RTCErrorType::UNSUPPORTED_OPERATION,
89*d9f75844SAndroid Build Coastguard Worker         "The send key and receive key must have the same cipher suite.");
90*d9f75844SAndroid Build Coastguard Worker   }
91*d9f75844SAndroid Build Coastguard Worker 
92*d9f75844SAndroid Build Coastguard Worker   recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(params.cipher_suite);
93*d9f75844SAndroid Build Coastguard Worker   if (*recv_cipher_suite_ == rtc::kSrtpInvalidCryptoSuite) {
94*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
95*d9f75844SAndroid Build Coastguard Worker                     "Invalid SRTP crypto suite");
96*d9f75844SAndroid Build Coastguard Worker   }
97*d9f75844SAndroid Build Coastguard Worker 
98*d9f75844SAndroid Build Coastguard Worker   int recv_key_len, recv_salt_len;
99*d9f75844SAndroid Build Coastguard Worker   if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
100*d9f75844SAndroid Build Coastguard Worker                                      &recv_salt_len)) {
101*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
102*d9f75844SAndroid Build Coastguard Worker                     "Could not get lengths for crypto suite(s):"
103*d9f75844SAndroid Build Coastguard Worker                     " recv cipher_suite ");
104*d9f75844SAndroid Build Coastguard Worker   }
105*d9f75844SAndroid Build Coastguard Worker 
106*d9f75844SAndroid Build Coastguard Worker   recv_key_ = rtc::ZeroOnFreeBuffer<uint8_t>(recv_key_len + recv_salt_len);
107*d9f75844SAndroid Build Coastguard Worker   if (!ParseKeyParams(params.key_params, recv_key_.data(), recv_key_.size())) {
108*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
109*d9f75844SAndroid Build Coastguard Worker                     "Failed to parse the crypto key params");
110*d9f75844SAndroid Build Coastguard Worker   }
111*d9f75844SAndroid Build Coastguard Worker 
112*d9f75844SAndroid Build Coastguard Worker   if (!MaybeSetKeyParams()) {
113*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
114*d9f75844SAndroid Build Coastguard Worker                     "Failed to set the crypto key params");
115*d9f75844SAndroid Build Coastguard Worker   }
116*d9f75844SAndroid Build Coastguard Worker   recv_params_ = params;
117*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker 
SendRtpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)120*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
121*d9f75844SAndroid Build Coastguard Worker                                   const rtc::PacketOptions& options,
122*d9f75844SAndroid Build Coastguard Worker                                   int flags) {
123*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
124*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR)
125*d9f75844SAndroid Build Coastguard Worker         << "Failed to send the packet because SRTP transport is inactive.";
126*d9f75844SAndroid Build Coastguard Worker     return false;
127*d9f75844SAndroid Build Coastguard Worker   }
128*d9f75844SAndroid Build Coastguard Worker   rtc::PacketOptions updated_options = options;
129*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "SRTP Encode");
130*d9f75844SAndroid Build Coastguard Worker   bool res;
131*d9f75844SAndroid Build Coastguard Worker   uint8_t* data = packet->MutableData();
132*d9f75844SAndroid Build Coastguard Worker   int len = rtc::checked_cast<int>(packet->size());
133*d9f75844SAndroid Build Coastguard Worker // If ENABLE_EXTERNAL_AUTH flag is on then packet authentication is not done
134*d9f75844SAndroid Build Coastguard Worker // inside libsrtp for a RTP packet. A external HMAC module will be writing
135*d9f75844SAndroid Build Coastguard Worker // a fake HMAC value. This is ONLY done for a RTP packet.
136*d9f75844SAndroid Build Coastguard Worker // Socket layer will update rtp sendtime extension header if present in
137*d9f75844SAndroid Build Coastguard Worker // packet with current time before updating the HMAC.
138*d9f75844SAndroid Build Coastguard Worker #if !defined(ENABLE_EXTERNAL_AUTH)
139*d9f75844SAndroid Build Coastguard Worker   res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
140*d9f75844SAndroid Build Coastguard Worker #else
141*d9f75844SAndroid Build Coastguard Worker   if (!IsExternalAuthActive()) {
142*d9f75844SAndroid Build Coastguard Worker     res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len);
143*d9f75844SAndroid Build Coastguard Worker   } else {
144*d9f75844SAndroid Build Coastguard Worker     updated_options.packet_time_params.rtp_sendtime_extension_id =
145*d9f75844SAndroid Build Coastguard Worker         rtp_abs_sendtime_extn_id_;
146*d9f75844SAndroid Build Coastguard Worker     res = ProtectRtp(data, len, static_cast<int>(packet->capacity()), &len,
147*d9f75844SAndroid Build Coastguard Worker                      &updated_options.packet_time_params.srtp_packet_index);
148*d9f75844SAndroid Build Coastguard Worker     // If protection succeeds, let's get auth params from srtp.
149*d9f75844SAndroid Build Coastguard Worker     if (res) {
150*d9f75844SAndroid Build Coastguard Worker       uint8_t* auth_key = nullptr;
151*d9f75844SAndroid Build Coastguard Worker       int key_len = 0;
152*d9f75844SAndroid Build Coastguard Worker       res = GetRtpAuthParams(
153*d9f75844SAndroid Build Coastguard Worker           &auth_key, &key_len,
154*d9f75844SAndroid Build Coastguard Worker           &updated_options.packet_time_params.srtp_auth_tag_len);
155*d9f75844SAndroid Build Coastguard Worker       if (res) {
156*d9f75844SAndroid Build Coastguard Worker         updated_options.packet_time_params.srtp_auth_key.resize(key_len);
157*d9f75844SAndroid Build Coastguard Worker         updated_options.packet_time_params.srtp_auth_key.assign(
158*d9f75844SAndroid Build Coastguard Worker             auth_key, auth_key + key_len);
159*d9f75844SAndroid Build Coastguard Worker       }
160*d9f75844SAndroid Build Coastguard Worker     }
161*d9f75844SAndroid Build Coastguard Worker   }
162*d9f75844SAndroid Build Coastguard Worker #endif
163*d9f75844SAndroid Build Coastguard Worker   if (!res) {
164*d9f75844SAndroid Build Coastguard Worker     uint16_t seq_num = ParseRtpSequenceNumber(*packet);
165*d9f75844SAndroid Build Coastguard Worker     uint32_t ssrc = ParseRtpSsrc(*packet);
166*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to protect RTP packet: size=" << len
167*d9f75844SAndroid Build Coastguard Worker                       << ", seqnum=" << seq_num << ", SSRC=" << ssrc;
168*d9f75844SAndroid Build Coastguard Worker     return false;
169*d9f75844SAndroid Build Coastguard Worker   }
170*d9f75844SAndroid Build Coastguard Worker 
171*d9f75844SAndroid Build Coastguard Worker   // Update the length of the packet now that we've added the auth tag.
172*d9f75844SAndroid Build Coastguard Worker   packet->SetSize(len);
173*d9f75844SAndroid Build Coastguard Worker   return SendPacket(/*rtcp=*/false, packet, updated_options, flags);
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker 
SendRtcpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)176*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
177*d9f75844SAndroid Build Coastguard Worker                                    const rtc::PacketOptions& options,
178*d9f75844SAndroid Build Coastguard Worker                                    int flags) {
179*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
180*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR)
181*d9f75844SAndroid Build Coastguard Worker         << "Failed to send the packet because SRTP transport is inactive.";
182*d9f75844SAndroid Build Coastguard Worker     return false;
183*d9f75844SAndroid Build Coastguard Worker   }
184*d9f75844SAndroid Build Coastguard Worker 
185*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "SRTP Encode");
186*d9f75844SAndroid Build Coastguard Worker   uint8_t* data = packet->MutableData();
187*d9f75844SAndroid Build Coastguard Worker   int len = rtc::checked_cast<int>(packet->size());
188*d9f75844SAndroid Build Coastguard Worker   if (!ProtectRtcp(data, len, static_cast<int>(packet->capacity()), &len)) {
189*d9f75844SAndroid Build Coastguard Worker     int type = -1;
190*d9f75844SAndroid Build Coastguard Worker     cricket::GetRtcpType(data, len, &type);
191*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to protect RTCP packet: size=" << len
192*d9f75844SAndroid Build Coastguard Worker                       << ", type=" << type;
193*d9f75844SAndroid Build Coastguard Worker     return false;
194*d9f75844SAndroid Build Coastguard Worker   }
195*d9f75844SAndroid Build Coastguard Worker   // Update the length of the packet now that we've added the auth tag.
196*d9f75844SAndroid Build Coastguard Worker   packet->SetSize(len);
197*d9f75844SAndroid Build Coastguard Worker 
198*d9f75844SAndroid Build Coastguard Worker   return SendPacket(/*rtcp=*/true, packet, options, flags);
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker 
OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)201*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnRtpPacketReceived(rtc::CopyOnWriteBuffer packet,
202*d9f75844SAndroid Build Coastguard Worker                                         int64_t packet_time_us) {
203*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "SrtpTransport::OnRtpPacketReceived");
204*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
205*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
206*d9f75844SAndroid Build Coastguard Worker         << "Inactive SRTP transport received an RTP packet. Drop it.";
207*d9f75844SAndroid Build Coastguard Worker     return;
208*d9f75844SAndroid Build Coastguard Worker   }
209*d9f75844SAndroid Build Coastguard Worker   char* data = packet.MutableData<char>();
210*d9f75844SAndroid Build Coastguard Worker   int len = rtc::checked_cast<int>(packet.size());
211*d9f75844SAndroid Build Coastguard Worker   if (!UnprotectRtp(data, len, &len)) {
212*d9f75844SAndroid Build Coastguard Worker     // Limit the error logging to avoid excessive logs when there are lots of
213*d9f75844SAndroid Build Coastguard Worker     // bad packets.
214*d9f75844SAndroid Build Coastguard Worker     const int kFailureLogThrottleCount = 100;
215*d9f75844SAndroid Build Coastguard Worker     if (decryption_failure_count_ % kFailureLogThrottleCount == 0) {
216*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Failed to unprotect RTP packet: size=" << len
217*d9f75844SAndroid Build Coastguard Worker                         << ", seqnum=" << ParseRtpSequenceNumber(packet)
218*d9f75844SAndroid Build Coastguard Worker                         << ", SSRC=" << ParseRtpSsrc(packet)
219*d9f75844SAndroid Build Coastguard Worker                         << ", previous failure count: "
220*d9f75844SAndroid Build Coastguard Worker                         << decryption_failure_count_;
221*d9f75844SAndroid Build Coastguard Worker     }
222*d9f75844SAndroid Build Coastguard Worker     ++decryption_failure_count_;
223*d9f75844SAndroid Build Coastguard Worker     return;
224*d9f75844SAndroid Build Coastguard Worker   }
225*d9f75844SAndroid Build Coastguard Worker   packet.SetSize(len);
226*d9f75844SAndroid Build Coastguard Worker   DemuxPacket(std::move(packet), packet_time_us);
227*d9f75844SAndroid Build Coastguard Worker }
228*d9f75844SAndroid Build Coastguard Worker 
OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,int64_t packet_time_us)229*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnRtcpPacketReceived(rtc::CopyOnWriteBuffer packet,
230*d9f75844SAndroid Build Coastguard Worker                                          int64_t packet_time_us) {
231*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "SrtpTransport::OnRtcpPacketReceived");
232*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
233*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
234*d9f75844SAndroid Build Coastguard Worker         << "Inactive SRTP transport received an RTCP packet. Drop it.";
235*d9f75844SAndroid Build Coastguard Worker     return;
236*d9f75844SAndroid Build Coastguard Worker   }
237*d9f75844SAndroid Build Coastguard Worker   char* data = packet.MutableData<char>();
238*d9f75844SAndroid Build Coastguard Worker   int len = rtc::checked_cast<int>(packet.size());
239*d9f75844SAndroid Build Coastguard Worker   if (!UnprotectRtcp(data, len, &len)) {
240*d9f75844SAndroid Build Coastguard Worker     int type = -1;
241*d9f75844SAndroid Build Coastguard Worker     cricket::GetRtcpType(data, len, &type);
242*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to unprotect RTCP packet: size=" << len
243*d9f75844SAndroid Build Coastguard Worker                       << ", type=" << type;
244*d9f75844SAndroid Build Coastguard Worker     return;
245*d9f75844SAndroid Build Coastguard Worker   }
246*d9f75844SAndroid Build Coastguard Worker   packet.SetSize(len);
247*d9f75844SAndroid Build Coastguard Worker   SignalRtcpPacketReceived(&packet, packet_time_us);
248*d9f75844SAndroid Build Coastguard Worker }
249*d9f75844SAndroid Build Coastguard Worker 
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)250*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnNetworkRouteChanged(
251*d9f75844SAndroid Build Coastguard Worker     absl::optional<rtc::NetworkRoute> network_route) {
252*d9f75844SAndroid Build Coastguard Worker   // Only append the SRTP overhead when there is a selected network route.
253*d9f75844SAndroid Build Coastguard Worker   if (network_route) {
254*d9f75844SAndroid Build Coastguard Worker     int srtp_overhead = 0;
255*d9f75844SAndroid Build Coastguard Worker     if (IsSrtpActive()) {
256*d9f75844SAndroid Build Coastguard Worker       GetSrtpOverhead(&srtp_overhead);
257*d9f75844SAndroid Build Coastguard Worker     }
258*d9f75844SAndroid Build Coastguard Worker     network_route->packet_overhead += srtp_overhead;
259*d9f75844SAndroid Build Coastguard Worker   }
260*d9f75844SAndroid Build Coastguard Worker   SignalNetworkRouteChanged(network_route);
261*d9f75844SAndroid Build Coastguard Worker }
262*d9f75844SAndroid Build Coastguard Worker 
OnWritableState(rtc::PacketTransportInternal * packet_transport)263*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::OnWritableState(
264*d9f75844SAndroid Build Coastguard Worker     rtc::PacketTransportInternal* packet_transport) {
265*d9f75844SAndroid Build Coastguard Worker   SignalWritableState(IsWritable(/*rtcp=*/false) && IsWritable(/*rtcp=*/true));
266*d9f75844SAndroid Build Coastguard Worker }
267*d9f75844SAndroid Build Coastguard Worker 
SetRtpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)268*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SetRtpParams(int send_cs,
269*d9f75844SAndroid Build Coastguard Worker                                  const uint8_t* send_key,
270*d9f75844SAndroid Build Coastguard Worker                                  int send_key_len,
271*d9f75844SAndroid Build Coastguard Worker                                  const std::vector<int>& send_extension_ids,
272*d9f75844SAndroid Build Coastguard Worker                                  int recv_cs,
273*d9f75844SAndroid Build Coastguard Worker                                  const uint8_t* recv_key,
274*d9f75844SAndroid Build Coastguard Worker                                  int recv_key_len,
275*d9f75844SAndroid Build Coastguard Worker                                  const std::vector<int>& recv_extension_ids) {
276*d9f75844SAndroid Build Coastguard Worker   // If parameters are being set for the first time, we should create new SRTP
277*d9f75844SAndroid Build Coastguard Worker   // sessions and call "SetSend/SetRecv". Otherwise we should call
278*d9f75844SAndroid Build Coastguard Worker   // "UpdateSend"/"UpdateRecv" on the existing sessions, which will internally
279*d9f75844SAndroid Build Coastguard Worker   // call "srtp_update".
280*d9f75844SAndroid Build Coastguard Worker   bool new_sessions = false;
281*d9f75844SAndroid Build Coastguard Worker   if (!send_session_) {
282*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(!recv_session_);
283*d9f75844SAndroid Build Coastguard Worker     CreateSrtpSessions();
284*d9f75844SAndroid Build Coastguard Worker     new_sessions = true;
285*d9f75844SAndroid Build Coastguard Worker   }
286*d9f75844SAndroid Build Coastguard Worker   bool ret = new_sessions
287*d9f75844SAndroid Build Coastguard Worker                  ? send_session_->SetSend(send_cs, send_key, send_key_len,
288*d9f75844SAndroid Build Coastguard Worker                                           send_extension_ids)
289*d9f75844SAndroid Build Coastguard Worker                  : send_session_->UpdateSend(send_cs, send_key, send_key_len,
290*d9f75844SAndroid Build Coastguard Worker                                              send_extension_ids);
291*d9f75844SAndroid Build Coastguard Worker   if (!ret) {
292*d9f75844SAndroid Build Coastguard Worker     ResetParams();
293*d9f75844SAndroid Build Coastguard Worker     return false;
294*d9f75844SAndroid Build Coastguard Worker   }
295*d9f75844SAndroid Build Coastguard Worker 
296*d9f75844SAndroid Build Coastguard Worker   ret = new_sessions ? recv_session_->SetRecv(recv_cs, recv_key, recv_key_len,
297*d9f75844SAndroid Build Coastguard Worker                                               recv_extension_ids)
298*d9f75844SAndroid Build Coastguard Worker                      : recv_session_->UpdateRecv(
299*d9f75844SAndroid Build Coastguard Worker                            recv_cs, recv_key, recv_key_len, recv_extension_ids);
300*d9f75844SAndroid Build Coastguard Worker   if (!ret) {
301*d9f75844SAndroid Build Coastguard Worker     ResetParams();
302*d9f75844SAndroid Build Coastguard Worker     return false;
303*d9f75844SAndroid Build Coastguard Worker   }
304*d9f75844SAndroid Build Coastguard Worker 
305*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "SRTP " << (new_sessions ? "activated" : "updated")
306*d9f75844SAndroid Build Coastguard Worker                    << " with negotiated parameters: send cipher_suite "
307*d9f75844SAndroid Build Coastguard Worker                    << send_cs << " recv cipher_suite " << recv_cs;
308*d9f75844SAndroid Build Coastguard Worker   MaybeUpdateWritableState();
309*d9f75844SAndroid Build Coastguard Worker   return true;
310*d9f75844SAndroid Build Coastguard Worker }
311*d9f75844SAndroid Build Coastguard Worker 
SetRtcpParams(int send_cs,const uint8_t * send_key,int send_key_len,const std::vector<int> & send_extension_ids,int recv_cs,const uint8_t * recv_key,int recv_key_len,const std::vector<int> & recv_extension_ids)312*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::SetRtcpParams(int send_cs,
313*d9f75844SAndroid Build Coastguard Worker                                   const uint8_t* send_key,
314*d9f75844SAndroid Build Coastguard Worker                                   int send_key_len,
315*d9f75844SAndroid Build Coastguard Worker                                   const std::vector<int>& send_extension_ids,
316*d9f75844SAndroid Build Coastguard Worker                                   int recv_cs,
317*d9f75844SAndroid Build Coastguard Worker                                   const uint8_t* recv_key,
318*d9f75844SAndroid Build Coastguard Worker                                   int recv_key_len,
319*d9f75844SAndroid Build Coastguard Worker                                   const std::vector<int>& recv_extension_ids) {
320*d9f75844SAndroid Build Coastguard Worker   // This can only be called once, but can be safely called after
321*d9f75844SAndroid Build Coastguard Worker   // SetRtpParams
322*d9f75844SAndroid Build Coastguard Worker   if (send_rtcp_session_ || recv_rtcp_session_) {
323*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
324*d9f75844SAndroid Build Coastguard Worker     return false;
325*d9f75844SAndroid Build Coastguard Worker   }
326*d9f75844SAndroid Build Coastguard Worker 
327*d9f75844SAndroid Build Coastguard Worker   send_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
328*d9f75844SAndroid Build Coastguard Worker   if (!send_rtcp_session_->SetSend(send_cs, send_key, send_key_len,
329*d9f75844SAndroid Build Coastguard Worker                                    send_extension_ids)) {
330*d9f75844SAndroid Build Coastguard Worker     return false;
331*d9f75844SAndroid Build Coastguard Worker   }
332*d9f75844SAndroid Build Coastguard Worker 
333*d9f75844SAndroid Build Coastguard Worker   recv_rtcp_session_.reset(new cricket::SrtpSession(field_trials_));
334*d9f75844SAndroid Build Coastguard Worker   if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len,
335*d9f75844SAndroid Build Coastguard Worker                                    recv_extension_ids)) {
336*d9f75844SAndroid Build Coastguard Worker     return false;
337*d9f75844SAndroid Build Coastguard Worker   }
338*d9f75844SAndroid Build Coastguard Worker 
339*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
340*d9f75844SAndroid Build Coastguard Worker                       " send cipher_suite "
341*d9f75844SAndroid Build Coastguard Worker                    << send_cs << " recv cipher_suite " << recv_cs;
342*d9f75844SAndroid Build Coastguard Worker   MaybeUpdateWritableState();
343*d9f75844SAndroid Build Coastguard Worker   return true;
344*d9f75844SAndroid Build Coastguard Worker }
345*d9f75844SAndroid Build Coastguard Worker 
IsSrtpActive() const346*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsSrtpActive() const {
347*d9f75844SAndroid Build Coastguard Worker   return send_session_ && recv_session_;
348*d9f75844SAndroid Build Coastguard Worker }
349*d9f75844SAndroid Build Coastguard Worker 
IsWritable(bool rtcp) const350*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsWritable(bool rtcp) const {
351*d9f75844SAndroid Build Coastguard Worker   return IsSrtpActive() && RtpTransport::IsWritable(rtcp);
352*d9f75844SAndroid Build Coastguard Worker }
353*d9f75844SAndroid Build Coastguard Worker 
ResetParams()354*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::ResetParams() {
355*d9f75844SAndroid Build Coastguard Worker   send_session_ = nullptr;
356*d9f75844SAndroid Build Coastguard Worker   recv_session_ = nullptr;
357*d9f75844SAndroid Build Coastguard Worker   send_rtcp_session_ = nullptr;
358*d9f75844SAndroid Build Coastguard Worker   recv_rtcp_session_ = nullptr;
359*d9f75844SAndroid Build Coastguard Worker   MaybeUpdateWritableState();
360*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "The params in SRTP transport are reset.";
361*d9f75844SAndroid Build Coastguard Worker }
362*d9f75844SAndroid Build Coastguard Worker 
CreateSrtpSessions()363*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::CreateSrtpSessions() {
364*d9f75844SAndroid Build Coastguard Worker   send_session_.reset(new cricket::SrtpSession(field_trials_));
365*d9f75844SAndroid Build Coastguard Worker   recv_session_.reset(new cricket::SrtpSession(field_trials_));
366*d9f75844SAndroid Build Coastguard Worker   if (external_auth_enabled_) {
367*d9f75844SAndroid Build Coastguard Worker     send_session_->EnableExternalAuth();
368*d9f75844SAndroid Build Coastguard Worker   }
369*d9f75844SAndroid Build Coastguard Worker }
370*d9f75844SAndroid Build Coastguard Worker 
ProtectRtp(void * p,int in_len,int max_len,int * out_len)371*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
372*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
373*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
374*d9f75844SAndroid Build Coastguard Worker     return false;
375*d9f75844SAndroid Build Coastguard Worker   }
376*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(send_session_);
377*d9f75844SAndroid Build Coastguard Worker   return send_session_->ProtectRtp(p, in_len, max_len, out_len);
378*d9f75844SAndroid Build Coastguard Worker }
379*d9f75844SAndroid Build Coastguard Worker 
ProtectRtp(void * p,int in_len,int max_len,int * out_len,int64_t * index)380*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtp(void* p,
381*d9f75844SAndroid Build Coastguard Worker                                int in_len,
382*d9f75844SAndroid Build Coastguard Worker                                int max_len,
383*d9f75844SAndroid Build Coastguard Worker                                int* out_len,
384*d9f75844SAndroid Build Coastguard Worker                                int64_t* index) {
385*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
386*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
387*d9f75844SAndroid Build Coastguard Worker     return false;
388*d9f75844SAndroid Build Coastguard Worker   }
389*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(send_session_);
390*d9f75844SAndroid Build Coastguard Worker   return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
391*d9f75844SAndroid Build Coastguard Worker }
392*d9f75844SAndroid Build Coastguard Worker 
ProtectRtcp(void * p,int in_len,int max_len,int * out_len)393*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ProtectRtcp(void* p,
394*d9f75844SAndroid Build Coastguard Worker                                 int in_len,
395*d9f75844SAndroid Build Coastguard Worker                                 int max_len,
396*d9f75844SAndroid Build Coastguard Worker                                 int* out_len) {
397*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
398*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
399*d9f75844SAndroid Build Coastguard Worker     return false;
400*d9f75844SAndroid Build Coastguard Worker   }
401*d9f75844SAndroid Build Coastguard Worker   if (send_rtcp_session_) {
402*d9f75844SAndroid Build Coastguard Worker     return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
403*d9f75844SAndroid Build Coastguard Worker   } else {
404*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(send_session_);
405*d9f75844SAndroid Build Coastguard Worker     return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
406*d9f75844SAndroid Build Coastguard Worker   }
407*d9f75844SAndroid Build Coastguard Worker }
408*d9f75844SAndroid Build Coastguard Worker 
UnprotectRtp(void * p,int in_len,int * out_len)409*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::UnprotectRtp(void* p, int in_len, int* out_len) {
410*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
411*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
412*d9f75844SAndroid Build Coastguard Worker     return false;
413*d9f75844SAndroid Build Coastguard Worker   }
414*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(recv_session_);
415*d9f75844SAndroid Build Coastguard Worker   return recv_session_->UnprotectRtp(p, in_len, out_len);
416*d9f75844SAndroid Build Coastguard Worker }
417*d9f75844SAndroid Build Coastguard Worker 
UnprotectRtcp(void * p,int in_len,int * out_len)418*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::UnprotectRtcp(void* p, int in_len, int* out_len) {
419*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
420*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
421*d9f75844SAndroid Build Coastguard Worker     return false;
422*d9f75844SAndroid Build Coastguard Worker   }
423*d9f75844SAndroid Build Coastguard Worker   if (recv_rtcp_session_) {
424*d9f75844SAndroid Build Coastguard Worker     return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
425*d9f75844SAndroid Build Coastguard Worker   } else {
426*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(recv_session_);
427*d9f75844SAndroid Build Coastguard Worker     return recv_session_->UnprotectRtcp(p, in_len, out_len);
428*d9f75844SAndroid Build Coastguard Worker   }
429*d9f75844SAndroid Build Coastguard Worker }
430*d9f75844SAndroid Build Coastguard Worker 
GetRtpAuthParams(uint8_t ** key,int * key_len,int * tag_len)431*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::GetRtpAuthParams(uint8_t** key,
432*d9f75844SAndroid Build Coastguard Worker                                      int* key_len,
433*d9f75844SAndroid Build Coastguard Worker                                      int* tag_len) {
434*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
435*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
436*d9f75844SAndroid Build Coastguard Worker     return false;
437*d9f75844SAndroid Build Coastguard Worker   }
438*d9f75844SAndroid Build Coastguard Worker 
439*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(send_session_);
440*d9f75844SAndroid Build Coastguard Worker   return send_session_->GetRtpAuthParams(key, key_len, tag_len);
441*d9f75844SAndroid Build Coastguard Worker }
442*d9f75844SAndroid Build Coastguard Worker 
GetSrtpOverhead(int * srtp_overhead) const443*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::GetSrtpOverhead(int* srtp_overhead) const {
444*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
445*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
446*d9f75844SAndroid Build Coastguard Worker     return false;
447*d9f75844SAndroid Build Coastguard Worker   }
448*d9f75844SAndroid Build Coastguard Worker 
449*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(send_session_);
450*d9f75844SAndroid Build Coastguard Worker   *srtp_overhead = send_session_->GetSrtpOverhead();
451*d9f75844SAndroid Build Coastguard Worker   return true;
452*d9f75844SAndroid Build Coastguard Worker }
453*d9f75844SAndroid Build Coastguard Worker 
EnableExternalAuth()454*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::EnableExternalAuth() {
455*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!IsSrtpActive());
456*d9f75844SAndroid Build Coastguard Worker   external_auth_enabled_ = true;
457*d9f75844SAndroid Build Coastguard Worker }
458*d9f75844SAndroid Build Coastguard Worker 
IsExternalAuthEnabled() const459*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsExternalAuthEnabled() const {
460*d9f75844SAndroid Build Coastguard Worker   return external_auth_enabled_;
461*d9f75844SAndroid Build Coastguard Worker }
462*d9f75844SAndroid Build Coastguard Worker 
IsExternalAuthActive() const463*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::IsExternalAuthActive() const {
464*d9f75844SAndroid Build Coastguard Worker   if (!IsSrtpActive()) {
465*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING)
466*d9f75844SAndroid Build Coastguard Worker         << "Failed to check IsExternalAuthActive: SRTP not active";
467*d9f75844SAndroid Build Coastguard Worker     return false;
468*d9f75844SAndroid Build Coastguard Worker   }
469*d9f75844SAndroid Build Coastguard Worker 
470*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(send_session_);
471*d9f75844SAndroid Build Coastguard Worker   return send_session_->IsExternalAuthActive();
472*d9f75844SAndroid Build Coastguard Worker }
473*d9f75844SAndroid Build Coastguard Worker 
MaybeSetKeyParams()474*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::MaybeSetKeyParams() {
475*d9f75844SAndroid Build Coastguard Worker   if (!send_cipher_suite_ || !recv_cipher_suite_) {
476*d9f75844SAndroid Build Coastguard Worker     return true;
477*d9f75844SAndroid Build Coastguard Worker   }
478*d9f75844SAndroid Build Coastguard Worker 
479*d9f75844SAndroid Build Coastguard Worker   return SetRtpParams(*send_cipher_suite_, send_key_.data(),
480*d9f75844SAndroid Build Coastguard Worker                       static_cast<int>(send_key_.size()), std::vector<int>(),
481*d9f75844SAndroid Build Coastguard Worker                       *recv_cipher_suite_, recv_key_.data(),
482*d9f75844SAndroid Build Coastguard Worker                       static_cast<int>(recv_key_.size()), std::vector<int>());
483*d9f75844SAndroid Build Coastguard Worker }
484*d9f75844SAndroid Build Coastguard Worker 
ParseKeyParams(const std::string & key_params,uint8_t * key,size_t len)485*d9f75844SAndroid Build Coastguard Worker bool SrtpTransport::ParseKeyParams(const std::string& key_params,
486*d9f75844SAndroid Build Coastguard Worker                                    uint8_t* key,
487*d9f75844SAndroid Build Coastguard Worker                                    size_t len) {
488*d9f75844SAndroid Build Coastguard Worker   // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
489*d9f75844SAndroid Build Coastguard Worker 
490*d9f75844SAndroid Build Coastguard Worker   // Fail if key-method is wrong.
491*d9f75844SAndroid Build Coastguard Worker   if (!absl::StartsWith(key_params, "inline:")) {
492*d9f75844SAndroid Build Coastguard Worker     return false;
493*d9f75844SAndroid Build Coastguard Worker   }
494*d9f75844SAndroid Build Coastguard Worker 
495*d9f75844SAndroid Build Coastguard Worker   // Fail if base64 decode fails, or the key is the wrong size.
496*d9f75844SAndroid Build Coastguard Worker   std::string key_b64(key_params.substr(7)), key_str;
497*d9f75844SAndroid Build Coastguard Worker   if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
498*d9f75844SAndroid Build Coastguard Worker                            nullptr) ||
499*d9f75844SAndroid Build Coastguard Worker       key_str.size() != len) {
500*d9f75844SAndroid Build Coastguard Worker     return false;
501*d9f75844SAndroid Build Coastguard Worker   }
502*d9f75844SAndroid Build Coastguard Worker 
503*d9f75844SAndroid Build Coastguard Worker   memcpy(key, key_str.c_str(), len);
504*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/8905): Switch to ZeroOnFreeBuffer for storing
505*d9f75844SAndroid Build Coastguard Worker   // sensitive data.
506*d9f75844SAndroid Build Coastguard Worker   rtc::ExplicitZeroMemory(&key_str[0], key_str.size());
507*d9f75844SAndroid Build Coastguard Worker   return true;
508*d9f75844SAndroid Build Coastguard Worker }
509*d9f75844SAndroid Build Coastguard Worker 
MaybeUpdateWritableState()510*d9f75844SAndroid Build Coastguard Worker void SrtpTransport::MaybeUpdateWritableState() {
511*d9f75844SAndroid Build Coastguard Worker   bool writable = IsWritable(/*rtcp=*/true) && IsWritable(/*rtcp=*/false);
512*d9f75844SAndroid Build Coastguard Worker   // Only fire the signal if the writable state changes.
513*d9f75844SAndroid Build Coastguard Worker   if (writable_ != writable) {
514*d9f75844SAndroid Build Coastguard Worker     writable_ = writable;
515*d9f75844SAndroid Build Coastguard Worker     SignalWritableState(writable_);
516*d9f75844SAndroid Build Coastguard Worker   }
517*d9f75844SAndroid Build Coastguard Worker }
518*d9f75844SAndroid Build Coastguard Worker 
519*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
520