Files @ r25616:f6fb8fecc5a4
Branch filter:

Location: cpp/openttd-patchpack/source/src/network/core/tcp.cpp - annotation

rubidium42
Codechange: [ContentInfo] Use StringList for tags instead of custom allocations
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r12768:980ae0491352
r6121:a8ff6abe7fb2
r6121:a8ff6abe7fb2
r6121:a8ff6abe7fb2
r6121:a8ff6abe7fb2
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r21383:942c32fb8b0e
r21383:942c32fb8b0e
r17622:d9f6f6845b5d
r17622:d9f6f6845b5d
r17622:d9f6f6845b5d
r17622:d9f6f6845b5d
r10746:38677d5ad005
r11593:8dd431018ab1
r23607:36c15679007d
r11593:8dd431018ab1
r5624:8f8d1f8d3a74
r5624:8f8d1f8d3a74
r5624:8f8d1f8d3a74
r10746:38677d5ad005
r5902:68b31dbadeb5
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r10871:90a72cf39d77
r10871:90a72cf39d77
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r10871:90a72cf39d77
r23607:36c15679007d
r25249:deeb506a6e53
r5902:68b31dbadeb5
r5902:68b31dbadeb5
r23607:36c15679007d
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r25458:3aaccd46b7fa
r5902:68b31dbadeb5
r10871:90a72cf39d77
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r16618:d89f0c3f42e7
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r5898:2191f99d1ffb
r25249:deeb506a6e53
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r14240:6ee15a1ac1b5
r16454:7e64ef2b771a
r16454:7e64ef2b771a
r5584:545d748cc681
r17318:87556706b761
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r17318:87556706b761
r17318:87556706b761
r5584:545d748cc681
r25249:deeb506a6e53
r25245:5872175e0e0c
r5584:545d748cc681
r25351:31942544c033
r25351:31942544c033
r5584:545d748cc681
r14240:6ee15a1ac1b5
r25440:04e72c31c8b4
r14240:6ee15a1ac1b5
r14240:6ee15a1ac1b5
r17318:87556706b761
r5584:545d748cc681
r17318:87556706b761
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r14240:6ee15a1ac1b5
r17318:87556706b761
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r25245:5872175e0e0c
r5584:545d748cc681
r25249:deeb506a6e53
r5584:545d748cc681
r17318:87556706b761
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r17318:87556706b761
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r16618:d89f0c3f42e7
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r23607:36c15679007d
r25270:0e1af506fef0
r5584:545d748cc681
r5584:545d748cc681
r13228:ca781b7ee590
r5584:545d748cc681
r5584:545d748cc681
r25242:16241601aa3b
r25244:61183b73d88e
r25244:61183b73d88e
r5584:545d748cc681
r25351:31942544c033
r25351:31942544c033
r25351:31942544c033
r25440:04e72c31c8b4
r13225:b2fd8781e711
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r13225:b2fd8781e711
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r25242:16241601aa3b
r25242:16241601aa3b
r13225:b2fd8781e711
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r25244:61183b73d88e
r25244:61183b73d88e
r5584:545d748cc681
r25351:31942544c033
r25351:31942544c033
r25351:31942544c033
r25440:04e72c31c8b4
r13225:b2fd8781e711
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r13225:b2fd8781e711
r23607:36c15679007d
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r23607:36c15679007d
r5584:545d748cc681
r5898:2191f99d1ffb
r5584:545d748cc681
r5584:545d748cc681
r5584:545d748cc681
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r17622:d9f6f6845b5d
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r16222:694bed5fd015
r23607:36c15679007d
r16222:694bed5fd015
r16222:694bed5fd015
r16228:7cc349983c50
r16222:694bed5fd015
/*
 * This file is part of OpenTTD.
 * 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.
 * 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.
 * 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/>.
 */

/**
 * @file tcp.cpp Basic functions to receive and send TCP packets.
 */

#include "../../stdafx.h"
#include "../../debug.h"

#include "tcp.h"

#include "../../safeguards.h"

/**
 * Construct a socket handler for a TCP connection.
 * @param s The just opened TCP connection.
 */
NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
		NetworkSocketHandler(),
		packet_queue(nullptr), packet_recv(nullptr),
		sock(s), writable(false)
{
}

NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
{
	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;

	this->EmptyPacketQueue();

	return NETWORK_RECV_STATUS_OKAY;
}

/**
 * This function puts the packet in the send-queue and it is send as
 * soon as possible. This is the next tick, or maybe one tick later
 * if the OS-network-buffer is full)
 * @param packet the packet to send
 */
