udp.cpp

Go to the documentation of this file.
00001 /* $Id: udp.cpp 15718 2009-03-15 00:32:18Z rubidium $ */
00002 
00007 #ifdef ENABLE_NETWORK
00008 
00009 #include "../../stdafx.h"
00010 #include "../../debug.h"
00011 #include "../../core/bitmath_func.hpp"
00012 #include "../../core/math_func.hpp"
00013 #include "../../core/alloc_func.hpp"
00014 #include "../../date_func.h"
00015 #include "packet.h"
00016 #include "udp.h"
00017 
00025 bool NetworkUDPSocketHandler::Listen(const uint32 host, const uint16 port, const bool broadcast)
00026 {
00027   struct sockaddr_in sin;
00028 
00029   /* Make sure socket is closed */
00030   this->Close();
00031 
00032   this->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
00033   if (!this->IsConnected()) {
00034     DEBUG(net, 0, "[udp] failed to start UDP listener");
00035     return false;
00036   }
00037 
00038   SetNonBlocking(this->sock);
00039 
00040   sin.sin_family = AF_INET;
00041   /* Listen on all IPs */
00042   sin.sin_addr.s_addr = host;
00043   sin.sin_port = htons(port);
00044 
00045   if (bind(this->sock, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
00046     DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port);
00047     return false;
00048   }
00049 
00050   if (broadcast) {
00051     /* Enable broadcast */
00052     unsigned long val = 1;
00053 #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
00054     setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val));
00055 #endif
00056   }
00057 
00058   DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port);
00059 
00060   return true;
00061 }
00062 
00066 void NetworkUDPSocketHandler::Close()
00067 {
00068   if (!this->IsConnected()) return;
00069 
00070   closesocket(this->sock);
00071   this->sock = INVALID_SOCKET;
00072 }
00073 
00074 NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection()
00075 {
00076   this->has_quit = true;
00077   return NETWORK_RECV_STATUS_OKAY;
00078 }
00079 
00085 void NetworkUDPSocketHandler::SendPacket(Packet *p, const struct sockaddr_in *recv)
00086 {
00087   int res;
00088 
00089   p->PrepareToSend();
00090 
00091   /* Send the buffer */
00092   res = sendto(this->sock, (const char*)p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv));
00093 
00094   /* Check for any errors, but ignore it otherwise */
00095   if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR());
00096 }
00097 
00101 void NetworkUDPSocketHandler::ReceivePackets()
00102 {
00103   struct sockaddr_in client_addr;
00104   socklen_t client_len;
00105   int nbytes;
00106   Packet p(this);
00107   int packet_len;
00108 
00109   if (!this->IsConnected()) return;
00110 
00111   packet_len = sizeof(p.buffer);
00112   client_len = sizeof(client_addr);
00113 
00114   /* Try to receive anything */
00115   SetNonBlocking(this->sock); // Some OSes seem to lose the non-blocking status of the socket
00116   nbytes = recvfrom(this->sock, (char*)p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
00117 
00118   /* We got some bytes for the base header of the packet. */
00119   if (nbytes > 2) {
00120     p.PrepareToRead();
00121 
00122     /* If the size does not match the packet must be corrupted.
00123      * Otherwise it will be marked as corrupted later on. */
00124     if (nbytes != p.size) {
00125       DEBUG(net, 1, "received a packet with mismatching size from %s:%d",
00126           inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
00127 
00128       return;
00129     }
00130 
00131     /* Handle the packet */
00132     this->HandleUDPPacket(&p, &client_addr);
00133   }
00134 }
00135 
00136 
00142 void NetworkUDPSocketHandler::Send_NetworkGameInfo(Packet *p, const NetworkGameInfo *info)
00143 {
00144   p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
00145 
00146   /*
00147    *              Please observe the order.
00148    * The parts must be read in the same order as they are sent!
00149    */
00150 
00151   /* Update the documentation in udp.h on changes
00152    * to the NetworkGameInfo wire-protocol! */
00153 
00154   /* NETWORK_GAME_INFO_VERSION = 4 */
00155   {
00156     /* Only send the GRF Identification (GRF_ID and MD5 checksum) of
00157      * the GRFs that are needed, i.e. the ones that the server has
00158      * selected in the NewGRF GUI and not the ones that are used due
00159      * to the fact that they are in [newgrf-static] in openttd.cfg */
00160     const GRFConfig *c;
00161     uint count = 0;
00162 
00163     /* Count number of GRFs to send information about */
00164     for (c = info->grfconfig; c != NULL; c = c->next) {
00165       if (!HasBit(c->flags, GCF_STATIC)) count++;
00166     }
00167     p->Send_uint8 (count); // Send number of GRFs
00168 
00169     /* Send actual GRF Identifications */
00170     for (c = info->grfconfig; c != NULL; c = c->next) {
00171       if (!HasBit(c->flags, GCF_STATIC)) this->Send_GRFIdentifier(p, c);
00172     }
00173   }
00174 
00175   /* NETWORK_GAME_INFO_VERSION = 3 */
00176   p->Send_uint32(info->game_date);
00177   p->Send_uint32(info->start_date);
00178 
00179   /* NETWORK_GAME_INFO_VERSION = 2 */
00180   p->Send_uint8 (info->companies_max);
00181   p->Send_uint8 (info->companies_on);
00182   p->Send_uint8 (info->spectators_max);
00183 
00184   /* NETWORK_GAME_INFO_VERSION = 1 */
00185   p->Send_string(info->server_name);
00186   p->Send_string(info->server_revision);
00187   p->Send_uint8 (info->server_lang);
00188   p->Send_bool  (info->use_password);
00189   p->Send_uint8 (info->clients_max);
00190   p->Send_uint8 (info->clients_on);
00191   p->Send_uint8 (info->spectators_on);
00192   p->Send_string(info->map_name);
00193   p->Send_uint16(info->map_width);
00194   p->Send_uint16(info->map_height);
00195   p->Send_uint8 (info->map_set);
00196   p->Send_bool  (info->dedicated);
00197 }
00198 
00204 void NetworkUDPSocketHandler::Recv_NetworkGameInfo(Packet *p, NetworkGameInfo *info)
00205 {
00206   static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
00207 
00208   info->game_info_version = p->Recv_uint8();
00209 
00210   /*
00211    *              Please observe the order.
00212    * The parts must be read in the same order as they are sent!
00213    */
00214 
00215   /* Update the documentation in udp.h on changes
00216    * to the NetworkGameInfo wire-protocol! */
00217 
00218   switch (info->game_info_version) {
00219     case 4: {
00220       GRFConfig **dst = &info->grfconfig;
00221       uint i;
00222       uint num_grfs = p->Recv_uint8();
00223 
00224       /* Broken/bad data. It cannot have that many NewGRFs. */
00225       if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
00226 
00227       for (i = 0; i < num_grfs; i++) {
00228         GRFConfig *c = CallocT<GRFConfig>(1);
00229         this->Recv_GRFIdentifier(p, c);
00230         this->HandleIncomingNetworkGameInfoGRFConfig(c);
00231 
00232         /* Append GRFConfig to the list */
00233         *dst = c;
00234         dst = &c->next;
00235       }
00236     } // Fallthrough
00237     case 3:
00238       info->game_date      = Clamp(p->Recv_uint32(), 0, MAX_DATE);
00239       info->start_date     = Clamp(p->Recv_uint32(), 0, MAX_DATE);
00240       /* Fallthrough */
00241     case 2:
00242       info->companies_max  = p->Recv_uint8 ();
00243       info->companies_on   = p->Recv_uint8 ();
00244       info->spectators_max = p->Recv_uint8 ();
00245       /* Fallthrough */
00246     case 1:
00247       p->Recv_string(info->server_name,     sizeof(info->server_name));
00248       p->Recv_string(info->server_revision, sizeof(info->server_revision));
00249       info->server_lang    = p->Recv_uint8 ();
00250       info->use_password   = p->Recv_bool  ();
00251       info->clients_max    = p->Recv_uint8 ();
00252       info->clients_on     = p->Recv_uint8 ();
00253       info->spectators_on  = p->Recv_uint8 ();
00254       if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
00255         info->game_date    = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
00256         info->start_date   = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
00257       }
00258       p->Recv_string(info->map_name, sizeof(info->map_name));
00259       info->map_width      = p->Recv_uint16();
00260       info->map_height     = p->Recv_uint16();
00261       info->map_set        = p->Recv_uint8 ();
00262       info->dedicated      = p->Recv_bool  ();
00263 
00264       if (info->server_lang >= NETWORK_NUM_LANGUAGES)  info->server_lang = 0;
00265       if (info->map_set     >= NETWORK_NUM_LANDSCAPES) info->map_set     = 0;
00266   }
00267 }
00268 
00273 #define UDP_COMMAND(type) case type: this->NetworkPacketReceive_ ## type ## _command(p, client_addr); break;
00274 
00280 void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, const struct sockaddr_in *client_addr)
00281 {
00282   PacketUDPType type;
00283 
00284   /* New packet == new client, which has not quit yet */
00285   this->has_quit = false;
00286 
00287   type = (PacketUDPType)p->Recv_uint8();
00288 
00289   switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
00290     UDP_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER);
00291     UDP_COMMAND(PACKET_UDP_SERVER_RESPONSE);
00292     UDP_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO);
00293     UDP_COMMAND(PACKET_UDP_SERVER_DETAIL_INFO);
00294     UDP_COMMAND(PACKET_UDP_SERVER_REGISTER);
00295     UDP_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER);
00296     UDP_COMMAND(PACKET_UDP_CLIENT_GET_LIST);
00297     UDP_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST);
00298     UDP_COMMAND(PACKET_UDP_SERVER_UNREGISTER);
00299     UDP_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS);
00300     UDP_COMMAND(PACKET_UDP_SERVER_NEWGRFS);
00301 
00302     default:
00303       if (this->HasClientQuit()) {
00304         DEBUG(net, 0, "[udp] received invalid packet type %d from %s:%d", type,  inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
00305       } else {
00306         DEBUG(net, 0, "[udp] received illegal packet from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
00307       }
00308       break;
00309   }
00310 }
00311 
00318 #define DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(type) \
00319 void NetworkUDPSocketHandler::NetworkPacketReceive_## type ##_command(\
00320     Packet *p, const struct sockaddr_in *client_addr) { \
00321   DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s:%d", \
00322       type, inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port)); \
00323 }
00324 
00325 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER);
00326 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE);
00327 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO);
00328 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_DETAIL_INFO);
00329 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_REGISTER);
00330 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER);
00331 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_LIST);
00332 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST);
00333 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_UNREGISTER);
00334 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS);
00335 DEFINE_UNAVAILABLE_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS);
00336 
00337 #endif /* ENABLE_NETWORK */

Generated on Sun Sep 13 08:19:16 2009 for OpenTTD by  doxygen 1.5.6