tcp.cpp

Go to the documentation of this file.
00001 /* $Id: tcp.cpp 21184 2010-11-14 12:42:29Z 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::Send_Packet(Packet *packet)
00060 {
00061   Packet *p;
00062   assert(packet != NULL);
00063 
00064   packet->PrepareToSend();
00065 
00066   /* Locate last packet buffered for the client */
00067   p = this->packet_queue;
00068   if (p == NULL) {
00069     /* No packets yet */
00070     this->packet_queue = packet;
00071   } else {
00072     /* Skip to the last packet */
00073     while (p->next != NULL) p = p->next;
00074     p->next = packet;
00075   }
00076 }
00077 
00088 bool NetworkTCPSocketHandler::Send_Packets(bool closing_down)
00089 {
00090   ssize_t res;
00091   Packet *p;
00092 
00093   /* We can not write to this socket!! */
00094   if (!this->writable) return false;
00095   if (!this->IsConnected()) return false;
00096 
00097   p = this->packet_queue;
00098   while (p != NULL) {
00099     res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0);
00100     if (res == -1) {
00101       int err = GET_LAST_ERROR();
00102       if (err != EWOULDBLOCK) {
00103         /* Something went wrong.. close client! */
00104         if (!closing_down) {
00105           DEBUG(net, 0, "send failed with error %d", err);
00106           this->CloseConnection();
00107         }
00108         return false;
00109       }
00110       return true;
00111     }
00112     if (res == 0) {
00113       /* Client/server has left us :( */
00114       if (!closing_down) this->CloseConnection();
00115       return false;
00116     }
00117 
00118     p->pos += res;
00119 
00120     /* Is this packet sent? */
00121     if (p->pos == p->size) {
00122       /* Go to the next packet */
00123       this->packet_queue = p->next;
00124       delete p;
00125       p = this->packet_queue;
00126     } else {
00127       return true;
00128     }
00129   }
00130 
00131   return true;
00132 }
00133 
00139 Packet *NetworkTCPSocketHandler::Recv_Packet()
00140 {
00141   ssize_t res;
00142 
00143   if (!this->IsConnected()) return NULL;
00144 
00145   if (this->packet_recv == NULL) {
00146     this->packet_recv = new Packet(this);
00147   }
00148 
00149   Packet *p = this->packet_recv;
00150 
00151   /* Read packet size */
00152   if (p->pos < sizeof(PacketSize)) {
00153     while (p->pos < sizeof(PacketSize)) {
00154     /* Read the size of the packet */
00155       res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
00156       if (res == -1) {
00157         int err = GET_LAST_ERROR();
00158         if (err != EWOULDBLOCK) {
00159           /* Something went wrong... (104 is connection reset by peer) */
00160           if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00161           this->CloseConnection();
00162           return NULL;
00163         }
00164         /* Connection would block, so stop for now */
00165         return NULL;
00166       }
00167       if (res == 0) {
00168         /* Client/server has left */
00169         this->CloseConnection();
00170         return NULL;
00171       }
00172       p->pos += res;
00173     }
00174 
00175     /* Read the packet size from the received packet */
00176     p->ReadRawPacketSize();
00177 
00178     if (p->size > SEND_MTU) {
00179       this->CloseConnection();
00180       return NULL;
00181     }
00182   }
00183 
00184   /* Read rest of packet */
00185   while (p->pos < p->size) {
00186     res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0);
00187     if (res == -1) {
00188       int err = GET_LAST_ERROR();
00189       if (err != EWOULDBLOCK) {
00190         /* Something went wrong... (104 is connection reset by peer) */
00191         if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00192         this->CloseConnection();
00193         return NULL;
00194       }
00195       /* Connection would block */
00196       return NULL;
00197     }
00198     if (res == 0) {
00199       /* Client/server has left */
00200       this->CloseConnection();
00201       return NULL;
00202     }
00203 
00204     p->pos += res;
00205   }
00206 
00207   /* Prepare for receiving a new packet */
00208   this->packet_recv = NULL;
00209 
00210   p->PrepareToRead();
00211   return p;
00212 }
00213 
00214 bool NetworkTCPSocketHandler::IsPacketQueueEmpty()
00215 {
00216   return this->packet_queue == NULL;
00217 }
00218 
00219 #endif /* ENABLE_NETWORK */

Generated on Sat Nov 20 20:59:04 2010 for OpenTTD by  doxygen 1.6.1