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