/* * libjingle * Copyright 2004--2005, 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. */ #ifndef __PORT_H__ #define __PORT_H__ #include "talk/base/network.h" #include "talk/base/socketaddress.h" #include "talk/base/proxyinfo.h" #include "talk/base/sigslot.h" #include "talk/base/thread.h" #include "talk/p2p/base/candidate.h" #include "talk/p2p/base/stun.h" #include "talk/p2p/base/stunrequest.h" #include #include #include namespace talk_base { class AsyncPacketSocket; } namespace cricket { class Connection; enum ProtocolType { PROTO_UDP, PROTO_TCP, PROTO_SSLTCP, PROTO_LAST = PROTO_SSLTCP }; const char * ProtoToString(ProtocolType proto); bool StringToProto(const char * value, ProtocolType& proto); struct ProtocolAddress { talk_base::SocketAddress address; ProtocolType proto; ProtocolAddress(const talk_base::SocketAddress& a, ProtocolType p) : address(a), proto(p) { } }; // Represents a local communication mechanism that can be used to create // connections to similar mechanisms of the other client. Subclasses of this // one add support for specific mechanisms like local UDP ports. class Port : public talk_base::MessageHandler, public sigslot::has_slots<> { public: Port(talk_base::Thread* thread, const std::string &type, talk_base::SocketFactory* factory, talk_base::Network* network); virtual ~Port(); // The thread on which this port performs its I/O. talk_base::Thread* thread() { return thread_; } // The factory used to create the sockets of this port. talk_base::SocketFactory* socket_factory() const { return factory_; } void set_socket_factory(talk_base::SocketFactory* factory) { factory_ = factory; } // Each port is identified by a name (for debugging purposes). const std::string& name() const { return name_; } void set_name(const std::string& name) { name_ = name; } // In order to establish a connection to this Port (so that real data can be // sent through), the other side must send us a STUN binding request that is // authenticated with this username and password. const std::string& username_fragment() const { return username_frag_; } const std::string& password() const { return password_; } // A value in [0,1] that indicates the preference for this port versus other // ports on this client. (Larger indicates more preference.) float preference() const { return preference_; } void set_preference(float preference) { preference_ = preference; } // Identifies the port type. //const std::string& protocol() const { return proto_; } const std::string& type() const { return type_; } // Identifies network that this port was allocated on. talk_base::Network* network() { return network_; } // Identifies the generation that this port was created in. uint32 generation() { return generation_; } void set_generation(uint32 generation) { generation_ = generation; } // PrepareAddress will attempt to get an address for this port that other // clients can send to. It may take some time before the address is read. // Once it is ready, we will send SignalAddressReady. If errors are // preventing the port from getting an address, it may send // SignalAddressError. virtual void PrepareAddress() = 0; sigslot::signal1 SignalAddressReady; sigslot::signal1 SignalAddressError; // Provides all of the above information in one handy object. const std::vector& candidates() const { return candidates_; } // Returns a map containing all of the connections of this port, keyed by the // remote address. typedef std::map AddressMap; const AddressMap& connections() { return connections_; } // Returns the connection to the given address or NULL if none exists. Connection* GetConnection(const talk_base::SocketAddress& remote_addr); // Creates a new connection to the given address. enum CandidateOrigin { ORIGIN_THIS_PORT, ORIGIN_OTHER_PORT, ORIGIN_MESSAGE }; virtual Connection* CreateConnection(const Candidate& remote_candidate, CandidateOrigin origin) = 0; // Called each time a connection is created. sigslot::signal2 SignalConnectionCreated; // Sends the given packet to the given address, provided that the address is // that of a connection or an address that has sent to us already. virtual int SendTo( const void* data, size_t size, const talk_base::SocketAddress& addr, bool payload) = 0; // Indicates that we received a successful STUN binding request from an // address that doesn't correspond to any current connection. To turn this // into a real connection, call CreateConnection. sigslot::signal4 SignalUnknownAddress; // Sends a response message (normal or error) to the given request. One of // these methods should be called as a response to SignalUnknownAddress. // NOTE: You MUST call CreateConnection BEFORE SendBindingResponse. void SendBindingResponse(StunMessage* request, const talk_base::SocketAddress& addr); void SendBindingErrorResponse( StunMessage* request, const talk_base::SocketAddress& addr, int error_code, const std::string& reason); // Indicates that errors occurred when performing I/O. sigslot::signal2 SignalReadError; sigslot::signal2 SignalWriteError; // Functions on the underlying socket(s). virtual int SetOption(talk_base::Socket::Option opt, int value) = 0; virtual int GetError() = 0; static void set_proxy(const std::string& user_agent, const talk_base::ProxyInfo& proxy) { agent_ = user_agent; proxy_ = proxy; } static const std::string& user_agent() { return agent_; } static const talk_base::ProxyInfo& proxy() { return proxy_; } talk_base::AsyncPacketSocket * CreatePacketSocket(ProtocolType proto); // Normally, packets arrive through a connection (or they result signaling of // unknown address). Calling this method turns off delivery of packets // through their respective connection and instead delivers every packet // through this port. void EnablePortPackets(); sigslot::signal4 SignalReadPacket; // Indicates to the port that its official use has now begun. This will // start the timer that checks to see if the port is being used. void Start(); // Called if the port has no connections and is no longer useful. void Destroy(); // Signaled when this port decides to delete itself because it no longer has // any usefulness. sigslot::signal1 SignalDestroyed; virtual void OnMessage(talk_base::Message *pmsg); // Debugging description of this port std::string ToString() const; protected: talk_base::Thread* thread_; talk_base::SocketFactory* factory_; std::string type_; talk_base::Network* network_; uint32 generation_; std::string name_; std::string username_frag_; std::string password_; float preference_; std::vector candidates_; AddressMap connections_; enum Lifetime { LT_PRESTART, LT_PRETIMEOUT, LT_POSTTIMEOUT } lifetime_; bool enable_port_packets_; // Fills in the username fragment and password. These will be initially set // in the constructor to random values. Subclasses can override, though. void set_username_fragment(const std::string& username_fragment) { username_frag_ = username_fragment; } void set_password(const std::string& password) { password_ = password; } // Fills in the local address of the port. void AddAddress(const talk_base::SocketAddress& address, const std::string& protocol, bool final); // Adds the given connection to the list. (Deleting removes them.) void AddConnection(Connection* conn); // Called when a packet is received from an unknown address that is not // currently a connection. If this is an authenticated STUN binding request, // then we will signal the client. void OnReadPacket(const char* data, size_t size, const talk_base::SocketAddress& addr); // Constructs a STUN binding request for the given connection and sends it. void SendBindingRequest(Connection* conn); // If the given data comprises a complete and correct STUN message then the // return value is true, otherwise false. If the message username corresponds // with this port's username fragment, msg will contain the parsed STUN // message. Otherwise, the function may send a STUN response internally. // remote_username contains the remote fragment of the STUN username. bool GetStunMessage(const char* data, size_t size, const talk_base::SocketAddress& addr, StunMessage *& msg, std::string& remote_username); friend class Connection; private: // Called when one of our connections deletes itself. void OnConnectionDestroyed(Connection* conn); // Checks if this port is useless, and hence, should be destroyed. void CheckTimeout(); static std::string agent_; static talk_base::ProxyInfo proxy_; }; // Represents a communication link between a port on the local client and a // port on the remote client. class Connection : public talk_base::MessageHandler, public sigslot::has_slots<> { public: virtual ~Connection(); // The local port where this connection sends and receives packets. Port* port() { return port_; } const Port* port() const { return port_; } // Returns the description of the local port virtual const Candidate& local_candidate() const; // Returns the description of the remote port to which we communicate. const Candidate& remote_candidate() const { return remote_candidate_; } enum ReadState { STATE_READABLE = 0, // we have received pings recently STATE_READ_TIMEOUT = 1 // we haven't received pings in a while }; ReadState read_state() const { return read_state_; } enum WriteState { STATE_WRITABLE = 0, // we have received ping responses recently STATE_WRITE_CONNECT = 1, // we have had a few ping failures STATE_WRITE_TIMEOUT = 2 // we have had a large number of ping failures }; WriteState write_state() const { return write_state_; } // Determines whether the connection has finished connecting. This can only // be false for TCP connections. bool connected() const { return connected_; } // Estimate of the round-trip time over this connection. uint32 rtt() const { return rtt_; } size_t sent_total_bytes(); size_t sent_bytes_second(); size_t recv_total_bytes(); size_t recv_bytes_second(); sigslot::signal1 SignalStateChange; // Sent when the connection has decided that it is no longer of value. It // will delete itself immediately after this call. sigslot::signal1 SignalDestroyed; // The connection can send and receive packets asynchronously. This matches // the interface of AsyncPacketSocket, which may use UDP or TCP under the // covers. virtual int Send(const void* data, size_t size) = 0; // Error if Send() returns < 0 virtual int GetError() = 0; sigslot::signal3 SignalReadPacket; // Called when a packet is received on this connection. void OnReadPacket(const char* data, size_t size); // Called when a connection is determined to be no longer useful to us. We // still keep it around in case the other side wants to use it. But we can // safely stop pinging on it and we can allow it to time out if the other // side stops using it as well. bool pruned() { return pruned_; } void Prune(); // Makes the connection go away. void Destroy(); // Checks that the state of this connection is up-to-date. The argument is // the current time, which is compared against various timeouts. void UpdateState(uint32 now); // Called when this connection should try checking writability again. uint32 last_ping_sent() { return last_ping_sent_; } void Ping(uint32 now); // Called whenever a valid ping is received on this connection. This is // public because the connection intercepts the first ping for us. void ReceivedPing(); // Debugging description of this connection std::string ToString() const; bool reported() { return reported_; } void set_reported(bool reported) { reported_ = reported;} protected: Port* port_; size_t local_candidate_index_; Candidate remote_candidate_; ReadState read_state_; WriteState write_state_; bool connected_; bool pruned_; StunRequestManager requests_; uint32 rtt_; uint32 rtt_data_points_; uint32 last_ping_sent_; // last time we sent a ping to the other side uint32 last_ping_received_; // last time we received a ping from the other // side std::vector pings_since_last_response_; size_t recv_total_bytes_; size_t recv_bytes_second_; uint32 last_recv_bytes_second_time_; size_t last_recv_bytes_second_calc_; size_t sent_total_bytes_; size_t sent_bytes_second_; uint32 last_sent_bytes_second_time_; size_t last_sent_bytes_second_calc_; // Callbacks from ConnectionRequest void OnConnectionRequestResponse(StunMessage *response, uint32 rtt); void OnConnectionRequestErrorResponse(StunMessage *response, uint32 rtt); // Called back when StunRequestManager has a stun packet to send void OnSendStunPacket(const void* data, size_t size, StunRequest* req); // Constructs a new connection to the given remote port. Connection(Port* port, size_t index, const Candidate& candidate); // Changes the state and signals if necessary. void set_read_state(ReadState value); void set_write_state(WriteState value); void set_connected(bool value); // Checks if this connection is useless, and hence, should be destroyed. void CheckTimeout(); void OnMessage(talk_base::Message *pmsg); friend class Port; friend class ConnectionRequest; private: bool reported_; }; // ProxyConnection defers all the interesting work to the port class ProxyConnection : public Connection { public: ProxyConnection(Port* port, size_t index, const Candidate& candidate); virtual int Send(const void* data, size_t size); virtual int GetError() { return error_; } private: int error_; }; } // namespace cricket #endif // __PORT_H__