1/*
2 * libjingle
3 * Copyright 2004--2005, 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#ifndef TALK_P2P_BASE_PORTALLOCATOR_H_
29#define TALK_P2P_BASE_PORTALLOCATOR_H_
30
31#include <string>
32#include <vector>
33
34#include "talk/p2p/base/portinterface.h"
35#include "webrtc/base/helpers.h"
36#include "webrtc/base/proxyinfo.h"
37#include "webrtc/base/sigslot.h"
38
39namespace cricket {
40
41// PortAllocator is responsible for allocating Port types for a given
42// P2PSocket. It also handles port freeing.
43//
44// Clients can override this class to control port allocation, including
45// what kinds of ports are allocated.
46
47enum {
48  PORTALLOCATOR_DISABLE_UDP = 0x01,
49  PORTALLOCATOR_DISABLE_STUN = 0x02,
50  PORTALLOCATOR_DISABLE_RELAY = 0x04,
51  PORTALLOCATOR_DISABLE_TCP = 0x08,
52  PORTALLOCATOR_ENABLE_SHAKER = 0x10,
53  PORTALLOCATOR_ENABLE_BUNDLE = 0x20,
54  PORTALLOCATOR_ENABLE_IPV6 = 0x40,
55  PORTALLOCATOR_ENABLE_SHARED_UFRAG = 0x80,
56  PORTALLOCATOR_ENABLE_SHARED_SOCKET = 0x100,
57  PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE = 0x200,
58};
59
60const uint32 kDefaultPortAllocatorFlags = 0;
61
62const uint32 kDefaultStepDelay = 1000;  // 1 sec step delay.
63// As per RFC 5245 Appendix B.1, STUN transactions need to be paced at certain
64// internal. Less than 20ms is not acceptable. We choose 50ms as our default.
65const uint32 kMinimumStepDelay = 50;
66
67// CF = CANDIDATE FILTER
68enum {
69  CF_NONE = 0x0,
70  CF_HOST = 0x1,
71  CF_REFLEXIVE = 0x2,
72  CF_RELAY = 0x4,
73  CF_ALL = 0x7,
74};
75
76class PortAllocatorSessionMuxer;
77
78class PortAllocatorSession : public sigslot::has_slots<> {
79 public:
80  // Content name passed in mostly for logging and debugging.
81  // TODO(mallinath) - Change username and password to ice_ufrag and ice_pwd.
82  PortAllocatorSession(const std::string& content_name,
83                       int component,
84                       const std::string& username,
85                       const std::string& password,
86                       uint32 flags);
87
88  // Subclasses should clean up any ports created.
89  virtual ~PortAllocatorSession() {}
90
91  uint32 flags() const { return flags_; }
92  void set_flags(uint32 flags) { flags_ = flags; }
93  std::string content_name() const { return content_name_; }
94  int component() const { return component_; }
95
96  // Starts gathering STUN and Relay configurations.
97  virtual void StartGettingPorts() = 0;
98  virtual void StopGettingPorts() = 0;
99  virtual bool IsGettingPorts() = 0;
100
101  sigslot::signal2<PortAllocatorSession*, PortInterface*> SignalPortReady;
102  sigslot::signal2<PortAllocatorSession*,
103                   const std::vector<Candidate>&> SignalCandidatesReady;
104  sigslot::signal1<PortAllocatorSession*> SignalCandidatesAllocationDone;
105
106  virtual uint32 generation() { return generation_; }
107  virtual void set_generation(uint32 generation) { generation_ = generation; }
108  sigslot::signal1<PortAllocatorSession*> SignalDestroyed;
109
110 protected:
111  const std::string& username() const { return username_; }
112  const std::string& password() const { return password_; }
113
114  std::string content_name_;
115  int component_;
116
117 private:
118  uint32 flags_;
119  uint32 generation_;
120  std::string username_;
121  std::string password_;
122};
123
124class PortAllocator : public sigslot::has_slots<> {
125 public:
126  PortAllocator() :
127      flags_(kDefaultPortAllocatorFlags),
128      min_port_(0),
129      max_port_(0),
130      step_delay_(kDefaultStepDelay),
131      allow_tcp_listen_(true),
132      candidate_filter_(CF_ALL) {
133    // This will allow us to have old behavior on non webrtc clients.
134  }
135  virtual ~PortAllocator();
136
137  PortAllocatorSession* CreateSession(
138      const std::string& sid,
139      const std::string& content_name,
140      int component,
141      const std::string& ice_ufrag,
142      const std::string& ice_pwd);
143
144  PortAllocatorSessionMuxer* GetSessionMuxer(const std::string& key) const;
145  void OnSessionMuxerDestroyed(PortAllocatorSessionMuxer* session);
146
147  uint32 flags() const { return flags_; }
148  void set_flags(uint32 flags) { flags_ = flags; }
149
150  const std::string& user_agent() const { return agent_; }
151  const rtc::ProxyInfo& proxy() const { return proxy_; }
152  void set_proxy(const std::string& agent, const rtc::ProxyInfo& proxy) {
153    agent_ = agent;
154    proxy_ = proxy;
155  }
156
157  // Gets/Sets the port range to use when choosing client ports.
158  int min_port() const { return min_port_; }
159  int max_port() const { return max_port_; }
160  bool SetPortRange(int min_port, int max_port) {
161    if (min_port > max_port) {
162      return false;
163    }
164
165    min_port_ = min_port;
166    max_port_ = max_port;
167    return true;
168  }
169
170  uint32 step_delay() const { return step_delay_; }
171  void set_step_delay(uint32 delay) {
172    step_delay_ = delay;
173  }
174
175  bool allow_tcp_listen() const { return allow_tcp_listen_; }
176  void set_allow_tcp_listen(bool allow_tcp_listen) {
177    allow_tcp_listen_ = allow_tcp_listen;
178  }
179
180  uint32 candidate_filter() { return candidate_filter_; }
181  bool set_candidate_filter(uint32 filter) {
182    // TODO(mallinath) - Do transition check?
183    candidate_filter_ = filter;
184    return true;
185  }
186
187 protected:
188  virtual PortAllocatorSession* CreateSessionInternal(
189      const std::string& content_name,
190      int component,
191      const std::string& ice_ufrag,
192      const std::string& ice_pwd) = 0;
193
194  typedef std::map<std::string, PortAllocatorSessionMuxer*> SessionMuxerMap;
195
196  uint32 flags_;
197  std::string agent_;
198  rtc::ProxyInfo proxy_;
199  int min_port_;
200  int max_port_;
201  uint32 step_delay_;
202  SessionMuxerMap muxers_;
203  bool allow_tcp_listen_;
204  uint32 candidate_filter_;
205};
206
207}  // namespace cricket
208
209#endif  // TALK_P2P_BASE_PORTALLOCATOR_H_
210