# tcp.cpp

Go to the documentation of this file.

    00001 /* $Id: tcp.cpp 11828 2008-01-13 01:21:35Z rubidium $ */
    00002
    00007 #ifdef ENABLE_NETWORK
    00008
    00009 #include "../../stdafx.h"
    00010 #include "../../debug.h"
    00011 #include "../../openttd.h"
    00012 #include "../../variables.h"
    00013
    00014 #include "../network_data.h"
    00015 #include "packet.h"
    00016 #include "tcp.h"
    00017
    00018 #include "table/strings.h"
    00019
    00021 void NetworkTCPSocketHandler::Initialize()
    00022 {
    00023   this->sock              = INVALID_SOCKET;
    00024
    00025   this->index             = 0;
    00026   this->last_frame        = 0;
    00027   this->last_frame_server = 0;
    00028   this->lag_test          = 0;
    00029
    00030   this->status            = STATUS_INACTIVE;
    00031   this->has_quit          = false;
    00032   this->writable          = false;
    00033
    00034   this->packet_queue      = NULL;
    00035   this->packet_recv       = NULL;
    00036
    00037   this->command_queue     = NULL;
    00038 }
    00039
    00040 void NetworkTCPSocketHandler::Destroy()
    00041 {
    00042   closesocket(this->sock);
    00043   this->writable = false;
    00044   this->has_quit = true;
    00045
    00046   /* Free all pending and partially received packets */
    00047   while (this->packet_queue != NULL) {
    00048     Packet *p = this->packet_queue->next;
    00049     delete this->packet_queue;
    00050     this->packet_queue = p;
    00051   }
    00052   delete this->packet_recv;
    00053   this->packet_recv = NULL;
    00054
    00055   while (this->command_queue != NULL) {
    00056     CommandPacket *p = this->command_queue->next;
    00057     free(this->command_queue);
    00058     this->command_queue = p;
    00059   }
    00060 }
    00061
    00070 NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection()
    00071 {
    00072   NetworkCloseClient(this);
    00073
    00074   /* Clients drop back to the main menu */
    00075   if (!_network_server && _networking) {
    00076     _switch_mode = SM_MENU;
    00077     _networking = false;
    00078     _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION;
    00079
    00080     return NETWORK_RECV_STATUS_CONN_LOST;
    00081   }
    00082
    00083   return NETWORK_RECV_STATUS_OKAY;
    00084 }
    00085
    00092 void NetworkTCPSocketHandler::Send_Packet(Packet *packet)
    00093 {
    00094   Packet *p;
    00095   assert(packet != NULL);
    00096
    00097   packet->PrepareToSend();
    00098
    00099   /* Locate last packet buffered for the client */
    00100   p = this->packet_queue;
    00101   if (p == NULL) {
    00102     /* No packets yet */
    00103     this->packet_queue = packet;
    00104   } else {
    00105     /* Skip to the last packet */
    00106     while (p->next != NULL) p = p->next;
    00107     p->next = packet;
    00108   }
    00109 }
    00110
    00118 bool NetworkTCPSocketHandler::Send_Packets()
    00119 {
    00120   ssize_t res;
    00121   Packet *p;
    00122
    00123   /* We can not write to this socket!! */
    00124   if (!this->writable) return false;
    00125   if (!this->IsConnected()) return false;
    00126
    00127   p = this->packet_queue;
    00128   while (p != NULL) {
    00129     res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0);
    00130     if (res == -1) {
    00131       int err = GET_LAST_ERROR();
    00132       if (err != EWOULDBLOCK) {
    00133         /* Something went wrong.. close client! */
    00134         DEBUG(net, 0, "send failed with error %d", err);
    00135         this->CloseConnection();
    00136         return false;
    00137       }
    00138       return true;
    00139     }
    00140     if (res == 0) {
    00141       /* Client/server has left us :( */
    00142       this->CloseConnection();
    00143       return false;
    00144     }
    00145
    00146     p->pos += res;
    00147
    00148     /* Is this packet sent? */
    00149     if (p->pos == p->size) {
    00150       /* Go to the next packet */
    00151       this->packet_queue = p->next;
    00152       delete p;
    00153       p = this->packet_queue;
    00154     } else {
    00155       return true;
    00156     }
    00157   }
    00158
    00159   return true;
    00160 }
    00161
    00167 Packet *NetworkTCPSocketHandler::Recv_Packet(NetworkRecvStatus *status)
    00168 {
    00169   ssize_t res;
    00170   Packet *p;
    00171
    00172   *status = NETWORK_RECV_STATUS_OKAY;
    00173
    00174   if (!this->IsConnected()) return NULL;
    00175
    00176   if (this->packet_recv == NULL) {
    00177     this->packet_recv = new Packet(this);
    00178     if (this->packet_recv == NULL) error("Failed to allocate packet");
    00179   }
    00180
    00181   p = this->packet_recv;
    00182
    00183   /* Read packet size */
    00184   if (p->pos < sizeof(PacketSize)) {
    00185     while (p->pos < sizeof(PacketSize)) {
    00186     /* Read the size of the packet */
    00187       res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0);
    00188       if (res == -1) {
    00189         int err = GET_LAST_ERROR();
    00190         if (err != EWOULDBLOCK) {
    00191           /* Something went wrong... (104 is connection reset by peer) */
    00192           if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
    00193           *status = this->CloseConnection();
    00194           return NULL;
    00195         }
    00196         /* Connection would block, so stop for now */
    00197         return NULL;
    00198       }
    00199       if (res == 0) {
    00200         /* Client/server has left */
    00201         *status = this->CloseConnection();
    00202         return NULL;
    00203       }
    00204       p->pos += res;
    00205     }
    00206
    00207     /* Read the packet size from the received packet */
    00208     p->ReadRawPacketSize();
    00209
    00210     if (p->size > SEND_MTU) {
    00211       *status = this->CloseConnection();
    00212       return NULL;
    00213     }
    00214   }
    00215
    00216   /* Read rest of packet */
    00217   while (p->pos < p->size) {
    00218     res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0);
    00219     if (res == -1) {
    00220       int err = GET_LAST_ERROR();
    00221       if (err != EWOULDBLOCK) {
    00222         /* Something went wrong... (104 is connection reset by peer) */
    00223         if (err != 104) DEBUG(net, 0, "recv failed with error %d", err);
    00224         *status = this->CloseConnection();
    00225         return NULL;
    00226       }
    00227       /* Connection would block */
    00228       return NULL;
    00229     }
    00230     if (res == 0) {
    00231       /* Client/server has left */
    00232       *status = this->CloseConnection();
    00233       return NULL;
    00234     }
    00235
    00236     p->pos += res;
    00237   }
    00238
    00239   /* Prepare for receiving a new packet */
    00240   this->packet_recv = NULL;
    00241
    00242   p->PrepareToRead();
    00243   return p;
    00244 }
    00245
    00246 bool NetworkTCPSocketHandler::IsPacketQueueEmpty()
    00247 {
    00248   return this->packet_queue == NULL;
    00249 }
    00250
    00251
    00252 #endif /* ENABLE_NETWORK */