Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2011 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/basicpacketsocketfactory.h"
     12 
     13 #include "webrtc/p2p/base/asyncstuntcpsocket.h"
     14 #include "webrtc/p2p/base/stun.h"
     15 #include "webrtc/base/asynctcpsocket.h"
     16 #include "webrtc/base/asyncudpsocket.h"
     17 #include "webrtc/base/logging.h"
     18 #include "webrtc/base/nethelpers.h"
     19 #include "webrtc/base/physicalsocketserver.h"
     20 #include "webrtc/base/scoped_ptr.h"
     21 #include "webrtc/base/socketadapters.h"
     22 #include "webrtc/base/ssladapter.h"
     23 #include "webrtc/base/thread.h"
     24 
     25 namespace rtc {
     26 
     27 BasicPacketSocketFactory::BasicPacketSocketFactory()
     28     : thread_(Thread::Current()),
     29       socket_factory_(NULL) {
     30 }
     31 
     32 BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread)
     33     : thread_(thread),
     34       socket_factory_(NULL) {
     35 }
     36 
     37 BasicPacketSocketFactory::BasicPacketSocketFactory(
     38     SocketFactory* socket_factory)
     39     : thread_(NULL),
     40       socket_factory_(socket_factory) {
     41 }
     42 
     43 BasicPacketSocketFactory::~BasicPacketSocketFactory() {
     44 }
     45 
     46 AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket(
     47     const SocketAddress& address,
     48     uint16_t min_port,
     49     uint16_t max_port) {
     50   // UDP sockets are simple.
     51   rtc::AsyncSocket* socket =
     52       socket_factory()->CreateAsyncSocket(
     53           address.family(), SOCK_DGRAM);
     54   if (!socket) {
     55     return NULL;
     56   }
     57   if (BindSocket(socket, address, min_port, max_port) < 0) {
     58     LOG(LS_ERROR) << "UDP bind failed with error "
     59                     << socket->GetError();
     60     delete socket;
     61     return NULL;
     62   }
     63   return new rtc::AsyncUDPSocket(socket);
     64 }
     65 
     66 AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket(
     67     const SocketAddress& local_address,
     68     uint16_t min_port,
     69     uint16_t max_port,
     70     int opts) {
     71   // Fail if TLS is required.
     72   if (opts & PacketSocketFactory::OPT_TLS) {
     73     LOG(LS_ERROR) << "TLS support currently is not available.";
     74     return NULL;
     75   }
     76 
     77   rtc::AsyncSocket* socket =
     78       socket_factory()->CreateAsyncSocket(local_address.family(),
     79                                           SOCK_STREAM);
     80   if (!socket) {
     81     return NULL;
     82   }
     83 
     84   if (BindSocket(socket, local_address, min_port, max_port) < 0) {
     85     LOG(LS_ERROR) << "TCP bind failed with error "
     86                   << socket->GetError();
     87     delete socket;
     88     return NULL;
     89   }
     90 
     91   // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
     92   if (opts & PacketSocketFactory::OPT_SSLTCP) {
     93     ASSERT(!(opts & PacketSocketFactory::OPT_TLS));
     94     socket = new rtc::AsyncSSLSocket(socket);
     95   }
     96 
     97   // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
     98   // See http://go/gtalktcpnodelayexperiment
     99   socket->SetOption(rtc::Socket::OPT_NODELAY, 1);
    100 
    101   if (opts & PacketSocketFactory::OPT_STUN)
    102     return new cricket::AsyncStunTCPSocket(socket, true);
    103 
    104   return new rtc::AsyncTCPSocket(socket, true);
    105 }
    106 
    107 AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
    108     const SocketAddress& local_address, const SocketAddress& remote_address,
    109     const ProxyInfo& proxy_info, const std::string& user_agent, int opts) {
    110 
    111   rtc::AsyncSocket* socket =
    112       socket_factory()->CreateAsyncSocket(local_address.family(), SOCK_STREAM);
    113   if (!socket) {
    114     return NULL;
    115   }
    116 
    117   if (BindSocket(socket, local_address, 0, 0) < 0) {
    118     LOG(LS_ERROR) << "TCP bind failed with error "
    119                   << socket->GetError();
    120     delete socket;
    121     return NULL;
    122   }
    123 
    124   // If using a proxy, wrap the socket in a proxy socket.
    125   if (proxy_info.type == rtc::PROXY_SOCKS5) {
    126     socket = new rtc::AsyncSocksProxySocket(
    127         socket, proxy_info.address, proxy_info.username, proxy_info.password);
    128   } else if (proxy_info.type == rtc::PROXY_HTTPS) {
    129     socket = new rtc::AsyncHttpsProxySocket(
    130         socket, user_agent, proxy_info.address,
    131         proxy_info.username, proxy_info.password);
    132   }
    133 
    134   // If using TLS, wrap the socket in an SSL adapter.
    135   if (opts & PacketSocketFactory::OPT_TLS) {
    136     ASSERT(!(opts & PacketSocketFactory::OPT_SSLTCP));
    137 
    138     rtc::SSLAdapter* ssl_adapter = rtc::SSLAdapter::Create(socket);
    139     if (!ssl_adapter) {
    140       return NULL;
    141     }
    142 
    143     socket = ssl_adapter;
    144 
    145     if (ssl_adapter->StartSSL(remote_address.hostname().c_str(), false) != 0) {
    146       delete ssl_adapter;
    147       return NULL;
    148     }
    149 
    150   // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket.
    151   } else if (opts & PacketSocketFactory::OPT_SSLTCP) {
    152     ASSERT(!(opts & PacketSocketFactory::OPT_TLS));
    153     socket = new rtc::AsyncSSLSocket(socket);
    154   }
    155 
    156   if (socket->Connect(remote_address) < 0) {
    157     LOG(LS_ERROR) << "TCP connect failed with error "
    158                   << socket->GetError();
    159     delete socket;
    160     return NULL;
    161   }
    162 
    163   // Finally, wrap that socket in a TCP or STUN TCP packet socket.
    164   AsyncPacketSocket* tcp_socket;
    165   if (opts & PacketSocketFactory::OPT_STUN) {
    166     tcp_socket = new cricket::AsyncStunTCPSocket(socket, false);
    167   } else {
    168     tcp_socket = new rtc::AsyncTCPSocket(socket, false);
    169   }
    170 
    171   // Set TCP_NODELAY (via OPT_NODELAY) for improved performance.
    172   // See http://go/gtalktcpnodelayexperiment
    173   tcp_socket->SetOption(rtc::Socket::OPT_NODELAY, 1);
    174 
    175   return tcp_socket;
    176 }
    177 
    178 AsyncResolverInterface* BasicPacketSocketFactory::CreateAsyncResolver() {
    179   return new rtc::AsyncResolver();
    180 }
    181 
    182 int BasicPacketSocketFactory::BindSocket(AsyncSocket* socket,
    183                                          const SocketAddress& local_address,
    184                                          uint16_t min_port,
    185                                          uint16_t max_port) {
    186   int ret = -1;
    187   if (min_port == 0 && max_port == 0) {
    188     // If there's no port range, let the OS pick a port for us.
    189     ret = socket->Bind(local_address);
    190   } else {
    191     // Otherwise, try to find a port in the provided range.
    192     for (int port = min_port; ret < 0 && port <= max_port; ++port) {
    193       ret = socket->Bind(rtc::SocketAddress(local_address.ipaddr(),
    194                                                   port));
    195     }
    196   }
    197   return ret;
    198 }
    199 
    200 SocketFactory* BasicPacketSocketFactory::socket_factory() {
    201   if (thread_) {
    202     ASSERT(thread_ == Thread::Current());
    203     return thread_->socketserver();
    204   } else {
    205     return socket_factory_;
    206   }
    207 }
    208 
    209 }  // namespace rtc
    210