tcp.cpp

Go to the documentation of this file.
00001 /* $Id: tcp.cpp 22068 2011-02-12 21:09:34Z rubidium $ */
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 SendPacketsState 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 SPS_NONE_SENT;
00100   if (!this->IsConnected()) return SPS_CLOSED;
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 SPS_CLOSED;
00114       }
00115       return SPS_PARTLY_SENT;
00116     }
00117     if (res == 0) {
00118       /* Client/server has left us :( */
00119       if (!closing_down) this->CloseConnection();
00120       return SPS_CLOSED;
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 SPS_PARTLY_SENT;
00133     }
00134   }
00135 
00136   return SPS_ALL_SENT;
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 
00224 bool NetworkTCPSocketHandler::CanSendReceive()
00225 {
00226   fd_set read_fd, write_fd;
00227   struct timeval tv;
00228 
00229   FD_ZERO(&read_fd);
00230   FD_ZERO(&write_fd);
00231 
00232   FD_SET(this->sock, &read_fd);
00233   FD_SET(this->sock, &write_fd);
00234 
00235   tv.tv_sec = tv.tv_usec = 0; // don't block at all.
00236 #if !defined(__MORPHOS__) && !defined(__AMIGA__)
00237   select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
00238 #else
00239   WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
00240 #endif
00241 
00242   this->writable = !!FD_ISSET(this->sock, &write_fd);
00243   return FD_ISSET(this->sock, &read_fd) != 0;
00244 }
00245 
00246 #endif /* ENABLE_NETWORK */

Generated on Fri Mar 18 23:17:37 2011 for OpenTTD by  doxygen 1.6.1