Codechange: [Network] split CloseSocket and CloseConnection more clearly (#9261)

* Codechange: [Network] split CloseSocket and CloseConnection more clearly

- CloseSocket now closes the actual OS socket.
- CloseConnection frees up the resources to just before CloseSocket.
- dtors call CloseSocket / CloseConnection where needed.
pull/332/head
Patric Stout 3 years ago committed by GitHub
parent 86741ad489
commit a403653805
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -40,7 +40,9 @@ struct Packet;
* SocketHandler for all network sockets in OpenTTD.
*/
class NetworkSocketHandler {
private:
bool has_quit; ///< Whether the current client has quit/send a bad packet
public:
/** Create a new unbound socket */
NetworkSocketHandler() { this->has_quit = false; }
@ -49,12 +51,13 @@ public:
virtual ~NetworkSocketHandler() {}
/**
* Close the current connection; for TCP this will be mostly equivalent
* to Close(), but for UDP it just means the packet has to be dropped.
* @param error Whether we quit under an error condition or not.
* @return new status of the connection.
* Mark the connection as closed.
*
* This doesn't mean the actual connection is closed, but just that we
* act like it is. This is useful for UDP, which doesn't normally close
* a socket, but its handler might need to pretend it does.
*/
virtual NetworkRecvStatus CloseConnection(bool error = true) { this->has_quit = true; return NETWORK_RECV_STATUS_OKAY; }
void MarkClosed() { this->has_quit = true; }
/**
* Whether the current client connected to the socket has quit.

@ -222,7 +222,7 @@ bool Packet::CanReadFromPacket(size_t bytes_to_read, bool close_connection)
/* Check if variable is within packet-size */
if (this->pos + bytes_to_read > this->Size()) {
if (close_connection) this->cs->NetworkSocketHandler::CloseConnection();
if (close_connection) this->cs->NetworkSocketHandler::MarkClosed();
return false;
}

@ -29,24 +29,45 @@ NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
{
/* Virtual functions get called statically in destructors, so make it explicit to remove any confusion. */
this->NetworkTCPSocketHandler::CloseConnection();
this->EmptyPacketQueue();
this->CloseSocket();
}
/**
* Free all pending and partially received packets.
*/
void NetworkTCPSocketHandler::EmptyPacketQueue()
{
while (this->packet_queue != nullptr) {
delete Packet::PopFromQueue(&this->packet_queue);
}
delete this->packet_recv;
this->packet_recv = nullptr;
}
/**
* Close the actual socket of the connection.
* Please make sure CloseConnection is called before CloseSocket, as
* otherwise not all resources might be released.
*/
void NetworkTCPSocketHandler::CloseSocket()
{
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
this->sock = INVALID_SOCKET;
}
/**
* This will put this socket handler in a close state. It will not
* actually close the OS socket; use CloseSocket for this.
* @param error Whether we quit under an error condition or not.
* @return new status of the connection.
*/
NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error)
{
this->MarkClosed();
this->writable = false;
NetworkSocketHandler::CloseConnection(error);
/* Free all pending and partially received packets */
while (this->packet_queue != nullptr) {
delete Packet::PopFromQueue(&this->packet_queue);
}
delete this->packet_recv;
this->packet_recv = nullptr;
this->EmptyPacketQueue();
return NETWORK_RECV_STATUS_OKAY;
}

@ -33,6 +33,8 @@ class NetworkTCPSocketHandler : public NetworkSocketHandler {
private:
Packet *packet_queue; ///< Packets that are awaiting delivery
Packet *packet_recv; ///< Partially received packet
void EmptyPacketQueue();
public:
SOCKET sock; ///< The socket currently connected to
bool writable; ///< Can we write to this socket?
@ -43,7 +45,9 @@ public:
*/
bool IsConnected() const { return this->sock != INVALID_SOCKET; }
NetworkRecvStatus CloseConnection(bool error = true) override;
virtual NetworkRecvStatus CloseConnection(bool error = true);
void CloseSocket();
virtual void SendPacket(Packet *packet);
SendPacketsState SendPackets(bool closing_down = false);

@ -34,10 +34,6 @@ NetworkAdminSocketHandler::NetworkAdminSocketHandler(SOCKET s) : status(ADMIN_ST
this->admin_version[0] = '\0';
}
NetworkAdminSocketHandler::~NetworkAdminSocketHandler()
{
}
NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error)
{
delete this;

@ -482,7 +482,6 @@ public:
NetworkRecvStatus CloseConnection(bool error = true) override;
NetworkAdminSocketHandler(SOCKET s);
~NetworkAdminSocketHandler();
NetworkRecvStatus ReceivePackets();

@ -137,17 +137,6 @@ const char *ContentInfo::GetTextfile(TextfileType type) const
return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp);
}
/**
* Close the actual socket.
*/
void NetworkContentSocketHandler::CloseSocket()
{
if (this->sock == INVALID_SOCKET) return;
closesocket(this->sock);
this->sock = INVALID_SOCKET;
}
/**
* Handle the given packet, i.e. pass it to the right
* parser receive command.

@ -21,8 +21,6 @@
/** Base socket handler for all Content TCP sockets */
class NetworkContentSocketHandler : public NetworkTCPSocketHandler {
protected:
void CloseSocket();
bool ReceiveInvalidPacket(PacketContentType type);
/**

@ -68,17 +68,18 @@ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s,
/** Free whatever needs to be freed. */
NetworkHTTPSocketHandler::~NetworkHTTPSocketHandler()
{
this->CloseConnection();
this->CloseSocket();
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
this->sock = INVALID_SOCKET;
free(this->data);
}
NetworkRecvStatus NetworkHTTPSocketHandler::CloseConnection(bool error)
/**
* Close the actual socket of the connection.
*/
void NetworkHTTPSocketHandler::CloseSocket()
{
NetworkSocketHandler::CloseConnection(error);
return NETWORK_RECV_STATUS_OKAY;
if (this->sock != INVALID_SOCKET) closesocket(this->sock);
this->sock = INVALID_SOCKET;
}
/**
@ -313,7 +314,7 @@ int NetworkHTTPSocketHandler::Receive()
if (ret < 0) cur->callback->OnFailure();
if (ret <= 0) {
/* Then... the connection can be closed */
cur->CloseConnection();
cur->CloseSocket();
iter = _http_connections.erase(iter);
delete cur;
continue;

@ -58,7 +58,7 @@ public:
return this->sock != INVALID_SOCKET;
}
NetworkRecvStatus CloseConnection(bool error = true) override;
void CloseSocket();
NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback,
const char *host, const char *url, const char *data, int depth);

