| /* |
| * libjingle |
| * Copyright 2011, Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "talk/base/basicpacketsocketfactory.h" |
| |
| #include "talk/base/asyncudpsocket.h" |
| #include "talk/base/asynctcpsocket.h" |
| #include "talk/base/logging.h" |
| #include "talk/base/socketadapters.h" |
| #include "talk/base/thread.h" |
| |
| namespace talk_base { |
| |
| BasicPacketSocketFactory::BasicPacketSocketFactory() |
| : thread_(Thread::Current()), |
| socket_factory_(NULL) { |
| } |
| |
| BasicPacketSocketFactory::BasicPacketSocketFactory(Thread* thread) |
| : thread_(thread), |
| socket_factory_(NULL) { |
| } |
| |
| BasicPacketSocketFactory::BasicPacketSocketFactory( |
| SocketFactory* socket_factory) |
| : thread_(NULL), |
| socket_factory_(socket_factory) { |
| } |
| |
| BasicPacketSocketFactory::~BasicPacketSocketFactory() { |
| } |
| |
| AsyncPacketSocket* BasicPacketSocketFactory::CreateUdpSocket( |
| const SocketAddress& address, int min_port, int max_port) { |
| // UDP sockets are simple. |
| talk_base::AsyncSocket* socket = |
| socket_factory()->CreateAsyncSocket(SOCK_DGRAM); |
| if (!socket) { |
| return NULL; |
| } |
| if (BindSocket(socket, address, min_port, max_port) < 0) { |
| LOG(LS_ERROR) << "UDP bind failed with error " |
| << socket->GetError(); |
| delete socket; |
| return NULL; |
| } |
| return new talk_base::AsyncUDPSocket(socket); |
| } |
| |
| AsyncPacketSocket* BasicPacketSocketFactory::CreateServerTcpSocket( |
| const SocketAddress& local_address, int min_port, int max_port, bool ssl) { |
| talk_base::AsyncSocket* socket = |
| socket_factory()->CreateAsyncSocket(SOCK_STREAM); |
| if (!socket) { |
| return NULL; |
| } |
| |
| if (BindSocket(socket, local_address, min_port, max_port) < 0) { |
| LOG(LS_ERROR) << "TCP bind failed with error " |
| << socket->GetError(); |
| delete socket; |
| return NULL; |
| } |
| |
| // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. |
| if (ssl) { |
| socket = new talk_base::AsyncSSLSocket(socket); |
| } |
| |
| // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. |
| // See http://go/gtalktcpnodelayexperiment |
| socket->SetOption(talk_base::Socket::OPT_NODELAY, 1); |
| |
| return new talk_base::AsyncTCPSocket(socket, true); |
| } |
| |
| AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket( |
| const SocketAddress& local_address, const SocketAddress& remote_address, |
| const ProxyInfo& proxy_info, const std::string& user_agent, bool ssl) { |
| talk_base::AsyncSocket* socket = |
| socket_factory()->CreateAsyncSocket(SOCK_STREAM); |
| if (!socket) { |
| return NULL; |
| } |
| |
| if (BindSocket(socket, local_address, 0, 0) < 0) { |
| LOG(LS_ERROR) << "TCP bind failed with error " |
| << socket->GetError(); |
| delete socket; |
| return NULL; |
| } |
| |
| // If using a proxy, wrap the socket in a proxy socket. |
| if (proxy_info.type == talk_base::PROXY_SOCKS5) { |
| socket = new talk_base::AsyncSocksProxySocket( |
| socket, proxy_info.address, proxy_info.username, proxy_info.password); |
| } else if (proxy_info.type == talk_base::PROXY_HTTPS) { |
| socket = new talk_base::AsyncHttpsProxySocket( |
| socket, user_agent, proxy_info.address, |
| proxy_info.username, proxy_info.password); |
| } |
| |
| // If using SSLTCP, wrap the TCP socket in a pseudo-SSL socket. |
| if (ssl) { |
| socket = new talk_base::AsyncSSLSocket(socket); |
| } |
| |
| if (socket->Connect(remote_address) < 0) { |
| LOG(LS_ERROR) << "TCP connect failed with error " |
| << socket->GetError(); |
| delete socket; |
| return NULL; |
| } |
| |
| // Finally, wrap that socket in a TCP packet socket. |
| talk_base::AsyncTCPSocket* tcp_socket = |
| new talk_base::AsyncTCPSocket(socket, false); |
| |
| // Set TCP_NODELAY (via OPT_NODELAY) for improved performance. |
| // See http://go/gtalktcpnodelayexperiment |
| tcp_socket->SetOption(talk_base::Socket::OPT_NODELAY, 1); |
| |
| return tcp_socket; |
| } |
| |
| int BasicPacketSocketFactory::BindSocket( |
| AsyncSocket* socket, const SocketAddress& local_address, |
| int min_port, int max_port) { |
| int ret = -1; |
| if (min_port == 0 && max_port == 0) { |
| // If there's no port range, let the OS pick a port for us. |
| ret = socket->Bind(local_address); |
| } else { |
| // Otherwise, try to find a port in the provided range. |
| for (int port = min_port; ret < 0 && port <= max_port; ++port) { |
| ret = socket->Bind(talk_base::SocketAddress(local_address.ipaddr(), |
| port)); |
| } |
| } |
| return ret; |
| } |
| |
| SocketFactory* BasicPacketSocketFactory::socket_factory() { |
| if (thread_) { |
| ASSERT(thread_ == Thread::Current()); |
| return thread_->socketserver(); |
| } else { |
| return socket_factory_; |
| } |
| } |
| |
| } // namespace talk_base |