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 "talk/base/buffer.h" 31 #include "talk/base/bytebuffer.h" 32 #include "talk/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 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03; 40 static const uint8 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 51 bool ParseDataChannelOpenMessage(const talk_base::Buffer& payload, 52 std::string* label, 53 DataChannelInit* config) { 54 // Format defined at 55 // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04 56 57 talk_base::ByteBuffer buffer(payload.data(), payload.length()); 58 59 uint8 message_type; 60 if (!buffer.ReadUInt8(&message_type)) { 61 LOG(LS_WARNING) << "Could not read OPEN message type."; 62 return false; 63 } 64 if (message_type != DATA_CHANNEL_OPEN_MESSAGE_TYPE) { 65 LOG(LS_WARNING) << "Data Channel OPEN message of unexpected type: " 66 << message_type; 67 return false; 68 } 69 70 uint8 channel_type; 71 if (!buffer.ReadUInt8(&channel_type)) { 72 LOG(LS_WARNING) << "Could not read OPEN message channel type."; 73 return false; 74 } 75 76 uint16 priority; 77 if (!buffer.ReadUInt16(&priority)) { 78 LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty."; 79 return false; 80 } 81 uint32 reliability_param; 82 if (!buffer.ReadUInt32(&reliability_param)) { 83 LOG(LS_WARNING) << "Could not read OPEN message reliabilility param."; 84 return false; 85 } 86 uint16 label_length; 87 if (!buffer.ReadUInt16(&label_length)) { 88 LOG(LS_WARNING) << "Could not read OPEN message label length."; 89 return false; 90 } 91 uint16 protocol_length; 92 if (!buffer.ReadUInt16(&protocol_length)) { 93 LOG(LS_WARNING) << "Could not read OPEN message protocol length."; 94 return false; 95 } 96 if (!buffer.ReadString(label, (size_t) label_length)) { 97 LOG(LS_WARNING) << "Could not read OPEN message label"; 98 return false; 99 } 100 if (!buffer.ReadString(&config->protocol, protocol_length)) { 101 LOG(LS_WARNING) << "Could not read OPEN message protocol."; 102 return false; 103 } 104 105 config->ordered = true; 106 switch (channel_type) { 107 case DCOMCT_UNORDERED_RELIABLE: 108 case DCOMCT_UNORDERED_PARTIAL_RTXS: 109 case DCOMCT_UNORDERED_PARTIAL_TIME: 110 config->ordered = false; 111 } 112 113 config->maxRetransmits = -1; 114 config->maxRetransmitTime = -1; 115 switch (channel_type) { 116 case DCOMCT_ORDERED_PARTIAL_RTXS: 117 case DCOMCT_UNORDERED_PARTIAL_RTXS: 118 config->maxRetransmits = reliability_param; 119 break; 120 case DCOMCT_ORDERED_PARTIAL_TIME: 121 case DCOMCT_UNORDERED_PARTIAL_TIME: 122 config->maxRetransmitTime = reliability_param; 123 break; 124 } 125 return true; 126 } 127 128 bool ParseDataChannelOpenAckMessage(const talk_base::Buffer& payload) { 129 talk_base::ByteBuffer buffer(payload.data(), payload.length()); 130 131 uint8 message_type; 132 if (!buffer.ReadUInt8(&message_type)) { 133 LOG(LS_WARNING) << "Could not read OPEN_ACK message type."; 134 return false; 135 } 136 if (message_type != DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE) { 137 LOG(LS_WARNING) << "Data Channel OPEN_ACK message of unexpected type: " 138 << message_type; 139 return false; 140 } 141 return true; 142 } 143 144 bool WriteDataChannelOpenMessage(const std::string& label, 145 const DataChannelInit& config, 146 talk_base::Buffer* payload) { 147 // Format defined at 148 // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1 149 uint8 channel_type = 0; 150 uint32 reliability_param = 0; 151 uint16 priority = 0; 152 if (config.ordered) { 153 if (config.maxRetransmits > -1) { 154 channel_type = DCOMCT_ORDERED_PARTIAL_RTXS; 155 reliability_param = config.maxRetransmits; 156 } else if (config.maxRetransmitTime > -1) { 157 channel_type = DCOMCT_ORDERED_PARTIAL_TIME; 158 reliability_param = config.maxRetransmitTime; 159 } else { 160 channel_type = DCOMCT_ORDERED_RELIABLE; 161 } 162 } else { 163 if (config.maxRetransmits > -1) { 164 channel_type = DCOMCT_UNORDERED_PARTIAL_RTXS; 165 reliability_param = config.maxRetransmits; 166 } else if (config.maxRetransmitTime > -1) { 167 channel_type = DCOMCT_UNORDERED_PARTIAL_TIME; 168 reliability_param = config.maxRetransmitTime; 169 } else { 170 channel_type = DCOMCT_UNORDERED_RELIABLE; 171 } 172 } 173 174 talk_base::ByteBuffer buffer( 175 NULL, 20 + label.length() + config.protocol.length(), 176 talk_base::ByteBuffer::ORDER_NETWORK); 177 buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE); 178 buffer.WriteUInt8(channel_type); 179 buffer.WriteUInt16(priority); 180 buffer.WriteUInt32(reliability_param); 181 buffer.WriteUInt16(static_cast<uint16>(label.length())); 182 buffer.WriteUInt16(static_cast<uint16>(config.protocol.length())); 183 buffer.WriteString(label); 184 buffer.WriteString(config.protocol); 185 payload->SetData(buffer.Data(), buffer.Length()); 186 return true; 187 } 188 189 void WriteDataChannelOpenAckMessage(talk_base::Buffer* payload) { 190 talk_base::ByteBuffer buffer(talk_base::ByteBuffer::ORDER_NETWORK); 191 buffer.WriteUInt8(DATA_CHANNEL_OPEN_ACK_MESSAGE_TYPE); 192 payload->SetData(buffer.Data(), buffer.Length()); 193 } 194 } // namespace webrtc 195