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

Generated on Wed Oct 1 17:03:21 2008 for openttd by  doxygen 1.5.6