Home | History | Annotate | Download | only in base
      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 "webrtc/p2p/base/asyncstuntcpsocket.h"
     12 
     13 #include <string.h>
     14 
     15 #include "webrtc/p2p/base/stun.h"
     16 #include "webrtc/base/common.h"
     17 #include "webrtc/base/logging.h"
     18 
     19 namespace cricket {
     20 
     21 static const size_t kMaxPacketSize = 64 * 1024;
     22 
     23 typedef uint16_t PacketLength;
     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 
     29 inline bool IsStunMessage(uint16_t msg_type) {
     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 
     71   ASSERT(pad_bytes < 4);
     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 
     82   // We claim to have sent the whole thing, even if we only sent partial
     83   return static_cast<int>(cb);
     84 }
     85 
     86 void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) {
     87   rtc::SocketAddress remote_addr(GetRemoteAddress());
     88   // STUN packet - First 4 bytes. Total header size is 20 bytes.
     89   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     90   // |0 0|     STUN Message Type     |         Message Length        |
     91   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     92 
     93   // TURN ChannelData
     94   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     95   // |         Channel Number        |            Length             |
     96   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     97 
     98   while (true) {
     99     // We need at least 4 bytes to read the STUN or ChannelData packet length.
    100     if (*len < kPacketLenOffset + kPacketLenSize)
    101       return;
    102 
    103     int pad_bytes;
    104     size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes);
    105     size_t actual_length = expected_pkt_len + pad_bytes;
    106 
    107     if (*len < actual_length) {
    108       return;
    109     }
    110 
    111     SignalReadPacket(this, data, expected_pkt_len, remote_addr,
    112                      rtc::CreatePacketTime(0));
    113 
    114     *len -= actual_length;
    115     if (*len > 0) {
    116       memmove(data, data + actual_length, *len);
    117     }
    118   }
    119 }
    120 
    121 void AsyncStunTCPSocket::HandleIncomingConnection(
    122     rtc::AsyncSocket* socket) {
    123   SignalNewConnection(this, new AsyncStunTCPSocket(socket, false));
    124 }
    125 
    126 size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, size_t len,
    127                                              int* pad_bytes) {
    128   *pad_bytes = 0;
    129   PacketLength pkt_len =
    130       rtc::GetBE16(static_cast<const char*>(data) + kPacketLenOffset);
    131   size_t expected_pkt_len;
    132   uint16_t msg_type = rtc::GetBE16(data);
    133   if (IsStunMessage(msg_type)) {
    134     // STUN message.
    135     expected_pkt_len = kStunHeaderSize + pkt_len;
    136   } else {
    137     // TURN ChannelData message.
    138     expected_pkt_len = kTurnChannelDataHdrSize + pkt_len;
    139     // From RFC 5766 section 11.5
    140     // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
    141     // a multiple of four bytes in order to ensure the alignment of
    142     // subsequent messages.  The padding is not reflected in the length
    143     // field of the ChannelData message, so the actual size of a ChannelData
    144     // message (including padding) is (4 + Length) rounded up to the nearest
    145     // multiple of 4.  Over UDP, the padding is not required but MAY be
    146     // included.
    147     if (expected_pkt_len % 4)
    148       *pad_bytes = 4 - (expected_pkt_len % 4);
    149   }
    150   return expected_pkt_len;
    151 }
    152 
    153 }  // namespace cricket
    154