1 /* 2 * This file is part of OpenTTD. 3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. 4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. 6 */ 7 8 /** 9 * @file tcp.h Basic functions to receive and send TCP packets. 10 */ 11 12 #ifndef NETWORK_CORE_TCP_H 13 #define NETWORK_CORE_TCP_H 14 15 #include "address.h" 16 #include "packet.h" 17 18 #include <atomic> 19 #include <chrono> 20 #include <map> 21 #include <thread> 22 23 /** The states of sending the packets. */ 24 enum SendPacketsState { 25 SPS_CLOSED, ///< The connection got closed. 26 SPS_NONE_SENT, ///< The buffer is still full, so no (parts of) packets could be sent. 27 SPS_PARTLY_SENT, ///< The packets are partly sent; there are more packets to be sent in the queue. 28 SPS_ALL_SENT, ///< All packets in the queue are sent. 29 }; 30 31 /** Base socket handler for all TCP sockets */ 32 class NetworkTCPSocketHandler : public NetworkSocketHandler { 33 private: 34 Packet *packet_queue; ///< Packets that are awaiting delivery 35 Packet *packet_recv; ///< Partially received packet 36 37 void EmptyPacketQueue(); 38 public: 39 SOCKET sock; ///< The socket currently connected to 40 bool writable; ///< Can we write to this socket? 41 42 /** 43 * Whether this socket is currently bound to a socket. 44 * @return true when the socket is bound, false otherwise 45 */ IsConnected()46 bool IsConnected() const { return this->sock != INVALID_SOCKET; } 47 48 virtual NetworkRecvStatus CloseConnection(bool error = true); 49 void CloseSocket(); 50 51 virtual void SendPacket(Packet *packet); 52 SendPacketsState SendPackets(bool closing_down = false); 53 54 virtual Packet *ReceivePacket(); 55 56 bool CanSendReceive(); 57 58 /** 59 * Whether there is something pending in the send queue. 60 * @return true when something is pending in the send queue. 61 */ HasSendQueue()62 bool HasSendQueue() { return this->packet_queue != nullptr; } 63 64 NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET); 65 ~NetworkTCPSocketHandler(); 66 }; 67 68 /** 69 * "Helper" class for creating TCP connections in a non-blocking manner 70 */ 71 class TCPConnecter { 72 private: 73 /** 74 * The current status of the connecter. 75 * 76 * We track the status like this to ensure everything is executed from the 77 * game-thread, and not at another random time where we might not have the 78 * lock on the game-state. 79 */ 80 enum class Status { 81 INIT, ///< TCPConnecter is created but resolving hasn't started. 82 RESOLVING, ///< The hostname is being resolved (threaded). 83 FAILURE, ///< Resolving failed. 84 CONNECTING, ///< We are currently connecting. 85 CONNECTED, ///< The connection is established. 86 }; 87 88 std::thread resolve_thread; ///< Thread used during resolving. 89 std::atomic<Status> status = Status::INIT; ///< The current status of the connecter. 90 std::atomic<bool> killed = false; ///< Whether this connecter is marked as killed. 91 92 addrinfo *ai = nullptr; ///< getaddrinfo() allocated linked-list of resolved addresses. 93 std::vector<addrinfo *> addresses; ///< Addresses we can connect to. 94 std::map<SOCKET, NetworkAddress> sock_to_address; ///< Mapping of a socket to the real address it is connecting to. USed for DEBUG statements. 95 size_t current_address = 0; ///< Current index in addresses we are trying. 96 97 std::vector<SOCKET> sockets; ///< Pending connect() attempts. 98 std::chrono::steady_clock::time_point last_attempt; ///< Time we last tried to connect. 99 100 std::string connection_string; ///< Current address we are connecting to (before resolving). 101 NetworkAddress bind_address; ///< Address we're binding to, if any. 102 int family = AF_UNSPEC; ///< Family we are using to connect with. 103 104 void Resolve(); 105 void OnResolved(addrinfo *ai); 106 bool TryNextAddress(); 107 void Connect(addrinfo *address); 108 virtual bool CheckActivity(); 109 110 /* We do not want any other derived classes from this class being able to 111 * access these private members, but it is okay for TCPServerConnecter. */ 112 friend class TCPServerConnecter; 113 114 static void ResolveThunk(TCPConnecter *connecter); 115 116 public: TCPConnecter()117 TCPConnecter() {}; 118 TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {}, int family = AF_UNSPEC); 119 virtual ~TCPConnecter(); 120 121 /** 122 * Callback when the connection succeeded. 123 * @param s the socket that we opened 124 */ OnConnect(SOCKET s)125 virtual void OnConnect(SOCKET s) {} 126 127 /** 128 * Callback for when the connection attempt failed. 129 */ OnFailure()130 virtual void OnFailure() {} 131 132 void Kill(); 133 134 static void CheckCallbacks(); 135 static void KillAll(); 136 }; 137 138 class TCPServerConnecter : public TCPConnecter { 139 private: 140 SOCKET socket = INVALID_SOCKET; ///< The socket when a connection is established. 141 142 bool CheckActivity() override; 143 144 public: 145 ServerAddress server_address; ///< Address we are connecting to. 146 147 TCPServerConnecter(const std::string &connection_string, uint16 default_port); 148 149 void SetConnected(SOCKET sock); 150 void SetFailure(); 151 }; 152 153 #endif /* NETWORK_CORE_TCP_H */ 154