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