1/*
2 *  Copyright 2008 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#ifndef WEBRTC_P2P_BASE_TESTRELAYSERVER_H_
12#define WEBRTC_P2P_BASE_TESTRELAYSERVER_H_
13
14#include "webrtc/p2p/base/relayserver.h"
15#include "webrtc/base/asynctcpsocket.h"
16#include "webrtc/base/scoped_ptr.h"
17#include "webrtc/base/sigslot.h"
18#include "webrtc/base/socketadapters.h"
19#include "webrtc/base/thread.h"
20
21namespace cricket {
22
23// A test relay server. Useful for unit tests.
24class TestRelayServer : public sigslot::has_slots<> {
25 public:
26  TestRelayServer(rtc::Thread* thread,
27                  const rtc::SocketAddress& udp_int_addr,
28                  const rtc::SocketAddress& udp_ext_addr,
29                  const rtc::SocketAddress& tcp_int_addr,
30                  const rtc::SocketAddress& tcp_ext_addr,
31                  const rtc::SocketAddress& ssl_int_addr,
32                  const rtc::SocketAddress& ssl_ext_addr)
33      : server_(thread) {
34    server_.AddInternalSocket(rtc::AsyncUDPSocket::Create(
35        thread->socketserver(), udp_int_addr));
36    server_.AddExternalSocket(rtc::AsyncUDPSocket::Create(
37        thread->socketserver(), udp_ext_addr));
38
39    tcp_int_socket_.reset(CreateListenSocket(thread, tcp_int_addr));
40    tcp_ext_socket_.reset(CreateListenSocket(thread, tcp_ext_addr));
41    ssl_int_socket_.reset(CreateListenSocket(thread, ssl_int_addr));
42    ssl_ext_socket_.reset(CreateListenSocket(thread, ssl_ext_addr));
43  }
44  int GetConnectionCount() const {
45    return server_.GetConnectionCount();
46  }
47  rtc::SocketAddressPair GetConnection(int connection) const {
48    return server_.GetConnection(connection);
49  }
50  bool HasConnection(const rtc::SocketAddress& address) const {
51    return server_.HasConnection(address);
52  }
53
54 private:
55  rtc::AsyncSocket* CreateListenSocket(rtc::Thread* thread,
56      const rtc::SocketAddress& addr) {
57    rtc::AsyncSocket* socket =
58        thread->socketserver()->CreateAsyncSocket(addr.family(), SOCK_STREAM);
59    socket->Bind(addr);
60    socket->Listen(5);
61    socket->SignalReadEvent.connect(this, &TestRelayServer::OnAccept);
62    return socket;
63  }
64  void OnAccept(rtc::AsyncSocket* socket) {
65    bool external = (socket == tcp_ext_socket_.get() ||
66                     socket == ssl_ext_socket_.get());
67    bool ssl = (socket == ssl_int_socket_.get() ||
68                socket == ssl_ext_socket_.get());
69    rtc::AsyncSocket* raw_socket = socket->Accept(NULL);
70    if (raw_socket) {
71      rtc::AsyncTCPSocket* packet_socket = new rtc::AsyncTCPSocket(
72          (!ssl) ? raw_socket :
73          new rtc::AsyncSSLServerSocket(raw_socket), false);
74      if (!external) {
75        packet_socket->SignalClose.connect(this,
76            &TestRelayServer::OnInternalClose);
77        server_.AddInternalSocket(packet_socket);
78      } else {
79        packet_socket->SignalClose.connect(this,
80            &TestRelayServer::OnExternalClose);
81        server_.AddExternalSocket(packet_socket);
82      }
83    }
84  }
85  void OnInternalClose(rtc::AsyncPacketSocket* socket, int error) {
86    server_.RemoveInternalSocket(socket);
87  }
88  void OnExternalClose(rtc::AsyncPacketSocket* socket, int error) {
89    server_.RemoveExternalSocket(socket);
90  }
91 private:
92  cricket::RelayServer server_;
93  rtc::scoped_ptr<rtc::AsyncSocket> tcp_int_socket_;
94  rtc::scoped_ptr<rtc::AsyncSocket> tcp_ext_socket_;
95  rtc::scoped_ptr<rtc::AsyncSocket> ssl_int_socket_;
96  rtc::scoped_ptr<rtc::AsyncSocket> ssl_ext_socket_;
97};
98
99}  // namespace cricket
100
101#endif  // WEBRTC_P2P_BASE_TESTRELAYSERVER_H_
102