tcp.cpp

Go to the documentation of this file.
00001 /* $Id: tcp.cpp 15206 2009-01-22 10:09:56Z rubidium $ */
00002 
00007 #ifdef ENABLE_NETWORK
00008 
00009 #include "../../stdafx.h"
00010 #include "../../debug.h"
00011 
00012 #include "packet.h"
00013 #include "tcp.h"
00014 
00015 NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) :
00016     NetworkSocketHandler(s),
00017     packet_queue(NULL), packet_recv(NULL), writable(false)
00018 {
00019 }
00020 
00021 NetworkTCPSocketHandler::~NetworkTCPSocketHandler()
00022 {
00023   this->CloseConnection();
00024 
00025   if (this->sock != INVALID_SOCKET) closesocket(this->sock);
00026   this->sock = INVALID_SOCKET;
00027 }
00028 
00029 NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection()
00030 {
00031   this->writable = false;
00032   this->has_quit = true;
00033 
00034   /* Free all pending and partially received packets */
00035   while (this->packet_queue != NULL) {
00036     Packet *p = this->packet_queue->next;
00037     delete this->packet_queue;
00038     this->packet_queue = p;
00039   }
00040   delete this->packet_recv;
00041   this->packet_recv = NULL;
00042 
00043   return NETWORK_RECV_STATUS_OKAY;
00044 }
00045 
00052 void NetworkTCPSocketHandler::Send_Packet(Packet *packet)
00053 {
00054   Packet *p;
00055   assert(packet != NULL);
00056 
00057   packet->PrepareToSend();
00058 
00059   /* Locate last packet buffered for the client */
00060   p = this->packet_queue;
00061   if (p == NULL) {
00062     /* No packets yet */
00063     this->packet_queue = packet;
00064   } else {
00065     /* Skip to the last packet */
00066     while (p->next != NULL) p = p->next;
00067     p->next = packet;
00068   }
00069 }
00070 
00078 bool NetworkTCPSocketHandler::Send_Packets()
00079 {
00080   ssize_t res;
00081   Packet *p;
00082 
00083   /* We can not write to this socket!! */
00084   if (!this->writable) return false;
00085   if (!this->IsConnected()) return false;
00086 
00087   p = this->packet_queue;
00088   while (p != NULL) {
00089     res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0);
00090     if (res == -1) {
00091       int err = GET_LAST_ERROR();
00092       if (err != EWOULDBLOCK) {
00093         /* Something went wrong.. close client! */
00094         DEBUG(net, 0, "send failed with error %d", err);
00095         this->CloseConnection();
00096         return false;
00097       }
00098       return true;
00099     }
00100     if (res == 0) {
00101       /* Client/server has left us :( */
00102       this->CloseConnection();
00103       return false;
00104     }
00105 
00106     p->pos += res;
00107 
00108     /* Is this packet sent? */
00109     if (p->pos == p->size) {
00110       /* Go to the next packet */
00111       this->packet_queue = p->next;
00112       delete p;
00113       p = this->packet_queue;
00114     } else {
00115       return true;
00116     }
00117   }
00118 
00119   return true;
00120 }
00121 
00127 Packet *NetworkTCPSocketHandler::Recv_Packet(NetworkRecvStatus *status)
00128 {
00129   ssize_t res;
00130   Packet *p;
00131 
00132   *status = NETWORK_RECV_STATUS_OKAY;
00133 
00134   if (!this->IsConnected()) return NULL;
00135 
00136   if (this->packet_recv == NULL) {
00137     this->packet_recv = new Packet(this);
00138     if (this->packet_recv == NULL) error("Failed to allocate packet");
00139   }
00140 
00141   p = this->packet_recv;
00142 
00143   /* Read packet size */
00144   if (p->pos < sizeof(PacketSize)) {
00145     while (p->pos < sizeof(PacketSize)) {
00146     /* Read the size of the packet */
00147       res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
00148       if (res == -1) {
00149         int err = GET_LAST_ERROR();
00150         if (err != EWOULDBLOCK) {
00151           /* Something went wrong... (104 is connection reset by peer) */
00152           if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00153           *status = this->CloseConnection();
00154           return NULL;
00155         }
00156         /* Connection would block, so stop for now */
00157         return NULL;
00158       }
00159       if (res == 0) {
00160         /* Client/server has left */
00161         *status = this->CloseConnection();
00162         return NULL;
00163       }
00164       p->pos += res;
00165     }
00166 
00167     /* Read the packet size from the received packet */
00168     p->ReadRawPacketSize();
00169 
00170     if (p->size > SEND_MTU) {
00171       *status = this->CloseConnection();
00172       return NULL;
00173     }
00174   }
00175 
00176   /* Read rest of packet */
00177   while (p->pos < p->size) {
00178     res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0);
00179     if (res == -1) {
00180       int err = GET_LAST_ERROR();
00181       if (err != EWOULDBLOCK) {
00182         /* Something went wrong... (104 is connection reset by peer) */
00183         if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
00184         *status = this->CloseConnection();
00185         return NULL;
00186       }
00187       /* Connection would block */
00188       return NULL;
00189     }
00190     if (res == 0) {
00191       /* Client/server has left */
00192       *status = this->CloseConnection();
00193       return NULL;
00194     }
00195 
00196     p->pos += res;
00197   }
00198 
00199   /* Prepare for receiving a new packet */
00200   this->packet_recv = NULL;
00201 
00202   p->PrepareToRead();
00203   return p;
00204 }
00205 
00206 bool NetworkTCPSocketHandler::IsPacketQueueEmpty()
00207 {
00208   return this->packet_queue == NULL;
00209 }
00210 
00211 #endif /* ENABLE_NETWORK */

Generated on Tue Dec 1 00:06:16 2009 for OpenTTD by  doxygen 1.5.6