henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 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 | |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 11 | #include "p2p/base/async_stun_tcp_socket.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 12 | |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 13 | #include <errno.h> |
| 14 | #include <stdint.h> |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 15 | #include <string.h> |
| 16 | |
Patrik Höglund | 56d9452 | 2019-11-18 14:53:32 | [diff] [blame] | 17 | #include "api/transport/stun.h" |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 18 | #include "rtc_base/byte_order.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 19 | #include "rtc_base/checks.h" |
Yves Gerey | 3e70781 | 2018-11-28 15:47:49 | [diff] [blame] | 20 | #include "rtc_base/network/sent_packet.h" |
| 21 | #include "rtc_base/third_party/sigslot/sigslot.h" |
Steve Anton | 10542f2 | 2019-01-11 17:11:00 | [diff] [blame] | 22 | #include "rtc_base/time_utils.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 23 | |
| 24 | namespace cricket { |
| 25 | |
| 26 | static const size_t kMaxPacketSize = 64 * 1024; |
| 27 | |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 28 | typedef uint16_t PacketLength; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 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 | |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 34 | inline bool IsStunMessage(uint16_t msg_type) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 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). |
| 43 | AsyncStunTCPSocket* AsyncStunTCPSocket::Create( |
| 44 | rtc::AsyncSocket* socket, |
| 45 | const rtc::SocketAddress& bind_address, |
| 46 | const rtc::SocketAddress& remote_address) { |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 47 | return new AsyncStunTCPSocket( |
| 48 | AsyncTCPSocketBase::ConnectSocket(socket, bind_address, remote_address), |
| 49 | false); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 50 | } |
| 51 | |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 52 | AsyncStunTCPSocket::AsyncStunTCPSocket(rtc::AsyncSocket* socket, bool listen) |
| 53 | : rtc::AsyncTCPSocketBase(socket, listen, kBufSize) {} |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 54 | |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 55 | int AsyncStunTCPSocket::Send(const void* pv, |
| 56 | size_t cb, |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 57 | const rtc::PacketOptions& options) { |
| 58 | if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) { |
| 59 | SetError(EMSGSIZE); |
| 60 | return -1; |
| 61 | } |
| 62 | |
| 63 | // If we are blocking on send, then silently drop this packet |
| 64 | if (!IsOutBufferEmpty()) |
| 65 | return static_cast<int>(cb); |
| 66 | |
| 67 | int pad_bytes; |
| 68 | size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes); |
| 69 | |
| 70 | // Accepts only complete STUN/ChannelData packets. |
| 71 | if (cb != expected_pkt_len) |
| 72 | return -1; |
| 73 | |
| 74 | AppendToOutBuffer(pv, cb); |
| 75 | |
nisse | ede5da4 | 2017-01-12 13:15:36 | [diff] [blame] | 76 | RTC_DCHECK(pad_bytes < 4); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 77 | char padding[4] = {0}; |
| 78 | AppendToOutBuffer(padding, pad_bytes); |
| 79 | |
| 80 | int res = FlushOutBuffer(); |
| 81 | if (res <= 0) { |
| 82 | // drop packet if we made no progress |
| 83 | ClearOutBuffer(); |
| 84 | return res; |
| 85 | } |
| 86 | |
deadbeef | b56671e | 2017-05-27 01:40:05 | [diff] [blame] | 87 | rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); |
| 88 | SignalSentPacket(this, sent_packet); |
| 89 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 90 | // We claim to have sent the whole thing, even if we only sent partial |
| 91 | return static_cast<int>(cb); |
| 92 | } |
| 93 | |
| 94 | void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) { |
| 95 | rtc::SocketAddress remote_addr(GetRemoteAddress()); |
| 96 | // STUN packet - First 4 bytes. Total header size is 20 bytes. |
| 97 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 98 | // |0 0| STUN Message Type | Message Length | |
| 99 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 100 | |
| 101 | // TURN ChannelData |
| 102 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 103 | // | Channel Number | Length | |
| 104 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 105 | |
| 106 | while (true) { |
| 107 | // We need at least 4 bytes to read the STUN or ChannelData packet length. |
| 108 | if (*len < kPacketLenOffset + kPacketLenSize) |
| 109 | return; |
| 110 | |
| 111 | int pad_bytes; |
| 112 | size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes); |
| 113 | size_t actual_length = expected_pkt_len + pad_bytes; |
| 114 | |
| 115 | if (*len < actual_length) { |
| 116 | return; |
| 117 | } |
| 118 | |
| 119 | SignalReadPacket(this, data, expected_pkt_len, remote_addr, |
Niels Möller | 15ca5a9 | 2018-11-01 13:32:47 | [diff] [blame] | 120 | rtc::TimeMicros()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 121 | |
| 122 | *len -= actual_length; |
| 123 | if (*len > 0) { |
| 124 | memmove(data, data + actual_length, *len); |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 129 | void AsyncStunTCPSocket::HandleIncomingConnection(rtc::AsyncSocket* socket) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 130 | SignalNewConnection(this, new AsyncStunTCPSocket(socket, false)); |
| 131 | } |
| 132 | |
Yves Gerey | 665174f | 2018-06-19 13:03:05 | [diff] [blame] | 133 | size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, |
| 134 | size_t len, |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 135 | int* pad_bytes) { |
| 136 | *pad_bytes = 0; |
| 137 | PacketLength pkt_len = |
| 138 | rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset); |
| 139 | size_t expected_pkt_len; |
Peter Boström | 0c4e06b | 2015-10-07 10:23:21 | [diff] [blame] | 140 | uint16_t msg_type = rtc::GetBE16(data); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 | [diff] [blame] | 141 | if (IsStunMessage(msg_type)) { |
| 142 | // STUN message. |
| 143 | expected_pkt_len = kStunHeaderSize + pkt_len; |
| 144 | } else { |
| 145 | // TURN ChannelData message. |
| 146 | expected_pkt_len = kTurnChannelDataHdrSize + pkt_len; |
| 147 | // From RFC 5766 section 11.5 |
| 148 | // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to |
| 149 | // a multiple of four bytes in order to ensure the alignment of |
| 150 | // subsequent messages. The padding is not reflected in the length |
| 151 | // field of the ChannelData message, so the actual size of a ChannelData |
| 152 | // message (including padding) is (4 + Length) rounded up to the nearest |
| 153 | // multiple of 4. Over UDP, the padding is not required but MAY be |
| 154 | // included. |
| 155 | if (expected_pkt_len % 4) |
| 156 | *pad_bytes = 4 - (expected_pkt_len % 4); |
| 157 | } |
| 158 | return expected_pkt_len; |
| 159 | } |
| 160 | |
| 161 | } // namespace cricket |