1 /*
2  * libjingle
3  * Copyright 2013 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "talk/app/webrtc/sctputils.h"
29 
30 #include "webrtc/base/buffer.h"
31 #include "webrtc/base/bytebuffer.h"
32 #include "webrtc/base/logging.h"
33 
34 namespace webrtc {
35 
36 // Format defined at
37 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-01#section
38 
39 static const uint8_t DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
40 static const uint8_t DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE = 0x02;
41 
42 enum DataChannelOpenMessageChannelType {
43   DCOMCT_ORDERED_RELIABLE = 0x00,
44   DCOMCT_ORDERED_PARTIAL_RTXS = 0x01,
45   DCOMCT_ORDERED_PARTIAL_TIME = 0x02,
46   DCOMCT_UNORDERED_RELIABLE = 0x80,
47   DCOMCT_UNORDERED_PARTIAL_RTXS = 0x81,
48   DCOMCT_UNORDERED_PARTIAL_TIME = 0x82,
49 };
50 
IsOpenMessage(const rtc::Buffer & payload)51 bool IsOpenMessage(const rtc::Buffer& payload) {
52   // Format defined at
53   // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
54 
55   rtc::ByteBuffer buffer(payload);
56   uint8_t message_type;
57   if (!buffer.ReadUInt8(&message_type)) {
58     LOG(LS_WARNING) << "Could not read OPEN message type.";
59     return false;
60   }
61   return message_type == DATA_CHANNEL_OPEN_MESSAGE_TYPE;
62 }
63 
ParseDataChannelOpenMessage(const rtc::Buffer & payload,std::string * label,DataChannelInit * config)64 bool ParseDataChannelOpenMessage(const rtc::Buffer& payload,
65                                  std::string* label,
66                                  DataChannelInit* config) {
67   // Format defined at
68   // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
69 
70   rtc::ByteBuffer buffer(payload);
71   uint8_t message_type;
72   if (!buffer.ReadUInt8(&message_type)) {
73     LOG(LS_WARNING) << "Could not read OPEN message type.";
74     return false;
75   }
76   if (message_type != DATA_CHANNEL_OPEN_MESSAGE_TYPE) {
77     LOG(LS_WARNING) << "Data Channel OPEN message of unexpected type: "
78                     << message_type;
79     return false;
80   }
81 
82   uint8_t channel_type;
83   if (!buffer.ReadUInt8(&channel_type)) {
84     LOG(LS_WARNING) << "Could not read OPEN message channel type.";
85     return false;
86   }
87 
88   uint16_t priority;
89   if (!buffer.ReadUInt16(&priority)) {
90     LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty.";
91     return false;
92   }
93   uint32_t reliability_param;
94   if (!buffer.ReadUInt32(&reliability_param)) {
95     LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
96     return false;
97   }
98   uint16_t label_length;
99   if (!buffer.ReadUInt16(&label_length)) {
100     LOG(LS_WARNING) << "Could not read OPEN message label length.";
101     return false;
102   }
103   uint16_t protocol_length;
104   if (!buffer.ReadUInt16(&protocol_length)) {
105     LOG(LS_WARNING) << "Could not read OPEN message protocol length.";
106     return false;
107   }
108   if (!buffer.ReadString(label, (size_t) label_length)) {
109     LOG(LS_WARNING) << "Could not read OPEN message label";
110     return false;
111   }
112   if (!buffer.ReadString(&config->protocol, protocol_length)) {
113     LOG(LS_WARNING) << "Could not read OPEN message protocol.";
114     return false;
115   }
116 
117   config->ordered = true;
118   switch (channel_type) {
119     case DCOMCT_UNORDERED_RELIABLE:
120     case DCOMCT_UNORDERED_PARTIAL_RTXS:
121     case DCOMCT_UNORDERED_PARTIAL_TIME:
122       config->ordered = false;
123   }
124 
125   config->maxRetransmits = -1;
126   config->maxRetransmitTime = -1;
127   switch (channel_type) {
128     case DCOMCT_ORDERED_PARTIAL_RTXS:
129     case DCOMCT_UNORDERED_PARTIAL_RTXS:
130       config->maxRetransmits = reliability_param;
131       break;
132     case DCOMCT_ORDERED_PARTIAL_TIME:
133     case DCOMCT_UNORDERED_PARTIAL_TIME:
134       config->maxRetransmitTime = reliability_param;
135       break;
136   }
137   return true;
138 }
139 
ParseDataChannelOpenAckMessage(const rtc::Buffer & payload)140 bool ParseDataChannelOpenAckMessage(const rtc::Buffer& payload) {
141   rtc::ByteBuffer buffer(payload);
142   uint8_t message_type;
143   if (!buffer.ReadUInt8(&message_type)) {
144     LOG(LS_WARNING) << "Could not read OPEN_ACK message type.";
145     return false;
146   }
147   if (message_type != DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE) {
148     LOG(LS_WARNING) << "Data Channel OPEN_ACK message of unexpected type: "
149                     << message_type;
150     return false;
151   }
152   return true;
153 }
154 
WriteDataChannelOpenMessage(const std::string & label,const DataChannelInit & config,rtc::Buffer * payload)155 bool WriteDataChannelOpenMessage(const std::string& label,
156                                  const DataChannelInit& config,
157                                  rtc::Buffer* payload) {
158   // Format defined at
159   // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
160   uint8_t channel_type = 0;
161   uint32_t reliability_param = 0;
162   uint16_t priority = 0;
163   if (config.ordered) {
164     if (config.maxRetransmits > -1) {
165       channel_type = DCOMCT_ORDERED_PARTIAL_RTXS;
166       reliability_param = config.maxRetransmits;
167     } else if (config.maxRetransmitTime > -1) {
168       channel_type = DCOMCT_ORDERED_PARTIAL_TIME;
169       reliability_param = config.maxRetransmitTime;
170     } else {
171       channel_type = DCOMCT_ORDERED_RELIABLE;
172     }
173   } else {
174     if (config.maxRetransmits > -1) {
175       channel_type = DCOMCT_UNORDERED_PARTIAL_RTXS;
176       reliability_param = config.maxRetransmits;
177     } else if (config.maxRetransmitTime > -1) {
178       channel_type = DCOMCT_UNORDERED_PARTIAL_TIME;
179       reliability_param = config.maxRetransmitTime;
180     } else {
181       channel_type = DCOMCT_UNORDERED_RELIABLE;
182     }
183   }
184 
185   rtc::ByteBuffer buffer(
186       NULL, 20 + label.length() + config.protocol.length(),
187       rtc::ByteBuffer::ORDER_NETWORK);
188   buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
189   buffer.WriteUInt8(channel_type);
190   buffer.WriteUInt16(priority);
191   buffer.WriteUInt32(reliability_param);
192   buffer.WriteUInt16(static_cast<uint16_t>(label.length()));
193   buffer.WriteUInt16(static_cast<uint16_t>(config.protocol.length()));
194   buffer.WriteString(label);
195   buffer.WriteString(config.protocol);
196   payload->SetData(buffer.Data(), buffer.Length());
197   return true;
198 }
199 
WriteDataChannelOpenAckMessage(rtc::Buffer * payload)200 void WriteDataChannelOpenAckMessage(rtc::Buffer* payload) {
201   rtc::ByteBuffer buffer(rtc::ByteBuffer::ORDER_NETWORK);
202   buffer.WriteUInt8(DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE);
203   payload->SetData(buffer.Data(), buffer.Length());
204 }
205 }  // namespace webrtc
206