1/*
2 * libjingle
3 * Copyright 2012, 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_TURNSERVER_H_
29#define TALK_P2P_BASE_TURNSERVER_H_
30
31#include <list>
32#include <map>
33#include <set>
34#include <string>
35
36#include "talk/base/asyncpacketsocket.h"
37#include "talk/base/messagequeue.h"
38#include "talk/base/sigslot.h"
39#include "talk/base/socketaddress.h"
40#include "talk/p2p/base/portinterface.h"
41
42namespace talk_base {
43class ByteBuffer;
44class PacketSocketFactory;
45class Thread;
46}
47
48namespace cricket {
49
50class StunMessage;
51class TurnMessage;
52
53// The default server port for TURN, as specified in RFC5766.
54const int TURN_SERVER_PORT = 3478;
55
56// An interface through which the MD5 credential hash can be retrieved.
57class TurnAuthInterface {
58 public:
59  // Gets HA1 for the specified user and realm.
60  // HA1 = MD5(A1) = MD5(username:realm:password).
61  // Return true if the given username and realm are valid, or false if not.
62  virtual bool GetKey(const std::string& username, const std::string& realm,
63                      std::string* key) = 0;
64};
65
66// The core TURN server class. Give it a socket to listen on via
67// AddInternalServerSocket, and a factory to create external sockets via
68// SetExternalSocketFactory, and it's ready to go.
69// Not yet wired up: TCP support.
70class TurnServer : public sigslot::has_slots<> {
71 public:
72  explicit TurnServer(talk_base::Thread* thread);
73  ~TurnServer();
74
75  // Gets/sets the realm value to use for the server.
76  const std::string& realm() const { return realm_; }
77  void set_realm(const std::string& realm) { realm_ = realm; }
78
79  // Gets/sets the value for the SOFTWARE attribute for TURN messages.
80  const std::string& software() const { return software_; }
81  void set_software(const std::string& software) { software_ = software; }
82
83  // Sets the authentication callback; does not take ownership.
84  void set_auth_hook(TurnAuthInterface* auth_hook) { auth_hook_ = auth_hook; }
85
86  void set_enable_otu_nonce(bool enable) { enable_otu_nonce_ = enable; }
87
88  // Starts listening for packets from internal clients.
89  void AddInternalSocket(talk_base::AsyncPacketSocket* socket,
90                         ProtocolType proto);
91  // Starts listening for the connections on this socket. When someone tries
92  // to connect, the connection will be accepted and a new internal socket
93  // will be added.
94  void AddInternalServerSocket(talk_base::AsyncSocket* socket,
95                               ProtocolType proto);
96  // Specifies the factory to use for creating external sockets.
97  void SetExternalSocketFactory(talk_base::PacketSocketFactory* factory,
98                                const talk_base::SocketAddress& address);
99
100 private:
101  // Encapsulates the client's connection to the server.
102  class Connection {
103   public:
104    Connection() : proto_(PROTO_UDP), socket_(NULL) {}
105    Connection(const talk_base::SocketAddress& src,
106               ProtocolType proto,
107               talk_base::AsyncPacketSocket* socket);
108    const talk_base::SocketAddress& src() const { return src_; }
109    talk_base::AsyncPacketSocket* socket() { return socket_; }
110    bool operator==(const Connection& t) const;
111    bool operator<(const Connection& t) const;
112    std::string ToString() const;
113
114   private:
115    talk_base::SocketAddress src_;
116    talk_base::SocketAddress dst_;
117    cricket::ProtocolType proto_;
118    talk_base::AsyncPacketSocket* socket_;
119  };
120  class Allocation;
121  class Permission;
122  class Channel;
123  typedef std::map<Connection, Allocation*> AllocationMap;
124
125  void OnInternalPacket(talk_base::AsyncPacketSocket* socket, const char* data,
126                        size_t size, const talk_base::SocketAddress& address,
127                        const talk_base::PacketTime& packet_time);
128
129  void OnNewInternalConnection(talk_base::AsyncSocket* socket);
130
131  // Accept connections on this server socket.
132  void AcceptConnection(talk_base::AsyncSocket* server_socket);
133  void OnInternalSocketClose(talk_base::AsyncPacketSocket* socket, int err);
134
135  void HandleStunMessage(Connection* conn, const char* data, size_t size);
136  void HandleBindingRequest(Connection* conn, const StunMessage* msg);
137  void HandleAllocateRequest(Connection* conn, const TurnMessage* msg,
138                             const std::string& key);
139
140  bool GetKey(const StunMessage* msg, std::string* key);
141  bool CheckAuthorization(Connection* conn, const StunMessage* msg,
142                          const char* data, size_t size,
143                          const std::string& key);
144  std::string GenerateNonce() const;
145  bool ValidateNonce(const std::string& nonce) const;
146
147  Allocation* FindAllocation(Connection* conn);
148  Allocation* CreateAllocation(Connection* conn, int proto,
149                               const std::string& key);
150
151  void SendErrorResponse(Connection* conn, const StunMessage* req,
152                         int code, const std::string& reason);
153
154  void SendErrorResponseWithRealmAndNonce(Connection* conn,
155                                          const StunMessage* req,
156                                          int code,
157                                          const std::string& reason);
158  void SendStun(Connection* conn, StunMessage* msg);
159  void Send(Connection* conn, const talk_base::ByteBuffer& buf);
160
161  void OnAllocationDestroyed(Allocation* allocation);
162  void DestroyInternalSocket(talk_base::AsyncPacketSocket* socket);
163
164  typedef std::map<talk_base::AsyncPacketSocket*,
165                   ProtocolType> InternalSocketMap;
166  typedef std::map<talk_base::AsyncSocket*,
167                   ProtocolType> ServerSocketMap;
168
169  talk_base::Thread* thread_;
170  std::string nonce_key_;
171  std::string realm_;
172  std::string software_;
173  TurnAuthInterface* auth_hook_;
174  // otu - one-time-use. Server will respond with 438 if it's
175  // sees the same nonce in next transaction.
176  bool enable_otu_nonce_;
177  InternalSocketMap server_sockets_;
178  ServerSocketMap server_listen_sockets_;
179  talk_base::scoped_ptr<talk_base::PacketSocketFactory>
180      external_socket_factory_;
181  talk_base::SocketAddress external_addr_;
182  AllocationMap allocations_;
183};
184
185}  // namespace cricket
186
187#endif  // TALK_P2P_BASE_TURNSERVER_H_
188