vertex arrays renamed to varray_ and exposed to rest of engine
[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 static qbyte packetBuffer[NET_DATAGRAMSIZE + 4];
234
235 int WIPX_Read (int handle, qbyte *buf, int len, struct qsockaddr *addr)
236 {
237         int addrlen = sizeof (struct qsockaddr);
238         int socket = ipxsocket[handle];
239         int ret;
240         int errno;
241
242         ret = precvfrom (socket, packetBuffer, len+4, 0, (struct sockaddr *)addr, &addrlen);
243         if (ret == -1)
244         {
245                 errno = pWSAGetLastError();
246
247                 if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
248                         return 0;
249
250         }
251
252         if (ret < 4)
253                 return 0;
254         
255         // remove sequence number, it's only needed for DOS IPX
256         ret -= 4;
257         memcpy(buf, packetBuffer+4, ret);
258
259         return ret;
260 }
261
262 //=============================================================================
263
264 int WIPX_Broadcast (int handle, qbyte *buf, int len)
265 {
266         return WIPX_Write (handle, buf, len, &broadcastaddr);
267 }
268
269 //=============================================================================
270
271 int WIPX_Write (int handle, qbyte *buf, int len, struct qsockaddr *addr)
272 {
273         int socket = ipxsocket[handle];
274         int ret;
275
276         // build packet with sequence number
277         *(int *)(&packetBuffer[0]) = sequence[handle];
278         sequence[handle]++;
279         memcpy(&packetBuffer[4], buf, len);
280         len += 4;
281
282         ret = psendto (socket, packetBuffer, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
283         if (ret == -1)
284                 if (pWSAGetLastError() == WSAEWOULDBLOCK)
285                         return 0;
286
287         return ret;
288 }
289
290 //=============================================================================
291
292 char *WIPX_AddrToString (struct qsockaddr *addr)
293 {
294         static char buf[28];
295
296         sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
297                 ((struct sockaddr_ipx *)addr)->sa_netnum[0] & 0xff,
298                 ((struct sockaddr_ipx *)addr)->sa_netnum[1] & 0xff,
299                 ((struct sockaddr_ipx *)addr)->sa_netnum[2] & 0xff,
300                 ((struct sockaddr_ipx *)addr)->sa_netnum[3] & 0xff,
301                 ((struct sockaddr_ipx *)addr)->sa_nodenum[0] & 0xff,
302                 ((struct sockaddr_ipx *)addr)->sa_nodenum[1] & 0xff,
303                 ((struct sockaddr_ipx *)addr)->sa_nodenum[2] & 0xff,
304                 ((struct sockaddr_ipx *)addr)->sa_nodenum[3] & 0xff,
305                 ((struct sockaddr_ipx *)addr)->sa_nodenum[4] & 0xff,
306                 ((struct sockaddr_ipx *)addr)->sa_nodenum[5] & 0xff,
307                 ntohs(((struct sockaddr_ipx *)addr)->sa_socket)
308                 );
309         return buf;
310 }
311
312 //=============================================================================
313
314 int WIPX_StringToAddr (char *string, struct qsockaddr *addr)
315 {
316         int  val;
317         char buf[3];
318
319         buf[2] = 0;
320         memset(addr, 0, sizeof(struct qsockaddr));
321         addr->sa_family = AF_IPX;
322
323 #define DO(src,dest)    \
324         buf[0] = string[src];   \
325         buf[1] = string[src + 1];       \
326         if (sscanf (buf, "%x", &val) != 1)      \
327                 return -1;      \
328         ((struct sockaddr_ipx *)addr)->dest = val
329
330         DO(0, sa_netnum[0]);
331         DO(2, sa_netnum[1]);
332         DO(4, sa_netnum[2]);
333         DO(6, sa_netnum[3]);
334         DO(9, sa_nodenum[0]);
335         DO(11, sa_nodenum[1]);
336         DO(13, sa_nodenum[2]);
337         DO(15, sa_nodenum[3]);
338         DO(17, sa_nodenum[4]);
339         DO(19, sa_nodenum[5]);
340 #undef DO
341
342         sscanf (&string[22], "%u", &val);
343         ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)val);
344
345         return 0;
346 }
347
348 //=============================================================================
349
350 int WIPX_GetSocketAddr (int handle, struct qsockaddr *addr)
351 {
352         int errno;
353         int socket = ipxsocket[handle];
354         int addrlen = sizeof(struct qsockaddr);
355
356         memset(addr, 0, sizeof(struct qsockaddr));
357         if(pgetsockname(socket, (struct sockaddr *)addr, &addrlen) != 0)
358         {
359                 errno = pWSAGetLastError();
360         }
361
362         return 0;
363 }
364
365 //=============================================================================
366
367 int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
368 {
369         strcpy(name, WIPX_AddrToString(addr));
370         return 0;
371 }
372
373 //=============================================================================
374
375 int WIPX_GetAddrFromName(char *name, struct qsockaddr *addr)
376 {
377         int n;
378         char buf[32];
379
380         n = strlen(name);
381
382         if (n == 12)
383         {
384                 sprintf(buf, "00000000:%s:%u", name, net_hostport);
385                 return WIPX_StringToAddr (buf, addr);
386         }
387         if (n == 21)
388         {
389                 sprintf(buf, "%s:%u", name, net_hostport);
390                 return WIPX_StringToAddr (buf, addr);
391         }
392         if (n > 21 && n <= 27)
393                 return WIPX_StringToAddr (name, addr);
394
395         return -1;
396 }
397
398 //=============================================================================
399
400 int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
401 {
402         if (addr1->sa_family != addr2->sa_family)
403                 return -1;
404
405         if (*((struct sockaddr_ipx *)addr1)->sa_netnum && *((struct sockaddr_ipx *)addr2)->sa_netnum)
406                 if (memcmp(((struct sockaddr_ipx *)addr1)->sa_netnum, ((struct sockaddr_ipx *)addr2)->sa_netnum, 4) != 0)
407                         return -1;
408         if (memcmp(((struct sockaddr_ipx *)addr1)->sa_nodenum, ((struct sockaddr_ipx *)addr2)->sa_nodenum, 6) != 0)
409                 return -1;
410
411         if (((struct sockaddr_ipx *)addr1)->sa_socket != ((struct sockaddr_ipx *)addr2)->sa_socket)
412                 return 1;
413
414         return 0;
415 }
416
417 //=============================================================================
418
419 int WIPX_GetSocketPort (struct qsockaddr *addr)
420 {
421         return ntohs(((struct sockaddr_ipx *)addr)->sa_socket);
422 }
423
424
425 int WIPX_SetSocketPort (struct qsockaddr *addr, int port)
426 {
427         ((struct sockaddr_ipx *)addr)->sa_socket = htons((unsigned short)port);
428         return 0;
429 }
430