3 * Copyright 2013, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "webrtc/p2p/base/asyncstuntcpsocket.h"
32 #include "webrtc/p2p/base/stun.h"
33 #include "webrtc/base/common.h"
34 #include "webrtc/base/logging.h"
38 static const size_t kMaxPacketSize = 64 * 1024;
40 typedef uint16 PacketLength;
41 static const size_t kPacketLenSize = sizeof(PacketLength);
42 static const size_t kPacketLenOffset = 2;
43 static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize;
44 static const size_t kTurnChannelDataHdrSize = 4;
46 inline bool IsStunMessage(uint16 msg_type) {
47 // The first two bits of a channel data message are 0b01.
48 return (msg_type & 0xC000) ? false : true;
52 // Binds and connects |socket| and creates AsyncTCPSocket for
53 // it. Takes ownership of |socket|. Returns NULL if bind() or
54 // connect() fail (|socket| is destroyed in that case).
55 AsyncStunTCPSocket* AsyncStunTCPSocket::Create(
56 rtc::AsyncSocket* socket,
57 const rtc::SocketAddress& bind_address,
58 const rtc::SocketAddress& remote_address) {
59 return new AsyncStunTCPSocket(AsyncTCPSocketBase::ConnectSocket(
60 socket, bind_address, remote_address), false);
63 AsyncStunTCPSocket::AsyncStunTCPSocket(
64 rtc::AsyncSocket* socket, bool listen)
65 : rtc::AsyncTCPSocketBase(socket, listen, kBufSize) {
68 int AsyncStunTCPSocket::Send(const void *pv, size_t cb,
69 const rtc::PacketOptions& options) {
70 if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) {
75 // If we are blocking on send, then silently drop this packet
76 if (!IsOutBufferEmpty())
77 return static_cast<int>(cb);
80 size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes);
82 // Accepts only complete STUN/ChannelData packets.
83 if (cb != expected_pkt_len)
86 AppendToOutBuffer(pv, cb);
88 ASSERT(pad_bytes < 4);
89 char padding[4] = {0};
90 AppendToOutBuffer(padding, pad_bytes);
92 int res = FlushOutBuffer();
94 // drop packet if we made no progress
99 // We claim to have sent the whole thing, even if we only sent partial
100 return static_cast<int>(cb);
103 void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) {
104 rtc::SocketAddress remote_addr(GetRemoteAddress());
105 // STUN packet - First 4 bytes. Total header size is 20 bytes.
106 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 // |0 0| STUN Message Type | Message Length |
108 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 // | Channel Number | Length |
113 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 // We need at least 4 bytes to read the STUN or ChannelData packet length.
117 if (*len < kPacketLenOffset + kPacketLenSize)
121 size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes);
122 size_t actual_length = expected_pkt_len + pad_bytes;
124 if (*len < actual_length) {
128 SignalReadPacket(this, data, expected_pkt_len, remote_addr,
129 rtc::CreatePacketTime(0));
131 *len -= actual_length;
133 memmove(data, data + actual_length, *len);
138 void AsyncStunTCPSocket::HandleIncomingConnection(
139 rtc::AsyncSocket* socket) {
140 SignalNewConnection(this, new AsyncStunTCPSocket(socket, false));
143 size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, size_t len,
146 PacketLength pkt_len =
147 rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset);
148 size_t expected_pkt_len;
149 uint16 msg_type = rtc::GetBE16(data);
150 if (IsStunMessage(msg_type)) {
152 expected_pkt_len = kStunHeaderSize + pkt_len;
154 // TURN ChannelData message.
155 expected_pkt_len = kTurnChannelDataHdrSize + pkt_len;
156 // From RFC 5766 section 11.5
157 // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
158 // a multiple of four bytes in order to ensure the alignment of
159 // subsequent messages. The padding is not reflected in the length
160 // field of the ChannelData message, so the actual size of a ChannelData
161 // message (including padding) is (4 + Length) rounded up to the nearest
162 // multiple of 4. Over UDP, the padding is not required but MAY be
164 if (expected_pkt_len % 4)
165 *pad_bytes = 4 - (expected_pkt_len % 4);
167 return expected_pkt_len;
170 } // namespace cricket