1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/media/rtc_data_channel_handler.h"
6
7#include <limits>
8#include <string>
9
10#include "base/logging.h"
11#include "base/metrics/histogram.h"
12#include "base/strings/utf_string_conversions.h"
13
14namespace content {
15
16namespace {
17
18enum DataChannelCounters {
19  CHANNEL_CREATED,
20  CHANNEL_OPENED,
21  CHANNEL_RELIABLE,
22  CHANNEL_ORDERED,
23  CHANNEL_NEGOTIATED,
24  CHANNEL_BOUNDARY
25};
26
27void IncrementCounter(DataChannelCounters counter) {
28  UMA_HISTOGRAM_ENUMERATION("WebRTC.DataChannelCounters",
29                            counter,
30                            CHANNEL_BOUNDARY);
31}
32
33}  // namespace
34
35RtcDataChannelHandler::RtcDataChannelHandler(
36    webrtc::DataChannelInterface* channel)
37    : channel_(channel),
38      webkit_client_(NULL) {
39  DVLOG(1) << "::ctor";
40  channel_->RegisterObserver(this);
41
42  IncrementCounter(CHANNEL_CREATED);
43  if (isReliable())
44    IncrementCounter(CHANNEL_RELIABLE);
45  if (ordered())
46    IncrementCounter(CHANNEL_ORDERED);
47  if (negotiated())
48    IncrementCounter(CHANNEL_NEGOTIATED);
49
50  UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmits",
51                              maxRetransmits(), 0,
52                              std::numeric_limits<unsigned short>::max(), 50);
53  UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.DataChannelMaxRetransmitTime",
54                              maxRetransmitTime(), 0,
55                              std::numeric_limits<unsigned short>::max(), 50);
56}
57
58RtcDataChannelHandler::~RtcDataChannelHandler() {
59  DVLOG(1) << "::dtor";
60  channel_->UnregisterObserver();
61}
62
63void RtcDataChannelHandler::setClient(
64    blink::WebRTCDataChannelHandlerClient* client) {
65  webkit_client_ = client;
66}
67
68blink::WebString RtcDataChannelHandler::label() {
69  return base::UTF8ToUTF16(channel_->label());
70}
71
72bool RtcDataChannelHandler::isReliable() {
73  return channel_->reliable();
74}
75
76bool RtcDataChannelHandler::ordered() const {
77  return channel_->ordered();
78}
79
80unsigned short RtcDataChannelHandler::maxRetransmitTime() const {
81  return channel_->maxRetransmitTime();
82}
83
84unsigned short RtcDataChannelHandler::maxRetransmits() const {
85  return channel_->maxRetransmits();
86}
87
88blink::WebString RtcDataChannelHandler::protocol() const {
89  return base::UTF8ToUTF16(channel_->protocol());
90}
91
92bool RtcDataChannelHandler::negotiated() const {
93  return channel_->negotiated();
94}
95
96unsigned short RtcDataChannelHandler::id() const {
97  return channel_->id();
98}
99
100unsigned long RtcDataChannelHandler::bufferedAmount() {
101  return channel_->buffered_amount();
102}
103
104bool RtcDataChannelHandler::sendStringData(const blink::WebString& data) {
105  std::string utf8_buffer = base::UTF16ToUTF8(data);
106  rtc::Buffer buffer(utf8_buffer.c_str(), utf8_buffer.length());
107  webrtc::DataBuffer data_buffer(buffer, false);
108  RecordMessageSent(data_buffer.size());
109  return channel_->Send(data_buffer);
110}
111
112bool RtcDataChannelHandler::sendRawData(const char* data, size_t length) {
113  rtc::Buffer buffer(data, length);
114  webrtc::DataBuffer data_buffer(buffer, true);
115  RecordMessageSent(data_buffer.size());
116  return channel_->Send(data_buffer);
117}
118
119void RtcDataChannelHandler::close() {
120  channel_->Close();
121}
122
123void RtcDataChannelHandler::OnStateChange() {
124  if (!webkit_client_) {
125    LOG(ERROR) << "WebRTCDataChannelHandlerClient not set.";
126    return;
127  }
128  DVLOG(1) << "OnStateChange " << channel_->state();
129  switch (channel_->state()) {
130    case webrtc::DataChannelInterface::kConnecting:
131      webkit_client_->didChangeReadyState(
132          blink::WebRTCDataChannelHandlerClient::ReadyStateConnecting);
133      break;
134    case webrtc::DataChannelInterface::kOpen:
135      IncrementCounter(CHANNEL_OPENED);
136      webkit_client_->didChangeReadyState(
137          blink::WebRTCDataChannelHandlerClient::ReadyStateOpen);
138      break;
139    case webrtc::DataChannelInterface::kClosing:
140      webkit_client_->didChangeReadyState(
141          blink::WebRTCDataChannelHandlerClient::ReadyStateClosing);
142      break;
143    case webrtc::DataChannelInterface::kClosed:
144      webkit_client_->didChangeReadyState(
145          blink::WebRTCDataChannelHandlerClient::ReadyStateClosed);
146      break;
147    default:
148      NOTREACHED();
149      break;
150  }
151}
152
153void RtcDataChannelHandler::OnMessage(const webrtc::DataBuffer& buffer) {
154  if (!webkit_client_) {
155    LOG(ERROR) << "WebRTCDataChannelHandlerClient not set.";
156    return;
157  }
158
159  if (buffer.binary) {
160    webkit_client_->didReceiveRawData(buffer.data.data(), buffer.data.length());
161  } else {
162    base::string16 utf16;
163    if (!base::UTF8ToUTF16(buffer.data.data(), buffer.data.length(), &utf16)) {
164      LOG(ERROR) << "Failed convert received data to UTF16";
165      return;
166    }
167    webkit_client_->didReceiveStringData(utf16);
168  }
169}
170
171void RtcDataChannelHandler::RecordMessageSent(size_t num_bytes) {
172  // Currently, messages are capped at some fairly low limit (16 Kb?)
173  // but we may allow unlimited-size messages at some point, so making
174  // the histogram maximum quite large (100 Mb) to have some
175  // granularity at the higher end in that eventuality. The histogram
176  // buckets are exponentially growing in size, so we'll still have
177  // good granularity at the low end.
178
179  // This makes the last bucket in the histogram count messages from
180  // 100 Mb to infinity.
181  const int kMaxBucketSize = 100 * 1024 * 1024;
182  const int kNumBuckets = 50;
183
184  if (isReliable()) {
185    UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.ReliableDataChannelMessageSize",
186                                num_bytes,
187                                1, kMaxBucketSize, kNumBuckets);
188  } else {
189    UMA_HISTOGRAM_CUSTOM_COUNTS("WebRTC.UnreliableDataChannelMessageSize",
190                                num_bytes,
191                                1, kMaxBucketSize, kNumBuckets);
192  }
193}
194
195}  // namespace content
196