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/>.
9 * @file tcp.h Basic functions to receive and send TCP packets.
12 #ifndef NETWORK_CORE_TCP_H
13 #define NETWORK_CORE_TCP_H
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
{
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();
38 SOCKET sock
; ///< The socket currently connected to
39 bool writable
; ///< Can we write to this socket?
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);
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();
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();
68 * "Helper" class for creating TCP connections in a non-blocking manner
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.
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.
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
);
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() {}
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
{
153 SOCKET socket
= INVALID_SOCKET
; ///< The socket when a connection is established.
155 bool CheckActivity() override
;
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
);
166 #endif /* NETWORK_CORE_TCP_H */