tcp.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00014 #ifdef ENABLE_NETWORK
00015 
00016 #include "../../stdafx.h"
00017 #include "../../debug.h"
00018 
00019 #include "tcp.h"
00020 
00021 NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
00022     NetworkSocketHandler(),
00023     packet_queue(NULL), packet_recv(NULL),
00024     sock(s), writable(false)
00025 {
00026 }
00027 
00028 NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
00029 {
00030   this->CloseConnection();
00031 
00032   if (this->sock != INVALID_SOCKET) closesocket(this->sock);
00033   this->sock = INVALID_SOCKET;
00034 }
00035 
00036 NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error)
00037 {
00038   this->writable = false;
00039   NetworkSocketHandler::CloseConnection(error);
00040 
00041   /* Free all pending and partially received packets */
00042   while (this->packet_queue != NULL) {
00043     Packet *p = this->packet_queue->next;
00044     delete this->packet_queue;
00045     this->packet_queue = p;
00046   }
00047   delete this->packet_recv;
00048   this->packet_recv = NULL;
00049 
00050   return NETWORK_RECV_STATUS_OKAY;
00051 }
00052 
00059 void NetworkTCPSocketHandler::SendPacket(Packet *packet)
00060 {
00061   Packet *p;
00062   assert(packet != NULL);
00063 
00064   packet->PrepareToSend();
00065 
00066   /* Reallocate the packet as in 99+% of the times we send at most 25 bytes and
00067    * keeping the other 1400+ bytes wastes memory, especially when someone tries
00068    * to do a denial of service attack! */
00069   packet->buffer = ReallocT(packet->buffer, packet->size);
00070 
00071   /* Locate last packet buffered for the client */
00072   p = this->packet_queue;
00073   if (p == NULL) {
00074     /* No packets yet */
00075     this->packet_queue = packet;
00076   } else {
00077     /* Skip to the last packet */
00078     while (p->next != NULL) p = p->next;
00079     p->next = packet;
00080   }
00081 }
00082 
00093 bool NetworkTCPSocketHandler::SendPackets(bool closing_down)
00094 {
00095   ssize_t res;
00096   Packet *p;
00097 
00098   /* We can not write to this socket!! */
00099   if (!this->writable) return false;
00100   if (!this->IsConnected()) return false;
00101 
00102   p = this->packet_queue;
00103   while (p != NULL) {
00104     res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0);
00105     if (res == -1) {
00106       int err = GET_LAST_ERROR();
00107       if (err != EWOULDBLOCK) {
00108         /* Something went wrong.. close client! */
00109         if (!closing_down) {
00110           DEBUG(net, 0, "send failed with error %d", err);
00111           this->CloseConnection();
00112         }
00113         return false;
00114       }
00115       return true;
00116     }
00117     if (res == 0) {
00118       /* Client/server has left us :( */
00119       if (!closing_down) this->CloseConnection();
00120       return false;
00121     }
00122 
00123     p->pos += res;
00124 
00125     /* Is this packet sent? */
00126     if (p->pos == p->size) {
00127       /* Go to the next packet */
00128       this->packet_queue = p->next;
00129       delete p;
00130       p = this->packet_queue;
00131     } else {
00132       return true;
00133     }
00134   }
00135 
00136   return true;
00137 }
00138 
00144 Packet *NetworkTCPSocketHandler::ReceivePacket()
00145 {
00146   ssize_t res;
00147 
00148   if (!this->IsConnected()) return NULL;
00149 
00150   if (this->packet_recv == NULL) {
00151     this->packet_recv = new Packet(this);
00152   }
00153 
00154   Packet *p = this->packet_recv;
00155 
00156   /* Read packet size */
00157   if (p->pos < sizeof(PacketSize)) {
00158     while (p->pos < sizeof(PacketSize)) {
00159     /* Read the size of the packet */
00160       res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
00161       if (res == -1) {
00162         int err = GET_LAST_ERROR();
00163         if (err != EWOULDBLOCK) {
00164           /* Something went wrong... (104 is connection reset by peer) */
00165           if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00166           this->CloseConnection();
00167           return NULL;
00168         }
00169         /* Connection would block, so stop for now */
00170         return NULL;
00171       }
00172       if (res == 0) {
00173         /* Client/server has left */
00174         this->CloseConnection();
00175         return NULL;
00176       }
00177       p->pos += res;
00178     }
00179 
00180     /* Read the packet size from the received packet */
00181     p->ReadRawPacketSize();
00182 
00183     if (p->size > SEND_MTU) {
00184       this->CloseConnection();
00185       return NULL;
00186     }
00187   }
00188 
00189   /* Read rest of packet */
00190   while (p->pos < p->size) {
00191     res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0);
00192     if (res == -1) {
00193       int err = GET_LAST_ERROR();
00194       if (err != EWOULDBLOCK) {
00195         /* Something went wrong... (104 is connection reset by peer) */
00196         if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00197         this->CloseConnection();
00198         return NULL;
00199       }
00200       /* Connection would block */
00201       return NULL;
00202     }
00203     if (res == 0) {
00204       /* Client/server has left */
00205       this->CloseConnection();
00206       return NULL;
00207     }
00208 
00209     p->pos += res;
00210   }
00211 
00212   /* Prepare for receiving a new packet */
00213   this->packet_recv = NULL;
00214 
00215   p->PrepareToRead();
00216   return p;
00217 }
00218 
00219 bool NetworkTCPSocketHandler::IsPacketQueueEmpty()
00220 {
00221   return this->packet_queue == NULL;
00222 }
00223 
00229 bool NetworkTCPSocketHandler::CanSendReceive()
00230 {
00231   fd_set read_fd, write_fd;
00232   struct timeval tv;
00233 
00234   FD_ZERO(&read_fd);
00235   FD_ZERO(&write_fd);
00236 
00237   FD_SET(this->sock, &read_fd);
00238   FD_SET(this->sock, &write_fd);
00239 
00240   tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00241 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00242   select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00243 #else
00244   WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00245 #endif
00246 
00247   this->writable = !!FD_ISSET(this->sock, &write_fd);
00248   return FD_ISSET(this->sock, &read_fd) != 0;
00249 }
00250 
00251 #endif /* ENABLE_NETWORK */

Generated on Sun Jan 23 01:49:04 2011 for OpenTTD by  doxygen 1.6.1