OpenTTD
tcp.cpp
Go to the documentation of this file.
1 /* $Id$ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
14 #include "../../stdafx.h"
15 #include "../../debug.h"
16 
17 #include "tcp.h"
18 
19 #include "../../safeguards.h"
20 
27  packet_queue(nullptr), packet_recv(nullptr),
28  sock(s), writable(false)
29 {
30 }
31 
32 NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
33 {
34  this->CloseConnection();
35 
36  if (this->sock != INVALID_SOCKET) closesocket(this->sock);
37  this->sock = INVALID_SOCKET;
38 }
39 
41 {
42  this->writable = false;
44 
45  /* Free all pending and partially received packets */
46  while (this->packet_queue != nullptr) {
47  Packet *p = this->packet_queue->next;
48  delete this->packet_queue;
49  this->packet_queue = p;
50  }
51  delete this->packet_recv;
52  this->packet_recv = nullptr;
53 
55 }
56 
64 {
65  Packet *p;
66  assert(packet != nullptr);
67 
68  packet->PrepareToSend();
69 
70  /* Reallocate the packet as in 99+% of the times we send at most 25 bytes and
71  * keeping the other 1400+ bytes wastes memory, especially when someone tries
72  * to do a denial of service attack! */
73  packet->buffer = ReallocT(packet->buffer, packet->size);
74 
75  /* Locate last packet buffered for the client */
76  p = this->packet_queue;
77  if (p == nullptr) {
78  /* No packets yet */
79  this->packet_queue = packet;
80  } else {
81  /* Skip to the last packet */
82  while (p->next != nullptr) p = p->next;
83  p->next = packet;
84  }
85 }
86 
98 {
99  ssize_t res;
100  Packet *p;
101 
102  /* We can not write to this socket!! */
103  if (!this->writable) return SPS_NONE_SENT;
104  if (!this->IsConnected()) return SPS_CLOSED;
105 
106  p = this->packet_queue;
107  while (p != nullptr) {
108  res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0);
109  if (res == -1) {
110  int err = GET_LAST_ERROR();
111  if (err != EWOULDBLOCK) {
112  /* Something went wrong.. close client! */
113  if (!closing_down) {
114  DEBUG(net, 0, "send failed with error %d", err);
115  this->CloseConnection();
116  }
117  return SPS_CLOSED;
118  }
119  return SPS_PARTLY_SENT;
120  }
121  if (res == 0) {
122  /* Client/server has left us :( */
123  if (!closing_down) this->CloseConnection();
124  return SPS_CLOSED;
125  }
126 
127  p->pos += res;
128 
129  /* Is this packet sent? */
130  if (p->pos == p->size) {
131  /* Go to the next packet */
132  this->packet_queue = p->next;
133  delete p;
134  p = this->packet_queue;
135  } else {
136  return SPS_PARTLY_SENT;
137  }
138  }
139 
140  return SPS_ALL_SENT;
141 }
142 
148 {
149  ssize_t res;
150 
151  if (!this->IsConnected()) return nullptr;
152 
153  if (this->packet_recv == nullptr) {
154  this->packet_recv = new Packet(this);
155  }
156 
157  Packet *p = this->packet_recv;
158 
159  /* Read packet size */
160  if (p->pos < sizeof(PacketSize)) {
161  while (p->pos < sizeof(PacketSize)) {
162  /* Read the size of the packet */
163  res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
164  if (res == -1) {
165  int err = GET_LAST_ERROR();
166  if (err != EWOULDBLOCK) {
167  /* Something went wrong... (104 is connection reset by peer) */
168  if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
169  this->CloseConnection();
170  return nullptr;
171  }
172  /* Connection would block, so stop for now */
173  return nullptr;
174  }
175  if (res == 0) {
176  /* Client/server has left */
177  this->CloseConnection();
178  return nullptr;
179  }
180  p->pos += res;
181  }
182 
183  /* Read the packet size from the received packet */
184  p->ReadRawPacketSize();
185 
186  if (p->size > SEND_MTU) {
187  this->CloseConnection();
188  return nullptr;
189  }
190  }
191 
192  /* Read rest of packet */
193  while (p->pos < p->size) {
194  res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0);
195  if (res == -1) {
196  int err = GET_LAST_ERROR();
197  if (err != EWOULDBLOCK) {
198  /* Something went wrong... (104 is connection reset by peer) */
199  if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
200  this->CloseConnection();
201  return nullptr;
202  }
203  /* Connection would block */
204  return nullptr;
205  }
206  if (res == 0) {
207  /* Client/server has left */
208  this->CloseConnection();
209  return nullptr;
210  }
211 
212  p->pos += res;
213  }
214 
215  /* Prepare for receiving a new packet */
216  this->packet_recv = nullptr;
217 
218  p->PrepareToRead();
219  return p;
220 }
221 
228 {
229  fd_set read_fd, write_fd;
230  struct timeval tv;
231 
232  FD_ZERO(&read_fd);
233  FD_ZERO(&write_fd);
234 
235  FD_SET(this->sock, &read_fd);
236  FD_SET(this->sock, &write_fd);
237 
238  tv.tv_sec = tv.tv_usec = 0; // don't block at all.
239  if (select(FD_SETSIZE, &read_fd, &write_fd, nullptr, &tv) < 0) return false;
240 
241  this->writable = !!FD_ISSET(this->sock, &write_fd);
242  return FD_ISSET(this->sock, &read_fd) != 0;
243 }
Everything is okay.
Definition: core.h:25
SOCKET sock
The socket currently connected to.
Definition: tcp.h:34
Internal entity of a packet.
Definition: packet.h:42
The connection got closed.
Definition: tcp.h:22
PacketSize pos
The current read/write position in the packet.
Definition: packet.h:52
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition: packet.cpp:63
NetworkRecvStatus CloseConnection(bool error=true) override
Close the current connection; for TCP this will be mostly equivalent to Close(), but for UDP it just ...
Definition: tcp.cpp:40
virtual Packet * ReceivePacket()
Receives a packet for the given client.
Definition: tcp.cpp:147
SendPacketsState SendPackets(bool closing_down=false)
Sends all the buffered packets out for this client.
Definition: tcp.cpp:97
void PrepareToRead()
Prepares the packet so it can be read.
Definition: packet.cpp:198
byte * buffer
The buffer of this packet, of basically variable length up to SEND_MTU.
Definition: packet.h:54
bool writable
Can we write to this socket?
Definition: tcp.h:35
Packet * packet_recv
Partially received packet.
Definition: tcp.h:32
static T * ReallocT(T *t_ptr, size_t num_elements)
Simplified reallocation function that allocates the specified number of elements of the given type...
Definition: alloc_func.hpp:113
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
Definition: core.h:24
All packets in the queue are sent.
Definition: tcp.h:25
PacketSize size
The size of the whole packet for received packets.
Definition: packet.h:50
The buffer is still full, so no (parts of) packets could be sent.
Definition: tcp.h:23
Packet * next
The next packet.
Definition: packet.h:44
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:37
virtual NetworkRecvStatus CloseConnection(bool error=true)
Close the current connection; for TCP this will be mostly equivalent to Close(), but for UDP it just ...
Definition: core.h:61
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:114
The packets are partly sent; there are more packets to be sent in the queue.
Definition: tcp.h:24
static const uint16 SEND_MTU
Number of bytes we can pack in a single packet.
Definition: config.h:35
bool IsConnected() const
Whether this socket is currently bound to a socket.
Definition: tcp.h:41
void ReadRawPacketSize()
Reads the packet size from the raw packet and stores it in the packet->size.
Definition: packet.cpp:188
virtual void SendPacket(Packet *packet)
This function puts the packet in the send-queue and it is send as soon as possible.
Definition: tcp.cpp:63
bool CanSendReceive()
Check whether this socket can send or receive something.
Definition: tcp.cpp:227
SendPacketsState
The states of sending the packets.
Definition: tcp.h:21
Basic functions to receive and send TCP packets.
NetworkTCPSocketHandler(SOCKET s=INVALID_SOCKET)
Construct a socket handler for a TCP connection.
Definition: tcp.cpp:25
Packet * packet_queue
Packets that are awaiting delivery.
Definition: tcp.h:31
uint16 PacketSize
Size of the whole packet.
Definition: packet.h:21
SocketHandler for all network sockets in OpenTTD.
Definition: core.h:43