network/core/udp.c
branchcustombridgeheads
changeset 5642 bfa6074e2833
equal deleted inserted replaced
5641:d4d00a16ef26 5642:bfa6074e2833
       
     1 /* $Id$ */
       
     2 
       
     3 #ifdef ENABLE_NETWORK
       
     4 
       
     5 #include "../../stdafx.h"
       
     6 #include "../../date.h"
       
     7 #include "../../debug.h"
       
     8 #include "../../macros.h"
       
     9 #include "../../newgrf_config.h"
       
    10 
       
    11 #include "os_abstraction.h"
       
    12 #include "config.h"
       
    13 #include "game.h"
       
    14 #include "packet.h"
       
    15 #include "udp.h"
       
    16 
       
    17 /**
       
    18  * @file udp.c Basic functions to receive and send UDP packets.
       
    19  */
       
    20 
       
    21 /**
       
    22  * Send a packet over UDP
       
    23  * @param udp  the socket to send over
       
    24  * @param p    the packet to send
       
    25  * @param recv the receiver (target) of the packet
       
    26  */
       
    27 void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv)
       
    28 {
       
    29 	int res;
       
    30 
       
    31 	NetworkSend_FillPacketSize(p);
       
    32 
       
    33 	/* Send the buffer */
       
    34 	res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv));
       
    35 
       
    36 	/* Check for any errors, but ignore it otherwise */
       
    37 	if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR());
       
    38 }
       
    39 
       
    40 /**
       
    41  * Start listening on the given host and port.
       
    42  * @param udp       the place where the (references to the) UDP are stored
       
    43  * @param host      the host (ip) to listen on
       
    44  * @param port      the port to listen on
       
    45  * @param broadcast whether to allow broadcast sending/receiving
       
    46  * @return true if the listening succeeded
       
    47  */
       
    48 bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast)
       
    49 {
       
    50 	struct sockaddr_in sin;
       
    51 
       
    52 	/* Make sure socket is closed */
       
    53 	closesocket(*udp);
       
    54 
       
    55 	*udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
       
    56 	if (*udp == INVALID_SOCKET) {
       
    57 		DEBUG(net, 0, "[udp] failed to start UDP listener");
       
    58 		return false;
       
    59 	}
       
    60 
       
    61 	/* set nonblocking mode for socket */
       
    62 	{
       
    63 		unsigned long blocking = 1;
       
    64 #ifndef BEOS_NET_SERVER
       
    65 		ioctlsocket(*udp, FIONBIO, &blocking);
       
    66 #else
       
    67 		setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL);
       
    68 #endif
       
    69 	}
       
    70 
       
    71 	sin.sin_family = AF_INET;
       
    72 	/* Listen on all IPs */
       
    73 	sin.sin_addr.s_addr = host;
       
    74 	sin.sin_port = htons(port);
       
    75 
       
    76 	if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
       
    77 		DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port);
       
    78 		return false;
       
    79 	}
       
    80 
       
    81 	if (broadcast) {
       
    82 		/* Enable broadcast */
       
    83 		unsigned long val = 1;
       
    84 #ifndef BEOS_NET_SERVER // will work around this, some day; maybe.
       
    85 		setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val));
       
    86 #endif
       
    87 	}
       
    88 
       
    89 	DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port);
       
    90 
       
    91 	return true;
       
    92 }
       
    93 
       
    94 /**
       
    95  * Receive a packet at UDP level
       
    96  * @param udp the socket to receive the packet on
       
    97  */
       
    98 void NetworkUDPReceive(SOCKET udp)
       
    99 {
       
   100 	struct sockaddr_in client_addr;
       
   101 	socklen_t client_len;
       
   102 	int nbytes;
       
   103 	Packet p;
       
   104 	int packet_len;
       
   105 
       
   106 	packet_len = sizeof(p.buffer);
       
   107 	client_len = sizeof(client_addr);
       
   108 
       
   109 	/* Try to receive anything */
       
   110 	nbytes = recvfrom(udp, p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len);
       
   111 
       
   112 	/* We got some bytes for the base header of the packet.
       
   113 	 * Assume we received the whole packet. */
       
   114 	if (nbytes > 2) {
       
   115 		NetworkRecv_ReadPacketSize(&p);
       
   116 
       
   117 		/* Put the position on the right place */
       
   118 		p.pos = 2;
       
   119 		p.next = NULL;
       
   120 
       
   121 		/* Handle the packet */
       
   122 		NetworkHandleUDPPacket(&p, &client_addr);
       
   123 	}
       
   124 }
       
   125 
       
   126 
       
   127 /**
       
   128  * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
       
   129  * @param p the packet to write the data to
       
   130  * @param c the configuration to write the GRF ID and MD5 checksum from
       
   131  */
       
   132 void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c)
       
   133 {
       
   134 	uint j;
       
   135 	NetworkSend_uint32(p, c->grfid);
       
   136 	for (j = 0; j < sizeof(c->md5sum); j++) {
       
   137 		NetworkSend_uint8 (p, c->md5sum[j]);
       
   138 	}
       
   139 }
       
   140 
       
   141 /**
       
   142  * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
       
   143  * @param cs the client state (for closing connect on out-of-bounds reading etc)
       
   144  * @param p  the packet to read the data from
       
   145  * @param c  the configuration to write the GRF ID and MD5 checksum to
       
   146  */
       
   147 void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c)
       
   148 {
       
   149 	uint j;
       
   150 	c->grfid = NetworkRecv_uint32(cs, p);
       
   151 	for (j = 0; j < sizeof(c->md5sum); j++) {
       
   152 		c->md5sum[j] = NetworkRecv_uint8(cs, p);
       
   153 	}
       
   154 }
       
   155 
       
   156 
       
   157 /**
       
   158  * Serializes the NetworkGameInfo struct to the packet
       
   159  * @param p    the packet to write the data to
       
   160  * @param info the NetworkGameInfo struct to serialize
       
   161  */
       
   162 void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info)
       
   163 {
       
   164 	NetworkSend_uint8 (p, NETWORK_GAME_INFO_VERSION);
       
   165 
       
   166 	/*
       
   167 	 *              Please observe the order.
       
   168 	 * The parts must be read in the same order as they are sent!
       
   169 	 */
       
   170 
       
   171 
       
   172 	/* NETWORK_GAME_INFO_VERSION = 4 */
       
   173 	{
       
   174 		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
       
   175 		 * the GRFs that are needed, i.e. the ones that the server has
       
   176 		 * selected in the NewGRF GUI and not the ones that are used due
       
   177 		 * to the fact that they are in [newgrf-static] in openttd.cfg */
       
   178 		const GRFConfig *c;
       
   179 		uint count = 0;
       
   180 
       
   181 		/* Count number of GRFs to send information about */
       
   182 		for (c = info->grfconfig; c != NULL; c = c->next) {
       
   183 			if (!HASBIT(c->flags, GCF_STATIC)) count++;
       
   184 		}
       
   185 		NetworkSend_uint8 (p, count); // Send number of GRFs
       
   186 
       
   187 		/* Send actual GRF Identifications */
       
   188 		for (c = info->grfconfig; c != NULL; c = c->next) {
       
   189 			if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(p, c);
       
   190 		}
       
   191 	}
       
   192 
       
   193 	/* NETWORK_GAME_INFO_VERSION = 3 */
       
   194 	NetworkSend_uint32(p, info->game_date);
       
   195 	NetworkSend_uint32(p, info->start_date);
       
   196 
       
   197 	/* NETWORK_GAME_INFO_VERSION = 2 */
       
   198 	NetworkSend_uint8 (p, info->companies_max);
       
   199 	NetworkSend_uint8 (p, info->companies_on);
       
   200 	NetworkSend_uint8 (p, info->spectators_max);
       
   201 
       
   202 	/* NETWORK_GAME_INFO_VERSION = 1 */
       
   203 	NetworkSend_string(p, info->server_name);
       
   204 	NetworkSend_string(p, info->server_revision);
       
   205 	NetworkSend_uint8 (p, info->server_lang);
       
   206 	NetworkSend_uint8 (p, info->use_password);
       
   207 	NetworkSend_uint8 (p, info->clients_max);
       
   208 	NetworkSend_uint8 (p, info->clients_on);
       
   209 	NetworkSend_uint8 (p, info->spectators_on);
       
   210 	NetworkSend_string(p, info->map_name);
       
   211 	NetworkSend_uint16(p, info->map_width);
       
   212 	NetworkSend_uint16(p, info->map_height);
       
   213 	NetworkSend_uint8 (p, info->map_set);
       
   214 	NetworkSend_uint8 (p, info->dedicated);
       
   215 }
       
   216 
       
   217 /**
       
   218  * Deserializes the NetworkGameInfo struct from the packet
       
   219  * @param cs   the client state (for closing connect on out-of-bounds reading etc)
       
   220  * @param p    the packet to read the data from
       
   221  * @param info the NetworkGameInfo to deserialize into
       
   222  */
       
   223 void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info)
       
   224 {
       
   225 	info->game_info_version = NetworkRecv_uint8(cs, p);
       
   226 
       
   227 	/*
       
   228 	 *              Please observe the order.
       
   229 	 * The parts must be read in the same order as they are sent!
       
   230 	 */
       
   231 
       
   232 	switch (info->game_info_version) {
       
   233 		case 4: {
       
   234 			GRFConfig *c, **dst = &info->grfconfig;
       
   235 			uint i;
       
   236 			uint num_grfs = NetworkRecv_uint8(cs, p);
       
   237 
       
   238 			for (i = 0; i < num_grfs; i++) {
       
   239 				c = calloc(1, sizeof(*c));
       
   240 				NetworkRecv_GRFIdentifier(cs, p, c);
       
   241 				HandleIncomingNetworkGameInfoGRFConfig(c);
       
   242 
       
   243 				/* Append GRFConfig to the list */
       
   244 				*dst = c;
       
   245 				dst = &c->next;
       
   246 			}
       
   247 		} /* Fallthrough */
       
   248 		case 3:
       
   249 			info->game_date      = NetworkRecv_uint32(cs, p);
       
   250 			info->start_date     = NetworkRecv_uint32(cs, p);
       
   251 			/* Fallthrough */
       
   252 		case 2:
       
   253 			info->companies_max  = NetworkRecv_uint8 (cs, p);
       
   254 			info->companies_on   = NetworkRecv_uint8 (cs, p);
       
   255 			info->spectators_max = NetworkRecv_uint8 (cs, p);
       
   256 			/* Fallthrough */
       
   257 		case 1:
       
   258 			NetworkRecv_string(cs, p, info->server_name,     sizeof(info->server_name));
       
   259 			NetworkRecv_string(cs, p, info->server_revision, sizeof(info->server_revision));
       
   260 			info->server_lang    = NetworkRecv_uint8 (cs, p);
       
   261 			info->use_password   = NetworkRecv_uint8 (cs, p);
       
   262 			info->clients_max    = NetworkRecv_uint8 (cs, p);
       
   263 			info->clients_on     = NetworkRecv_uint8 (cs, p);
       
   264 			info->spectators_on  = NetworkRecv_uint8 (cs, p);
       
   265 			if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
       
   266 				info->game_date    = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
       
   267 				info->start_date   = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR;
       
   268 			}
       
   269 			NetworkRecv_string(cs, p, info->map_name, sizeof(info->map_name));
       
   270 			info->map_width      = NetworkRecv_uint16(cs, p);
       
   271 			info->map_height     = NetworkRecv_uint16(cs, p);
       
   272 			info->map_set        = NetworkRecv_uint8 (cs, p);
       
   273 			info->dedicated      = NetworkRecv_uint8 (cs, p);
       
   274 	}
       
   275 }
       
   276 
       
   277 #endif /* ENABLE_NETWORK */