henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [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 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "p2p/base/asyncstuntcpsocket.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 12 | |
| 13 | #include <string.h> |
| 14 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 15 | #include "p2p/base/stun.h" |
| 16 | #include "rtc_base/checks.h" |
| 17 | #include "rtc_base/logging.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 18 | |
| 19 | namespace cricket { |
| 20 | |
| 21 | static const size_t kMaxPacketSize = 64 * 1024; |
| 22 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 23 | typedef uint16_t PacketLength; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 24 | static const size_t kPacketLenSize = sizeof(PacketLength); |
| 25 | static const size_t kPacketLenOffset = 2; |
| 26 | static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize; |
| 27 | static const size_t kTurnChannelDataHdrSize = 4; |
| 28 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 29 | inline bool IsStunMessage(uint16_t msg_type) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 30 | // The first two bits of a channel data message are 0b01. |
| 31 | return (msg_type & 0xC000) ? false : true; |
| 32 | } |
| 33 | |
| 34 | // AsyncStunTCPSocket |
| 35 | // Binds and connects |socket| and creates AsyncTCPSocket for |
| 36 | // it. Takes ownership of |socket|. Returns NULL if bind() or |
| 37 | // connect() fail (|socket| is destroyed in that case). |
| 38 | AsyncStunTCPSocket* AsyncStunTCPSocket::Create( |
| 39 | rtc::AsyncSocket* socket, |
| 40 | const rtc::SocketAddress& bind_address, |
| 41 | const rtc::SocketAddress& remote_address) { |
| 42 | return new AsyncStunTCPSocket(AsyncTCPSocketBase::ConnectSocket( |
| 43 | socket, bind_address, remote_address), false); |
| 44 | } |
| 45 | |
| 46 | AsyncStunTCPSocket::AsyncStunTCPSocket( |
| 47 | rtc::AsyncSocket* socket, bool listen) |
| 48 | : rtc::AsyncTCPSocketBase(socket, listen, kBufSize) { |
| 49 | } |
| 50 | |
| 51 | int AsyncStunTCPSocket::Send(const void *pv, size_t cb, |
| 52 | const rtc::PacketOptions& options) { |
| 53 | if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) { |
| 54 | SetError(EMSGSIZE); |
| 55 | return -1; |
| 56 | } |
| 57 | |
| 58 | // If we are blocking on send, then silently drop this packet |
| 59 | if (!IsOutBufferEmpty()) |
| 60 | return static_cast<int>(cb); |
| 61 | |
| 62 | int pad_bytes; |
| 63 | size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes); |
| 64 | |
| 65 | // Accepts only complete STUN/ChannelData packets. |
| 66 | if (cb != expected_pkt_len) |
| 67 | return -1; |
| 68 | |
| 69 | AppendToOutBuffer(pv, cb); |
| 70 | |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 71 | RTC_DCHECK(pad_bytes < 4); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 72 | char padding[4] = {0}; |
| 73 | AppendToOutBuffer(padding, pad_bytes); |
| 74 | |
| 75 | int res = FlushOutBuffer(); |
| 76 | if (res <= 0) { |
| 77 | // drop packet if we made no progress |
| 78 | ClearOutBuffer(); |
| 79 | return res; |
| 80 | } |
| 81 | |
deadbeef | b56671e | 2017-05-26 18:40:05 -0700 | [diff] [blame] | 82 | rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis()); |
| 83 | SignalSentPacket(this, sent_packet); |
| 84 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 85 | // We claim to have sent the whole thing, even if we only sent partial |
| 86 | return static_cast<int>(cb); |
| 87 | } |
| 88 | |
| 89 | void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) { |
| 90 | rtc::SocketAddress remote_addr(GetRemoteAddress()); |
| 91 | // STUN packet - First 4 bytes. Total header size is 20 bytes. |
| 92 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 93 | // |0 0| STUN Message Type | Message Length | |
| 94 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 95 | |
| 96 | // TURN ChannelData |
| 97 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 98 | // | Channel Number | Length | |
| 99 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 100 | |
| 101 | while (true) { |
| 102 | // We need at least 4 bytes to read the STUN or ChannelData packet length. |
| 103 | if (*len < kPacketLenOffset + kPacketLenSize) |
| 104 | return; |
| 105 | |
| 106 | int pad_bytes; |
| 107 | size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes); |
| 108 | size_t actual_length = expected_pkt_len + pad_bytes; |
| 109 | |
| 110 | if (*len < actual_length) { |
| 111 | return; |
| 112 | } |
| 113 | |
| 114 | SignalReadPacket(this, data, expected_pkt_len, remote_addr, |
| 115 | rtc::CreatePacketTime(0)); |
| 116 | |
| 117 | *len -= actual_length; |
| 118 | if (*len > 0) { |
| 119 | memmove(data, data + actual_length, *len); |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | void AsyncStunTCPSocket::HandleIncomingConnection( |
| 125 | rtc::AsyncSocket* socket) { |
| 126 | SignalNewConnection(this, new AsyncStunTCPSocket(socket, false)); |
| 127 | } |
| 128 | |
| 129 | size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, 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; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 135 | uint16_t msg_type = rtc::GetBE16(data); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 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 |