tcp.cpp

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

Generated on Wed Mar 17 23:50:12 2010 for OpenTTD by  doxygen 1.6.1