1 /*
2 * Copyright 2013 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "pc/sctp_utils.h"
12
13 #include <stddef.h>
14 #include <stdint.h>
15
16 #include "api/priority.h"
17 #include "rtc_base/byte_buffer.h"
18 #include "rtc_base/copy_on_write_buffer.h"
19 #include "rtc_base/logging.h"
20
21 namespace webrtc {
22
23 // Format defined at
24 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-01#section
25
26 static const uint8_t DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
27 static const uint8_t DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE = 0x02;
28
29 enum DataChannelOpenMessageChannelType {
30 DCOMCT_ORDERED_RELIABLE = 0x00,
31 DCOMCT_ORDERED_PARTIAL_RTXS = 0x01,
32 DCOMCT_ORDERED_PARTIAL_TIME = 0x02,
33 DCOMCT_UNORDERED_RELIABLE = 0x80,
34 DCOMCT_UNORDERED_PARTIAL_RTXS = 0x81,
35 DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
36 };
37
38 // Values of priority in the DC open protocol message.
39 // These are compared against an integer, so are enum, not enum class.
40 enum DataChannelPriority {
41 DCO_PRIORITY_VERY_LOW = 128,
42 DCO_PRIORITY_LOW = 256,
43 DCO_PRIORITY_MEDIUM = 512,
44 DCO_PRIORITY_HIGH = 1024,
45 };
46
IsOpenMessage(const rtc::CopyOnWriteBuffer & payload)47 bool IsOpenMessage(const rtc::CopyOnWriteBuffer& payload) {
48 // Format defined at
49 // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
50 if (payload.size() < 1) {
51 RTC_LOG(LS_WARNING) << "Could not read OPEN message type.";
52 return false;
53 }
54
55 uint8_t message_type = payload[0];
56 return message_type == DATA_CHANNEL_OPEN_MESSAGE_TYPE;
57 }
58
ParseDataChannelOpenMessage(const rtc::CopyOnWriteBuffer & payload,std::string * label,DataChannelInit * config)59 bool ParseDataChannelOpenMessage(const rtc::CopyOnWriteBuffer& payload,
60 std::string* label,
61 DataChannelInit* config) {
62 // Format defined at
63 // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
64
65 rtc::ByteBufferReader buffer(payload.data<char>(), payload.size());
66 uint8_t message_type;
67 if (!buffer.ReadUInt8(&message_type)) {
68 RTC_LOG(LS_WARNING) << "Could not read OPEN message type.";
69 return false;
70 }
71 if (message_type != DATA_CHANNEL_OPEN_MESSAGE_TYPE) {
72 RTC_LOG(LS_WARNING) << "Data Channel OPEN message of unexpected type: "
73 << message_type;
74 return false;
75 }
76
77 uint8_t channel_type;
78 if (!buffer.ReadUInt8(&channel_type)) {
79 RTC_LOG(LS_WARNING) << "Could not read OPEN message channel type.";
80 return false;
81 }
82
83 uint16_t priority;
84 if (!buffer.ReadUInt16(&priority)) {
85 RTC_LOG(LS_WARNING)
86 << "Could not read OPEN message reliabilility prioirty.";
87 return false;
88 }
89 // Parse priority as defined in
90 // https://w3c.github.io/webrtc-priority/#rtcdatachannel-processing-steps
91 if (priority <= DCO_PRIORITY_VERY_LOW) {
92 config->priority = Priority::kVeryLow;
93 } else if (priority <= DCO_PRIORITY_LOW) {
94 config->priority = Priority::kLow;
95 } else if (priority <= DCO_PRIORITY_MEDIUM) {
96 config->priority = Priority::kMedium;
97 } else {
98 config->priority = Priority::kHigh;
99 }
100
101 uint32_t reliability_param;
102 if (!buffer.ReadUInt32(&reliability_param)) {
103 RTC_LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
104 return false;
105 }
106 uint16_t label_length;
107 if (!buffer.ReadUInt16(&label_length)) {
108 RTC_LOG(LS_WARNING) << "Could not read OPEN message label length.";
109 return false;
110 }
111 uint16_t protocol_length;
112 if (!buffer.ReadUInt16(&protocol_length)) {
113 RTC_LOG(LS_WARNING) << "Could not read OPEN message protocol length.";
114 return false;
115 }
116 if (!buffer.ReadString(label, (size_t)label_length)) {
117 RTC_LOG(LS_WARNING) << "Could not read OPEN message label";
118 return false;
119 }
120 if (!buffer.ReadString(&config->protocol, protocol_length)) {
121 RTC_LOG(LS_WARNING) << "Could not read OPEN message protocol.";
122 return false;
123 }
124
125 config->ordered = true;
126 switch (channel_type) {
127 case DCOMCT_UNORDERED_RELIABLE:
128 case DCOMCT_UNORDERED_PARTIAL_RTXS:
129 case DCOMCT_UNORDERED_PARTIAL_TIME:
130 config->ordered = false;
131 }
132
133 config->maxRetransmits = absl::nullopt;
134 config->maxRetransmitTime = absl::nullopt;
135 switch (channel_type) {
136 case DCOMCT_ORDERED_PARTIAL_RTXS:
137 case DCOMCT_UNORDERED_PARTIAL_RTXS:
138 config->maxRetransmits = reliability_param;
139 break;
140 case DCOMCT_ORDERED_PARTIAL_TIME:
141 case DCOMCT_UNORDERED_PARTIAL_TIME:
142 config->maxRetransmitTime = reliability_param;
143 break;
144 }
145 return true;
146 }
147
ParseDataChannelOpenAckMessage(const rtc::CopyOnWriteBuffer & payload)148 bool ParseDataChannelOpenAckMessage(const rtc::CopyOnWriteBuffer& payload) {
149 if (payload.size() < 1) {
150 RTC_LOG(LS_WARNING) << "Could not read OPEN_ACK message type.";
151 return false;
152 }
153
154 uint8_t message_type = payload[0];
155 if (message_type != DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE) {
156 RTC_LOG(LS_WARNING) << "Data Channel OPEN_ACK message of unexpected type: "
157 << message_type;
158 return false;
159 }
160 return true;
161 }
162
WriteDataChannelOpenMessage(const std::string & label,const DataChannelInit & config,rtc::CopyOnWriteBuffer * payload)163 bool WriteDataChannelOpenMessage(const std::string& label,
164 const DataChannelInit& config,
165 rtc::CopyOnWriteBuffer* payload) {
166 // Format defined at
167 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09#section-5.1
168 uint8_t channel_type = 0;
169 uint32_t reliability_param = 0;
170 uint16_t priority = 0;
171 // Set priority according to
172 // https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-12#section-6.4
173 if (config.priority) {
174 switch (*config.priority) {
175 case Priority::kVeryLow:
176 priority = DCO_PRIORITY_VERY_LOW;
177 break;
178 case Priority::kLow:
179 priority = DCO_PRIORITY_LOW;
180 break;
181 case Priority::kMedium:
182 priority = DCO_PRIORITY_MEDIUM;
183 break;
184 case Priority::kHigh:
185 priority = DCO_PRIORITY_HIGH;
186 break;
187 }
188 }
189 if (config.ordered) {
190 if (config.maxRetransmits) {
191 channel_type = DCOMCT_ORDERED_PARTIAL_RTXS;
192 reliability_param = *config.maxRetransmits;
193 } else if (config.maxRetransmitTime) {
194 channel_type = DCOMCT_ORDERED_PARTIAL_TIME;
195 reliability_param = *config.maxRetransmitTime;
196 } else {
197 channel_type = DCOMCT_ORDERED_RELIABLE;
198 }
199 } else {
200 if (config.maxRetransmits) {
201 channel_type = DCOMCT_UNORDERED_PARTIAL_RTXS;
202 reliability_param = *config.maxRetransmits;
203 } else if (config.maxRetransmitTime) {
204 channel_type = DCOMCT_UNORDERED_PARTIAL_TIME;
205 reliability_param = *config.maxRetransmitTime;
206 } else {
207 channel_type = DCOMCT_UNORDERED_RELIABLE;
208 }
209 }
210
211 rtc::ByteBufferWriter buffer(NULL,
212 20 + label.length() + config.protocol.length());
213 // TODO(tommi): Add error handling and check resulting length.
214 buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
215 buffer.WriteUInt8(channel_type);
216 buffer.WriteUInt16(priority);
217 buffer.WriteUInt32(reliability_param);
218 buffer.WriteUInt16(static_cast<uint16_t>(label.length()));
219 buffer.WriteUInt16(static_cast<uint16_t>(config.protocol.length()));
220 buffer.WriteString(label);
221 buffer.WriteString(config.protocol);
222 payload->SetData(buffer.Data(), buffer.Length());
223 return true;
224 }
225
WriteDataChannelOpenAckMessage(rtc::CopyOnWriteBuffer * payload)226 void WriteDataChannelOpenAckMessage(rtc::CopyOnWriteBuffer* payload) {
227 uint8_t data = DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE;
228 payload->SetData(&data, sizeof(data));
229 }
230
ToCricketDataMessageType(DataMessageType type)231 cricket::DataMessageType ToCricketDataMessageType(DataMessageType type) {
232 switch (type) {
233 case DataMessageType::kText:
234 return cricket::DMT_TEXT;
235 case DataMessageType::kBinary:
236 return cricket::DMT_BINARY;
237 case DataMessageType::kControl:
238 return cricket::DMT_CONTROL;
239 default:
240 return cricket::DMT_NONE;
241 }
242 return cricket::DMT_NONE;
243 }
244
ToWebrtcDataMessageType(cricket::DataMessageType type)245 DataMessageType ToWebrtcDataMessageType(cricket::DataMessageType type) {
246 switch (type) {
247 case cricket::DMT_TEXT:
248 return DataMessageType::kText;
249 case cricket::DMT_BINARY:
250 return DataMessageType::kBinary;
251 case cricket::DMT_CONTROL:
252 return DataMessageType::kControl;
253 case cricket::DMT_NONE:
254 default:
255 RTC_NOTREACHED();
256 }
257 return DataMessageType::kControl;
258 }
259
260 } // namespace webrtc
261