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