1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Low level UDP network interface. This is shared between the server
31 * and client, with SERVER defined for the former to select some extra
32 * functions. Handles socket creation, and packet send and receive.
33 *
34 *-----------------------------------------------------------------------------*/
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39 #ifdef HAVE_NETINET_IN_H
40 # include <netinet/in.h>
41 #endif
42 #include <stdlib.h>
43 #include <errno.h>
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #include <stdio.h>
48 #include <fcntl.h>
49 #include <string.h>
50
51 #ifdef HAVE_NET
52
53 #include "SDL.h"
54 #include "SDL_net.h"
55
56 #include "protocol.h"
57 #include "i_network.h"
58 #include "lprintf.h"
59 //#include "doomstat.h"
60
61 /* cph -
62 * Each client will either use the IPv4 socket or the IPv6 socket
63 * Each server will use whichever or both that are available
64 */
65 UDP_CHANNEL sentfrom;
66 IPaddress sentfrom_addr;
67 UDP_SOCKET udp_socket;
68
69 /* Statistics */
70 size_t sentbytes, recvdbytes;
71
72 UDP_PACKET *udp_packet;
73
74 /* I_ShutdownNetwork
75 *
76 * Shutdown the network code
77 */
I_ShutdownNetwork(void)78 void I_ShutdownNetwork(void)
79 {
80 SDLNet_FreePacket(udp_packet);
81 SDLNet_Quit();
82 }
83
84 /* I_InitNetwork
85 *
86 * Sets up the network code
87 */
I_InitNetwork(void)88 void I_InitNetwork(void)
89 {
90 SDLNet_Init();
91 atexit(I_ShutdownNetwork);
92 udp_packet = SDLNet_AllocPacket(10000);
93 }
94
I_AllocPacket(int size)95 UDP_PACKET *I_AllocPacket(int size)
96 {
97 return(SDLNet_AllocPacket(size));
98 }
99
I_FreePacket(UDP_PACKET * packet)100 void I_FreePacket(UDP_PACKET *packet)
101 {
102 SDLNet_FreePacket(packet);
103 }
104
105
106 /* cph - I_WaitForPacket - use select(2) via SDL_net's interface
107 * No more I_uSleep loop kludge */
108
I_WaitForPacket(int ms)109 void I_WaitForPacket(int ms)
110 {
111 SDLNet_SocketSet ss = SDLNet_AllocSocketSet(1);
112 SDLNet_UDP_AddSocket(ss, udp_socket);
113 SDLNet_CheckSockets(ss,ms);
114 SDLNet_FreeSocketSet(ss);
115 // build script doesn't allow this
116 //#if (defined _WIN32 && !defined PRBOOM_SERVER)
117 // I_UpdateConsole();
118 //#endif
119 }
120
121 /* I_ConnectToServer
122 *
123 * Connect to a server
124 */
125 IPaddress serverIP;
126
I_ConnectToServer(const char * serv)127 int I_ConnectToServer(const char *serv)
128 {
129 char server[500], *p;
130 Uint16 port;
131
132 /* Split serv into address and port */
133 if (strlen(serv)>500) return 0;
134 strcpy(server,serv);
135 p = strchr(server, ':');
136 if(p)
137 {
138 *p++ = '\0';
139 port = atoi(p);
140 }
141 else
142 port = 5030; /* Default server port */
143
144 SDLNet_ResolveHost(&serverIP, server, port);
145 if ( serverIP.host == INADDR_NONE )
146 return -1;
147
148 if (SDLNet_UDP_Bind(udp_socket, 0, &serverIP) == -1)
149 return -1;
150
151 return 0;
152 }
153
154 /* I_Disconnect
155 *
156 * Disconnect from server
157 */
I_Disconnect(void)158 void I_Disconnect(void)
159 {
160 /* int i;
161 UDP_PACKET *packet;
162 packet_header_t *pdata = (packet_header_t *)packet->data;
163 packet = I_AllocPacket(sizeof(packet_header_t) + 1);
164
165 packet->data[sizeof(packet_header_t)] = consoleplayer;
166 pdata->type = PKT_QUIT; pdata->tic = gametic;
167
168 for (i=0; i<4; i++) {
169 I_SendPacket(packet);
170 I_uSleep(10000);
171 }
172 I_FreePacket(packet);*/
173 SDLNet_UDP_Unbind(udp_socket, 0);
174 }
175
176 /*
177 * I_Socket
178 *
179 * Sets the given socket non-blocking, binds to the given port, or first
180 * available if none is given
181 */
I_Socket(Uint16 port)182 UDP_SOCKET I_Socket(Uint16 port)
183 {
184 if(port)
185 return (SDLNet_UDP_Open(port));
186 else {
187 UDP_SOCKET sock;
188 port = IPPORT_RESERVED;
189 while( (sock = SDLNet_UDP_Open(port)) == NULL )
190 port++;
191 return sock;
192 }
193 }
194
I_CloseSocket(UDP_SOCKET sock)195 void I_CloseSocket(UDP_SOCKET sock)
196 {
197 SDLNet_UDP_Close(sock);
198 }
199
I_RegisterPlayer(IPaddress * ipaddr)200 UDP_CHANNEL I_RegisterPlayer(IPaddress *ipaddr)
201 {
202 static int freechannel;
203 return(SDLNet_UDP_Bind(udp_socket, freechannel++, ipaddr));
204 }
205
I_UnRegisterPlayer(UDP_CHANNEL channel)206 void I_UnRegisterPlayer(UDP_CHANNEL channel)
207 {
208 SDLNet_UDP_Unbind(udp_socket, channel);
209 }
210
211 /*
212 * ChecksumPacket
213 *
214 * Returns the checksum of a given network packet
215 */
ChecksumPacket(const packet_header_t * buffer,size_t len)216 static byte ChecksumPacket(const packet_header_t* buffer, size_t len)
217 {
218 const byte* p = (const void*)buffer;
219 byte sum = 0;
220
221 if (len==0)
222 return 0;
223
224 while (p++, --len)
225 sum += *p;
226
227 return sum;
228 }
229
I_GetPacket(packet_header_t * buffer,size_t buflen)230 size_t I_GetPacket(packet_header_t* buffer, size_t buflen)
231 {
232 int checksum;
233 size_t len;
234 int status;
235
236 status = SDLNet_UDP_Recv(udp_socket, udp_packet);
237 len = udp_packet->len;
238 if (buflen<len)
239 len=buflen;
240 if ( (status!=0) && (len>0) )
241 memcpy(buffer, udp_packet->data, len);
242 sentfrom=udp_packet->channel;
243 #ifndef SDL_NET_UDP_PACKET_SRC
244 sentfrom_addr=udp_packet->address;
245 #else
246 sentfrom_addr=udp_packet->src; /* cph - allow for old SDL_net library */
247 #endif
248 checksum=buffer->checksum;
249 buffer->checksum=0;
250 if ( (status!=0) && (len>0)) {
251 byte psum = ChecksumPacket(buffer, udp_packet->len);
252 /* fprintf(stderr, "recvlen = %u, stolen = %u, csum = %u, psum = %u\n",
253 udp_packet->len, len, checksum, psum); */
254 if (psum == checksum) return len;
255 }
256 return 0;
257 }
258
I_SendPacket(packet_header_t * packet,size_t len)259 void I_SendPacket(packet_header_t* packet, size_t len)
260 {
261 packet->checksum = ChecksumPacket(packet, len);
262 memcpy(udp_packet->data, packet, udp_packet->len = len);
263 SDLNet_UDP_Send(udp_socket, 0, udp_packet);
264 }
265
I_SendPacketTo(packet_header_t * packet,size_t len,UDP_CHANNEL * to)266 void I_SendPacketTo(packet_header_t* packet, size_t len, UDP_CHANNEL *to)
267 {
268 packet->checksum = ChecksumPacket(packet, len);
269 memcpy(udp_packet->data, packet, udp_packet->len = len);
270 SDLNet_UDP_Send(udp_socket, *to, udp_packet);
271 }
272
I_PrintAddress(FILE * fp,UDP_CHANNEL * addr)273 void I_PrintAddress(FILE* fp, UDP_CHANNEL *addr)
274 {
275 /*
276 char *addy;
277 Uint16 port;
278 IPaddress *address;
279
280 address = SDLNet_UDP_GetPeerAddress(udp_socket, player);
281
282 //FIXME: if it cant resolv it may freeze up
283 addy = SDLNet_ResolveIP(address);
284 port = address->port;
285
286 if(addy != NULL)
287 fprintf(fp, "%s:%d", addy, port);
288 else
289 fprintf(fp, "Error");
290 */
291 }
292
293 #endif /* HAVE_NET */
294