Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2013, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/p2p/base/asyncstuntcpsocket.h"
     29 
     30 #include <cstring>
     31 
     32 #include "talk/base/common.h"
     33 #include "talk/base/logging.h"
     34 #include "talk/p2p/base/stun.h"
     35 
     36 namespace cricket {
     37 
     38 static const size_t kMaxPacketSize = 64 * 1024;
     39 
     40 typedef uint16 PacketLength;
     41 static const size_t kPacketLenSize = sizeof(PacketLength);
     42 static const size_t kPacketLenOffset = 2;
     43 static const size_t kBufSize = kMaxPacketSize + kStunHeaderSize;
     44 static const size_t kTurnChannelDataHdrSize = 4;
     45 
     46 inline bool IsStunMessage(uint16 msg_type) {
     47   // The first two bits of a channel data message are 0b01.
     48   return (msg_type & 0xC000) ? false : true;
     49 }
     50 
     51 // AsyncStunTCPSocket
     52 // Binds and connects |socket| and creates AsyncTCPSocket for
     53 // it. Takes ownership of |socket|. Returns NULL if bind() or
     54 // connect() fail (|socket| is destroyed in that case).
     55 AsyncStunTCPSocket* AsyncStunTCPSocket::Create(
     56     talk_base::AsyncSocket* socket,
     57     const talk_base::SocketAddress& bind_address,
     58     const talk_base::SocketAddress& remote_address) {
     59   return new AsyncStunTCPSocket(AsyncTCPSocketBase::ConnectSocket(
     60       socket, bind_address, remote_address), false);
     61 }
     62 
     63 AsyncStunTCPSocket::AsyncStunTCPSocket(
     64     talk_base::AsyncSocket* socket, bool listen)
     65     : talk_base::AsyncTCPSocketBase(socket, listen, kBufSize) {
     66 }
     67 
     68 int AsyncStunTCPSocket::Send(const void *pv, size_t cb) {
     69   if (cb > kBufSize || cb < kPacketLenSize + kPacketLenOffset) {
     70     SetError(EMSGSIZE);
     71     return -1;
     72   }
     73 
     74   // If we are blocking on send, then silently drop this packet
     75   if (!IsOutBufferEmpty())
     76     return static_cast<int>(cb);
     77 
     78   int pad_bytes;
     79   size_t expected_pkt_len = GetExpectedLength(pv, cb, &pad_bytes);
     80 
     81   // Accepts only complete STUN/ChannelData packets.
     82   if (cb != expected_pkt_len)
     83     return -1;
     84 
     85   AppendToOutBuffer(pv, cb);
     86 
     87   ASSERT(pad_bytes < 4);
     88   char padding[4] = {0};
     89   AppendToOutBuffer(padding, pad_bytes);
     90 
     91   int res = FlushOutBuffer();
     92   if (res <= 0) {
     93     // drop packet if we made no progress
     94     ClearOutBuffer();
     95     return res;
     96   }
     97 
     98   // We claim to have sent the whole thing, even if we only sent partial
     99   return static_cast<int>(cb);
    100 }
    101 
    102 void AsyncStunTCPSocket::ProcessInput(char* data, size_t* len) {
    103   talk_base::SocketAddress remote_addr(GetRemoteAddress());
    104   // STUN packet - First 4 bytes. Total header size is 20 bytes.
    105   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    106   // |0 0|     STUN Message Type     |         Message Length        |
    107   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    108 
    109   // TURN ChannelData
    110   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    111   // |         Channel Number        |            Length             |
    112   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    113 
    114   while (true) {
    115     // We need at least 4 bytes to read the STUN or ChannelData packet length.
    116     if (*len < kPacketLenOffset + kPacketLenSize)
    117       return;
    118 
    119     int pad_bytes;
    120     size_t expected_pkt_len = GetExpectedLength(data, *len, &pad_bytes);
    121     size_t actual_length = expected_pkt_len + pad_bytes;
    122 
    123     if (*len < actual_length) {
    124       return;
    125     }
    126 
    127     SignalReadPacket(this, data, expected_pkt_len, remote_addr);
    128 
    129     *len -= actual_length;
    130     if (*len > 0) {
    131       memmove(data, data + actual_length, *len);
    132     }
    133   }
    134 }
    135 
    136 void AsyncStunTCPSocket::HandleIncomingConnection(
    137     talk_base::AsyncSocket* socket) {
    138   SignalNewConnection(this, new AsyncStunTCPSocket(socket, false));
    139 }
    140 
    141 size_t AsyncStunTCPSocket::GetExpectedLength(const void* data, size_t len,
    142                                              int* pad_bytes) {
    143   *pad_bytes = 0;
    144   PacketLength pkt_len =
    145       talk_base::GetBE16(static_cast<const char*>(data) + kPacketLenOffset);
    146   size_t expected_pkt_len;
    147   uint16 msg_type = talk_base::GetBE16(data);
    148   if (IsStunMessage(msg_type)) {
    149     // STUN message.
    150     expected_pkt_len = kStunHeaderSize + pkt_len;
    151   } else {
    152     // TURN ChannelData message.
    153     expected_pkt_len = kTurnChannelDataHdrSize + pkt_len;
    154     // From RFC 5766 section 11.5
    155     // Over TCP and TLS-over-TCP, the ChannelData message MUST be padded to
    156     // a multiple of four bytes in order to ensure the alignment of
    157     // subsequent messages.  The padding is not reflected in the length
    158     // field of the ChannelData message, so the actual size of a ChannelData
    159     // message (including padding) is (4 + Length) rounded up to the nearest
    160     // multiple of 4.  Over UDP, the padding is not required but MAY be
    161     // included.
    162     if (expected_pkt_len % 4)
    163       *pad_bytes = 4 - (expected_pkt_len % 4);
    164   }
    165   return expected_pkt_len;
    166 }
    167 
    168 }  // namespace cricket
    169