most of Q2's keyboard handling ported over - what this means: keypad is now separatel...
[divverent/darkplaces.git] / net_wipx.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // net_wipx.c
21
22 #include "quakedef.h"
23 #include "winquake.h"
24 #include <wsipx.h>
25 #include "net_wipx.h"
26
27 #define MAXHOSTNAMELEN          256
28
29 static int net_acceptsocket = -1;               // socket for fielding new connections
30 static int net_controlsocket;
31 static struct qsockaddr broadcastaddr;
32
33 extern qboolean winsock_initialized;
34 extern WSADATA          winsockdata;
35
36 #define IPXSOCKETS 18
37 static int ipxsocket[IPXSOCKETS];
38 static int sequence[IPXSOCKETS];
39
40 //=============================================================================
41
42 int WIPX_Init (void)
43 {
44         int             i;
45         char    buff[MAXHOSTNAMELEN];
46         struct qsockaddr addr;
47         char    *p;
48         int             r;
49         WORD    wVersionRequested; 
50
51         if (!COM_CheckParm ("-ipx")) // LordHavoc: changed -noipx to -ipx at Dabb's request, apparently crashs on computers without MS clients installed
52                 return -1;
53
54 // make sure LoadLibrary has happened successfully
55         if (!winsock_lib_initialized)
56                 return -1;
57
58         if (winsock_initialized == 0)
59         {
60                 wVersionRequested = MAKEWORD(1, 1); 
61
62                 r = pWSAStartup (MAKEWORD(1, 1), &winsockdata);
63
64                 if (r)
65                 {
66                         Con_Printf ("Winsock initialization failed.\n");
67                         return -1;
68                 }
69         }
70         winsock_initialized++;
71
72         for (i = 0; i < IPXSOCKETS; i++)
73                 ipxsocket[i] = 0;
74
75         // determine my name & address
76         if (pgethostname(buff, MAXHOSTNAMELEN) == 0)
77         {
78                 // if the quake hostname isn't set, set it to the machine name
79                 if (strcmp(hostname.string, "UNNAMED") == 0)
80                 {
81                         // see if it's a text IP address (well, close enough)
82                         for (p = buff; *p; p++)
83                                 if ((*p < '0' || *p > '9') && *p != '.')
84                                         break;
85
86                         // if it is a real name, strip off the domain; we only want the host
87                         if (*p)
88                         {
89                                 for (i = 0; i < 15; i++)
90                                         if (buff[i] == '.')
91                                                 break;
92                                 buff[i] = 0;
93                         }
94                         Cvar_Set ("hostname", buff);
95                 }
96         }
97
98         if ((net_controlsocket = WIPX_OpenSocket (0)) == -1)
99         {
100                 Con_Printf("WIPX_Init: Unable to open control socket\n");
101                 if (--winsock_initialized == 0)
102                         pWSACleanup ();
103                 return -1;
104         }
105
106         ((struct sockaddr_ipx *)&broadcastaddr)->sa_family = AF_IPX;
107         memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_netnum, 0, 4);
108         memset(((struct sockaddr_ipx *)&broadcastaddr)->sa_nodenum, 0xff, 6);
109         ((struct sockaddr_ipx *)&broadcastaddr)->sa_socket = htons((unsigned short)net_hostport);
110
111         WIPX_GetSocketAddr (net_controlsocket, &addr);
112         strcpy(my_ipx_address,  WIPX_AddrToString (&addr));
113         p = strrchr (my_ipx_address, ':');
114         if (p)
115                 *p = 0;
116
117         Con_Printf("Winsock IPX Initialized\n");
118         ipxAvailable = true;
119
120         return net_controlsocket;
121 }
122
123 //=============================================================================
124
125 void WIPX_Shutdown (void)
126 {
127         WIPX_Listen (false);
128         WIPX_CloseSocket (net_controlsocket);
129         if (--winsock_initialized == 0)
130                 pWSACleanup ();
131 }
132
133 //=============================================================================
134
135 void WIPX_Listen (qboolean state)
136 {
137         // enable listening
138         if (state)
139         {
140                 if (net_acceptsocket != -1)
141                         return;
142                 if ((net_acceptsocket = WIPX_OpenSocket (net_hostport)) == -1)
143                         Sys_Error ("WIPX_Listen: Unable to open accept socket\n");
144                 return;
145         }
146
147         // disable listening
148         if (net_acceptsocket == -1)
149                 return;
150         WIPX_CloseSocket (net_acceptsocket);
151         net_acceptsocket = -1;
152 }
153
154 //=============================================================================
155
156 int WIPX_OpenSocket (int port)
157 {
158         int handle;
159         int newsocket;
160         struct sockaddr_ipx address;
161         u_long _true = 1;
162
163         for (handle = 0; handle < IPXSOCKETS; handle++)
164                 if (ipxsocket[handle] == 0)
165                         break;
166         if (handle == IPXSOCKETS)
167                 return -1;
168
169         if ((newsocket = psocket (AF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET)
170                 return -1;
171
172         if (pioctlsocket (newsocket, FIONBIO, &_true) == -1)
173                 goto ErrorReturn;
174
175         if (psetsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) < 0)
176                 goto ErrorReturn;
177
178         address.sa_family = AF_IPX;
179         memset(address.sa_netnum, 0, 4);
180         memset(address.sa_nodenum, 0, 6);;
181         address.sa_socket = htons((unsigned short)port);
182         if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
183         {
184                 ipxsocket[handle] = newsocket;
185                 sequence[handle] = 0;
186                 return handle;
187         }
188
189         Sys_Error ("Winsock IPX bind failed\n");
190 ErrorReturn:
191         pclosesocket (newsocket);
192         return -1;
193 }
194
195 //=============================================================================
196
197 int WIPX_CloseSocket (int handle)
198 {
199         int socket = ipxsocket[handle];
200         int ret;
201
202         ret =  pclosesocket (socket);
203         ipxsocket[handle] = 0;
204         return ret;
205 }
206
207
208 //=============================================================================
209
210 int WIPX_Connect (int handle, struct qsockaddr *addr)
211 {
212         return 0;
213 }
214
215 //=============================================================================
216
217 int WIPX_CheckNewConnections (void)
218 {
219         unsigned long   available;
220
221         if (net_acceptsocket == -1)
222                 return -1;
223
224         if (pioctlsocket (ipxsocket[net_acceptsocket], FIONREAD, &available) == -1)
225                 Sys_Error ("WIPX: ioctlsocket (FIONREAD) failed\n");
226         if (available)
227                 return net_acceptsocket;
228         return -1;
229 }
230
231 //=============================================================================
232
233 int WIPX_Recv (qbyte *buf, int len, struct qsockaddr *addr)
234 {
235         return WIPX_Read (net_acceptsocket, buf, len, addr);
236 }
237
238 //=============================================================================
239
240 int WIPX_Send (qbyte *buf, int len, struct qsockaddr *addr)
241 {
242         return WIPX_Write (net_acceptsocket, buf, len, addr);
243 }
244
245 //=============================================================================
246
247 static qbyte packetBuffer[NET_DATAGRAMSIZE + 4];
248
249 int WIPX_Read (int handle, qbyte *buf, int len, struct qsockaddr *addr)
250 {
251         int addrlen = sizeof (struct qsockaddr);
252         int socket = ipxsocket[handle];
253         int ret;
254         int errno;
255
256         ret = precvfrom (socket, packetBuffer, len+4, 0, (struct sockaddr *)addr, &addrlen);
257         if (ret == -1)
258         {
259                 errno = pWSAGetLastError();
260
261                 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
262                         return 0;
263
264         }
265
266         if (ret < 4)
267                 return 0;
268         
269         // remove sequence number, it's only needed for DOS IPX
270         ret -= 4;
271         memcpy(buf, packetBuffer+4, ret);
272
273         return ret;
274 }
275
276 //=============================================================================
277
278 int WIPX_Broadcast (int handle, qbyte *buf, int len)
279 {
280         return WIPX_Write (handle, buf, len, &broadcastaddr);
281 }
282
283 //=============================================================================
284
285 int WIPX_Write (int handle, qbyte *buf, int len, struct qsockaddr *addr)
286 {
287         int socket = ipxsocket[handle];
288         int ret;
289
290         // build packet with sequence number
291         *(int *)(&packetBuffer[0]) = sequence[handle];
292         sequence[handle]++;
293         memcpy(&packetBuffer[4], buf, len);
294         len += 4;
295
296         ret = psendto (socket, packetBuffer, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
297         if (ret == -1)
298                 if (pWSAGetLastError() == WSAEWOULDBLOCK)
299                         return 0;
300
301         return ret;
302 }
303
304 //=============================================================================
305
306 char *WIPX_AddrToString (const struct qsockaddr *addr)
307 {
308         static char buf[28];
309
310         sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
311                 ((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff,
312                 ((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff,
313                 ((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff,
314                 ((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff,
315                 ((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff,
316                 ((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff,
317                 ((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff,
318                 ((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff,
319                 ((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff,
320                 ((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff,
321                 ntohs(((struct sockaddr_ipx *)addr)->sa_socket)
322                 );
323         return buf;
324 }
325
326 //=============================================================================
327
328 int WIPX_StringToAddr (const char *string, struct qsockaddr *addr)
329 {
330         int  val;
331         char buf[3];
332
333         buf[2] = 0;
334         memset(addr, 0, sizeof(struct qsockaddr));
335         addr->sa_family = AF_IPX;
336
337 #define DO(src,dest)    \
338         buf[0] = string[src];   \
339         buf[1] = string[src + 1];       \
340         if (sscanf (buf, "%x", &val) != 1)      \
341                 return -1;      \
342         ((struct sockaddr_ipx *)addr)->dest = val
343
344         DO(0, sa_netnum[0]);
345         DO(2, sa_netnum[1]);
346         DO(4, sa_netnum[2]);
347         DO(6, sa_netnum[3]);
348         DO(9, sa_nodenum[0]);
349         DO(11, sa_nodenum[1]);
350         DO(13, sa_nodenum[2]);
351         DO(15, sa_nodenum[3]);
352         DO(17, sa_nodenum[4]);
353         DO(19, sa_nodenum[5]);
354 #undef DO
355
356         sscanf (&string[22], "%u", &val);
357         ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val);
358
359         return 0;
360 }
361
362 //=============================================================================
363
364 int WIPX_GetSocketAddr (int handle, struct qsockaddr *addr)
365 {
366         int errno;
367         int socket = ipxsocket[handle];
368         int addrlen = sizeof(struct qsockaddr);
369
370         memset(addr, 0, sizeof(struct qsockaddr));
371         if(pgetsockname(socket, (struct sockaddr *)addr, &addrlen) != 0)
372         {
373                 errno = pWSAGetLastError();
374         }
375
376         return 0;
377 }
378
379 //=============================================================================
380
381 int WIPX_GetNameFromAddr (const struct qsockaddr *addr, char *name)
382 {
383         strcpy(name, WIPX_AddrToString(addr));
384         return 0;
385 }
386
387 //=============================================================================
388
389 int WIPX_GetAddrFromName(const char *name, struct qsockaddr *addr)
390 {
391         int n;
392         char buf[32];
393
394         n = strlen(name);
395
396         if (n == 12)
397         {
398                 sprintf(buf, "00000000:%s:%u", name, net_hostport);
399                 return WIPX_StringToAddr (buf, addr);
400         }
401         if (n == 21)
402         {
403                 sprintf(buf, "%s:%u", name, net_hostport);
404                 return WIPX_StringToAddr (buf, addr);
405         }
406         if (n > 21 && n <= 27)
407                 return WIPX_StringToAddr (name, addr);
408
409         return -1;
410 }
411
412 //=============================================================================
413
414 int WIPX_AddrCompare (const struct qsockaddr *addr1, const struct qsockaddr *addr2)
415 {
416         if (addr1->sa_family != addr2->sa_family)
417                 return -1;
418
419         if (*((struct sockaddr_ipx *)addr1)->sa_netnum && *((struct sockaddr_ipx *)addr2)->sa_netnum)
420                 if (memcmp(((struct sockaddr_ipx *)addr1)->sa_netnum, ((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0)
421                         return -1;
422         if (memcmp(((struct sockaddr_ipx *)addr1)->sa_nodenum, ((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0)
423                 return -1;
424
425         if (((struct sockaddr_ipx *)addr1)->sa_socket != ((struct sockaddr_ipx *)addr2)->sa_socket)
426                 return 1;
427
428         return 0;
429 }
430
431 //=============================================================================
432
433 int WIPX_GetSocketPort (struct qsockaddr *addr)
434 {
435         return ntohs(((struct sockaddr_ipx *)addr)->sa_socket);
436 }
437
438
439 int WIPX_SetSocketPort (struct qsockaddr *addr, int port)
440 {
441         ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port);
442         return 0;
443 }
444