Codechange: Update minimum CMake version to 3.16 for all parts. (#13141)
[openttd-github.git] / src / network / core / tcp.h
blob419a2785871a7158eb3c90197d20942b7f73f8b3
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 */
8 /**
9 * @file tcp.h Basic functions to receive and send TCP packets.
12 #ifndef NETWORK_CORE_TCP_H
13 #define NETWORK_CORE_TCP_H
15 #include "address.h"
16 #include "packet.h"
18 #include <atomic>
19 #include <chrono>
20 #include <thread>
22 /** The states of sending the packets. */
23 enum SendPacketsState {
24 SPS_CLOSED, ///< The connection got closed.
25 SPS_NONE_SENT, ///< The buffer is still full, so no (parts of) packets could be sent.
26 SPS_PARTLY_SENT, ///< The packets are partly sent; there are more packets to be sent in the queue.
27 SPS_ALL_SENT, ///< All packets in the queue are sent.
30 /** Base socket handler for all TCP sockets */
31 class NetworkTCPSocketHandler : public NetworkSocketHandler {
32 private:
33 std::deque<std::unique_ptr<Packet>> packet_queue; ///< Packets that are awaiting delivery. Cannot be std::queue as that does not have a clear() function.
34 std::unique_ptr<Packet> packet_recv; ///< Partially received packet
36 void EmptyPacketQueue();
37 public:
38 SOCKET sock; ///< The socket currently connected to
39 bool writable; ///< Can we write to this socket?
41 /**
42 * Whether this socket is currently bound to a socket.
43 * @return true when the socket is bound, false otherwise
45 bool IsConnected() const { return this->sock != INVALID_SOCKET; }
47 virtual NetworkRecvStatus CloseConnection(bool error = true);
48 void CloseSocket();
50 virtual void SendPacket(std::unique_ptr<Packet> &&packet);
51 SendPacketsState SendPackets(bool closing_down = false);
53 virtual std::unique_ptr<Packet> ReceivePacket();
55 bool CanSendReceive();
57 /**
58 * Whether there is something pending in the send queue.
59 * @return true when something is pending in the send queue.
61 bool HasSendQueue() { return !this->packet_queue.empty(); }
63 NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET);
64 ~NetworkTCPSocketHandler();
67 /**
68 * "Helper" class for creating TCP connections in a non-blocking manner
70 class TCPConnecter {
71 private:
72 /**
73 * The current status of the connecter.
75 * We track the status like this to ensure everything is executed from the
76 * game-thread, and not at another random time where we might not have the
77 * lock on the game-state.
79 enum class Status {
80 Init, ///< TCPConnecter is created but resolving hasn't started.
81 Resolving, ///< The hostname is being resolved (threaded).
82 Failure, ///< Resolving failed.
83 Connecting, ///< We are currently connecting.
84 Connected, ///< The connection is established.
87 std::thread resolve_thread; ///< Thread used during resolving.
88 std::atomic<Status> status = Status::Init; ///< The current status of the connecter.
89 std::atomic<bool> killed = false; ///< Whether this connecter is marked as killed.
91 addrinfo *ai = nullptr; ///< getaddrinfo() allocated linked-list of resolved addresses.
92 std::vector<addrinfo *> addresses; ///< Addresses we can connect to.
93 std::map<SOCKET, NetworkAddress> sock_to_address; ///< Mapping of a socket to the real address it is connecting to. USed for DEBUG statements.
94 size_t current_address = 0; ///< Current index in addresses we are trying.
96 std::vector<SOCKET> sockets; ///< Pending connect() attempts.
97 std::chrono::steady_clock::time_point last_attempt; ///< Time we last tried to connect.
99 std::string connection_string; ///< Current address we are connecting to (before resolving).
100 NetworkAddress bind_address; ///< Address we're binding to, if any.
101 int family = AF_UNSPEC; ///< Family we are using to connect with.
103 static std::vector<std::shared_ptr<TCPConnecter>> connecters; ///< List of connections that are currently being created.
105 void Resolve();
106 void OnResolved(addrinfo *ai);
107 bool TryNextAddress();
108 void Connect(addrinfo *address);
109 virtual bool CheckActivity();
111 /* We do not want any other derived classes from this class being able to
112 * access these private members, but it is okay for TCPServerConnecter. */
113 friend class TCPServerConnecter;
115 static void ResolveThunk(TCPConnecter *connecter);
117 public:
118 TCPConnecter() {};
119 TCPConnecter(const std::string &connection_string, uint16_t default_port, const NetworkAddress &bind_address = {}, int family = AF_UNSPEC);
120 virtual ~TCPConnecter();
123 * Callback when the connection succeeded.
124 * @param s the socket that we opened
126 virtual void OnConnect([[maybe_unused]] SOCKET s) {}
129 * Callback for when the connection attempt failed.
131 virtual void OnFailure() {}
133 void Kill();
135 static void CheckCallbacks();
136 static void KillAll();
139 * Create the connecter, and initiate connecting by putting it in the collection of TCP connections to make.
140 * @tparam T The type of connecter to create.
141 * @param args The arguments to the constructor of T.
142 * @return Shared pointer to the connecter.
144 template <class T, typename... Args>
145 static std::shared_ptr<TCPConnecter> Create(Args&& ... args)
147 return TCPConnecter::connecters.emplace_back(std::make_shared<T>(std::forward<Args>(args)...));
151 class TCPServerConnecter : public TCPConnecter {
152 private:
153 SOCKET socket = INVALID_SOCKET; ///< The socket when a connection is established.
155 bool CheckActivity() override;
157 public:
158 ServerAddress server_address; ///< Address we are connecting to.
160 TCPServerConnecter(const std::string &connection_string, uint16_t default_port);
162 void SetConnected(SOCKET sock);
163 void SetFailure();
166 #endif /* NETWORK_CORE_TCP_H */