@ -44,7 +44,7 @@ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
bool NetworkUDPSocketHandler::Listen()
{
/* Make sure socket is closed */
this->Close();
this->CloseSocket();
for (NetworkAddress &addr : this->bind) {
addr.Listen(SOCK_DGRAM, &this->sockets);
@ -54,9 +54,9 @@ bool NetworkUDPSocketHandler::Listen()
}
/**
* Close the given UDP socket
* Close the actual UDP socket.
*/
void NetworkUDPSocketHandler::Close()
void NetworkUDPSocketHandler::CloseSocket()
{
for (auto &s : this->sockets) {
closesocket(s.second);
@ -64,12 +64,6 @@ void NetworkUDPSocketHandler::Close()
this->sockets.clear();
}
NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error)
{
NetworkSocketHandler::CloseConnection(error);
return NETWORK_RECV_STATUS_OKAY;
}
/**
* Send a packet over UDP
* @param p the packet to send

@ -49,8 +49,6 @@ protected:
/** The opened sockets. */
SocketList sockets;
NetworkRecvStatus CloseConnection(bool error = true) override;
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr);
/**
@ -187,10 +185,10 @@ public:
NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr);
/** On destructing of this class, the socket needs to be closed */
virtual ~NetworkUDPSocketHandler() { this->Close(); }
virtual ~NetworkUDPSocketHandler() { this->CloseSocket(); }
bool Listen();
void Close();
void CloseSocket();
void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false);
void ReceivePackets();

@ -158,6 +158,7 @@ ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler()
ClientNetworkGameSocketHandler::my_client = nullptr;
delete this->savegame;
delete this->GetInfo();
}
NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status)
@ -182,7 +183,6 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
* which would trigger the server to close the connection as well. */
CSleep(3 * MILLISECONDS_PER_TICK);
delete this->GetInfo();
delete this;
return status;
@ -200,7 +200,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
/* We just want to close the connection.. */
if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
this->NetworkSocketHandler::CloseConnection();
this->NetworkSocketHandler::MarkClosed();
this->CloseConnection(res);
_networking = false;

@ -76,7 +76,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p)
if (!ci->IsValid()) {
delete ci;
this->Close();
this->CloseConnection();
return false;
}
@ -488,7 +488,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename));
if (!this->BeforeDownload()) {
this->Close();
this->CloseConnection();
return false;
}
} else {
@ -497,7 +497,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p)
if (toRead != 0 && (size_t)p->TransferOut(TransferOutFWrite, this->curFile) != toRead) {
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
this->Close();
this->CloseConnection();
fclose(this->curFile);
this->curFile = nullptr;
@ -781,14 +781,16 @@ void ClientNetworkContentSocketHandler::Connect()
/**
* Disconnect from the content server.
*/
void ClientNetworkContentSocketHandler::Close()
NetworkRecvStatus ClientNetworkContentSocketHandler::CloseConnection(bool error)
{
if (this->sock == INVALID_SOCKET) return;
NetworkContentSocketHandler::CloseConnection();
this->CloseConnection();
this->CloseSocket();
if (this->sock == INVALID_SOCKET) return NETWORK_RECV_STATUS_OKAY;
this->CloseSocket();
this->OnDisconnect();
return NETWORK_RECV_STATUS_OKAY;
}
/**
@ -800,7 +802,7 @@ void ClientNetworkContentSocketHandler::SendReceive()
if (this->sock == INVALID_SOCKET || this->isConnecting) return;
if (std::chrono::steady_clock::now() > this->lastActivity + IDLE_TIMEOUT) {
this->Close();
this->CloseConnection();
return;
}

@ -107,7 +107,7 @@ public:
void Connect();
void SendReceive();
void Close();
NetworkRecvStatus CloseConnection(bool error = true) override;
void RequestContentList(ContentType type);
void RequestContentList(uint count, const ContentID *content_ids);

@ -260,7 +260,7 @@ public:
{
if (widget == WID_NCDS_CANCELOK) {
if (this->downloaded_bytes != this->total_bytes) {
_network_content_client.Close();
_network_content_client.CloseConnection();
delete this;
} else {
/* If downloading succeeded, close the online content window. This will close

@ -54,10 +54,10 @@ struct UDPSocket {
UDPSocket(const std::string &name_) : name(name_), socket(nullptr) {}
void Close()
void CloseSocket()
{
std::lock_guard<std::mutex> lock(mutex);
socket->Close();
socket->CloseSocket();
delete socket;
socket = nullptr;
}
@ -619,9 +619,9 @@ void NetworkUDPServerListen()
/** Close all UDP related stuff. */
void NetworkUDPClose()
{
_udp_client.Close();
_udp_server.Close();
_udp_master.Close();
_udp_client.CloseSocket();
_udp_server.CloseSocket();
_udp_master.CloseSocket();
_network_udp_server = false;
_network_udp_broadcast = 0;

Loading…
Cancel
Save