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