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