void NetworkTCPSocketHandler::SendPacket(Packet *packet)
{
	assert(packet != nullptr);

	packet->PrepareToSend();
	Packet::AddToQueue(&this->packet_queue, packet);
}

/**
 * Sends all the buffered packets out for this client. It stops when:
 *   1) all packets are send (queue is empty)
 *   2) the OS reports back that it can not send any more
 *      data right now (full network-buffer, it happens ;))
 *   3) sending took too long
 * @param closing_down Whether we are closing down the connection.
 * @return \c true if a (part of a) packet could be sent and
 *         the connection is not closed yet.
 */
SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
{
	ssize_t res;
	Packet *p;

	/* We can not write to this socket!! */
	if (!this->writable) return SPS_NONE_SENT;
	if (!this->IsConnected()) return SPS_CLOSED;

	while ((p = this->packet_queue) != nullptr) {
		res = p->TransferOut<int>(send, this->sock, 0);
		if (res == -1) {
			NetworkError err = NetworkError::GetLast();
			if (!err.WouldBlock()) {
				/* Something went wrong.. close client! */
				if (!closing_down) {
					DEBUG(net, 0, "Send failed: %s", err.AsString());
					this->CloseConnection();
				}
				return SPS_CLOSED;
			}
			return SPS_PARTLY_SENT;
		}
		if (res == 0) {
			/* Client/server has left us :( */
			if (!closing_down) this->CloseConnection();
			return SPS_CLOSED;
		}

		/* Is this packet sent? */
		if (p->RemainingBytesToTransfer() == 0) {
			/* Go to the next packet */
			delete Packet::PopFromQueue(&this->packet_queue);
		} else {
			return SPS_PARTLY_SENT;
		}
	}

	return SPS_ALL_SENT;
}

/**
 * Receives a packet for the given client
 * @return The received packet (or nullptr when it didn't receive one)
 */
Packet *NetworkTCPSocketHandler::ReceivePacket()
{
	ssize_t res;

	if (!this->IsConnected()) return nullptr;

	if (this->packet_recv == nullptr) {
		this->packet_recv = new Packet(this, TCP_MTU);
	}

	Packet *p = this->packet_recv;

	/* Read packet size */
	if (!p->HasPacketSizeData()) {
		while (p->RemainingBytesToTransfer() != 0) {
			res = p->TransferIn<int>(recv, this->sock, 0);
			if (res == -1) {
				NetworkError err = NetworkError::GetLast();
				if (!err.WouldBlock()) {
					/* Something went wrong... */
					if (!err.IsConnectionReset()) DEBUG(net, 0, "Recv failed: %s", err.AsString());
					this->CloseConnection();
					return nullptr;
				}
				/* Connection would block, so stop for now */
				return nullptr;
			}
			if (res == 0) {
				/* Client/server has left */
				this->CloseConnection();
				return nullptr;
			}
		}

		/* Parse the size in the received packet and if not valid, close the connection. */
		if (!p->ParsePacketSize()) {
			this->CloseConnection();
			return nullptr;
		}
	}

	/* Read rest of packet */
	while (p->RemainingBytesToTransfer() != 0) {
		res = p->TransferIn<int>(recv, this->sock, 0);
		if (res == -1) {
			NetworkError err = NetworkError::GetLast();
			if (!err.WouldBlock()) {
				/* Something went wrong... */
				if (!err.IsConnectionReset()) DEBUG(net, 0, "Recv failed: %s", err.AsString());
				this->CloseConnection();
				return nullptr;
			}
			/* Connection would block */
			return nullptr;
		}
		if (res == 0) {
			/* Client/server has left */
			this->CloseConnection();
			return nullptr;
		}
	}

	/* Prepare for receiving a new packet */
	this->packet_recv = nullptr;

	p->PrepareToRead();
	return p;
}

/**
 * Check whether this socket can send or receive something.
 * @return \c true when there is something to receive.
 * @note Sets #writable if more data can be sent.
 */
bool NetworkTCPSocketHandler::CanSendReceive()
{
	fd_set read_fd, write_fd;
	struct timeval tv;

	FD_ZERO(&read_fd);
	FD_ZERO(&write_fd);

	FD_SET(this->sock, &read_fd);
	FD_SET(this->sock, &write_fd);

	tv.tv_sec = tv.tv_usec = 0; // don't block at all.
	if (select(FD_SETSIZE, &read_fd, &write_fd, nullptr, &tv) < 0) return false;

	this->writable = !!FD_ISSET(this->sock, &write_fd);
	return FD_ISSET(this->sock, &read_fd) != 0;
}