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