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 "p2p/base/async_stun_tcp_socket.h"
12
13 #include <errno.h>
14 #include <stdint.h>
15 #include <string.h>
16
17 #include "api/transport/stun.h"
18 #include "rtc_base/byte_order.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/network/sent_packet.h"
21 #include "rtc_base/third_party/sigslot/sigslot.h"
22 #include "rtc_base/time_utils.h"
23
24 namespace cricket {
25
26 static const size_t kMaxPacketSize = 64 * 1024;
27
28 typedef uint16_t PacketLength;
29 static const size_t kPacketLenSize = sizeof(PacketLength);
30 static const size_t kPacketLenOffset = 2;
31 static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize;
32 static const size_t kTurnChannelDataHdrSize = 4;
33
IsStunMessage(uint16_t msg_type)34 inline bool IsStunMessage(uint16_t msg_type) {
35 // The first two bits of a channel data message are 0b01.
36 return (msg_type & 0xC000) ? false : true;
37 }
38
39 // AsyncStunTCPSocket
40 // Binds and connects `socket` and creates AsyncTCPSocket for
41 // it. Takes ownership of `socket`. Returns NULL if bind() or
42 // connect() fail (`socket` is destroyed in that case).
Create(rtc::Socket * socket,const rtc::SocketAddress & bind_address,const rtc::SocketAddress & remote_address)43 AsyncStunTCPSocket* AsyncStunTCPSocket::Create(
44 rtc::Socket* socket,
45 const rtc::SocketAddress& bind_address,
46 const rtc::SocketAddress& remote_address) {
47 return new AsyncStunTCPSocket(
48 AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address));
49 }
50
AsyncStunTCPSocket(rtc::Socket * socket)51 AsyncStunTCPSocket::AsyncStunTCPSocket(rtc::Socket* socket)
52 : rtc::AsyncTCPSocketBase(socket, kBufSize) {}
53
Send(const void * pv,size_t cb,const rtc::PacketOptions & options)54 int AsyncStunTCPSocket::Send(const void* pv,
55 size_t cb,
56 const rtc::PacketOptions& options) {
57 if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) {
58 SetError(EMSGSIZE);
59 return -1;
60 }
61
62 // If we are blocking on send, then silently drop this packet
63 if (!IsOutBufferEmpty())
64 return static_cast<int>(cb);
65
66 int pad_bytes;
67 size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes);
68
69 // Accepts only complete STUN/ChannelData packets.
70 if (cb != expected_pkt_len)
71 return -1;
72
73 AppendToOutBuffer(pv, cb);
74
75 RTC_DCHECK(pad_bytes < 4);
76 char padding[4] = {0};
77 AppendToOutBuffer(padding, pad_bytes);
78
79 int res = FlushOutBuffer();
80 if (res <= 0) {
81 // drop packet if we made no progress
82 ClearOutBuffer();
83 return res;
84 }
85
86 rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis());
87 SignalSentPacket(this, sent_packet);
88
89 // We claim to have sent the whole thing, even if we only sent partial
90 return static_cast<int>(cb);
91 }
92
ProcessInput(char * data,size_t * len)93 void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) {
94 rtc::SocketAddress remote_addr(GetRemoteAddress());
95 // STUN packet - First 4 bytes. Total header size is 20 bytes.
96 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 // |0 0| STUN Message Type | Message Length |
98 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99
100 // TURN ChannelData
101 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 // | Channel Number | Length |
103 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104
105 while (true) {
106 // We need at least 4 bytes to read the STUN or ChannelData packet length.
107 if (*len < kPacketLenOffset + kPacketLenSize)
108 return;
109
110 int pad_bytes;
111 size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes);
112 size_t actual_length = expected_pkt_len + pad_bytes;
113
114 if (*len < actual_length) {
115 return;
116 }
117
118 SignalReadPacket(this, data, expected_pkt_len, remote_addr,
119 rtc::TimeMicros());
120
121 *len -= actual_length;
122 if (*len > 0) {
123 memmove(data, data + actual_length, *len);
124 }
125 }
126 }
127
GetExpectedLength(const void * data,size_t len,int * pad_bytes)128 size_t AsyncStunTCPSocket::GetExpectedLength(const void* data,
129 size_t len,
130 int* pad_bytes) {
131 *pad_bytes = 0;
132 PacketLength pkt_len =
133 rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset);
134 size_t expected_pkt_len;
135 uint16_t msg_type = rtc::GetBE16(data);
136 if (IsStunMessage(msg_type)) {
137 // STUN message.
138 expected_pkt_len = kStunHeaderSize + pkt_len;
139 } else {
140 // TURN ChannelData message.
141 expected_pkt_len = kTurnChannelDataHdrSize + pkt_len;
142 // From RFC 5766 section 11.5
143 // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
144 // a multiple of four bytes in order to ensure the alignment of
145 // subsequent messages. The padding is not reflected in the length
146 // field of the ChannelData message, so the actual size of a ChannelData
147 // message (including padding) is (4 + Length) rounded up to the nearest
148 // multiple of 4. Over UDP, the padding is not required but MAY be
149 // included.
150 if (expected_pkt_len % 4)
151 *pad_bytes = 4 - (expected_pkt_len % 4);
152 }
153 return expected_pkt_len;
154 }
155
156 } // namespace cricket
157