# 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 */