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_main.c
21
22#include "quakedef.h"
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <netdb.h>
28#include <sys/param.h>
29#include <sys/ioctl.h>
30#include <sys/uio.h>
31#include <arpa/inet.h>
32#include <errno.h>
33
34#if defined(sun)
35#include <unistd.h>
36#endif
37
38#ifdef sun
39#include <sys/filio.h>
40#endif
41
42#ifdef NeXT
43#include <libc.h>
44#endif
45
46netadr_t	net_local_adr;
47
48netadr_t	net_from;
49sizebuf_t	net_message;
50int			net_socket;			// non blocking, for receives
51int			net_send_socket;	// blocking, for sends
52
53#define	MAX_UDP_PACKET	8192
54byte		net_message_buffer[MAX_UDP_PACKET];
55
56// int gethostname (char *, int);
57int close (int);
58
59//=============================================================================
60
61void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s)
62{
63	memset (s, 0, sizeof(*s));
64	s->sin_family = AF_INET;
65
66	*(int *)&s->sin_addr = *(int *)&a->ip;
67	s->sin_port = a->port;
68}
69
70void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a)
71{
72	*(int *)&a->ip = *(int *)&s->sin_addr;
73	a->port = s->sin_port;
74}
75
76qboolean	NET_CompareBaseAdr (netadr_t a, netadr_t b)
77{
78	if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
79		return true;
80	return false;
81}
82
83
84qboolean	NET_CompareAdr (netadr_t a, netadr_t b)
85{
86	if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
87		return true;
88	return false;
89}
90
91char	*NET_AdrToString (netadr_t a)
92{
93	static	char	s[64];
94
95	sprintf (s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
96
97	return s;
98}
99
100char	*NET_BaseAdrToString (netadr_t a)
101{
102	static	char	s[64];
103
104	sprintf (s, "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
105
106	return s;
107}
108
109/*
110=============
111NET_StringToAdr
112
113idnewt
114idnewt:28000
115192.246.40.70
116192.246.40.70:28000
117=============
118*/
119qboolean	NET_StringToAdr (char *s, netadr_t *a)
120{
121	struct hostent	*h;
122	struct sockaddr_in sadr;
123	char	*colon;
124	char	copy[128];
125
126
127	memset (&sadr, 0, sizeof(sadr));
128	sadr.sin_family = AF_INET;
129
130	sadr.sin_port = 0;
131
132	strcpy (copy, s);
133	// strip off a trailing :port if present
134	for (colon = copy ; *colon ; colon++)
135		if (*colon == ':')
136		{
137			*colon = 0;
138			sadr.sin_port = htons(atoi(colon+1));
139		}
140
141	if (copy[0] >= '0' && copy[0] <= '9')
142	{
143		*(int *)&sadr.sin_addr = inet_addr(copy);
144	}
145	else
146	{
147		if (! (h = gethostbyname(copy)) )
148			return 0;
149		*(int *)&sadr.sin_addr = *(int *)h->h_addr_list[0];
150	}
151
152	SockadrToNetadr (&sadr, a);
153
154	return true;
155}
156
157// Returns true if we can't bind the address locally--in other words,
158// the IP is NOT one of our interfaces.
159qboolean NET_IsClientLegal(netadr_t *adr)
160{
161	struct sockaddr_in sadr;
162	int newsocket;
163
164#if 0
165	if (adr->ip[0] == 127)
166		return false; // no local connections period
167
168	NetadrToSockadr (adr, &sadr);
169
170	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
171		Sys_Error ("NET_IsClientLegal: socket:", strerror(errno));
172
173	sadr.sin_port = 0;
174
175	if( bind (newsocket, (void *)&sadr, sizeof(sadr)) == -1)
176	{
177		// It is not a local address
178		close(newsocket);
179		return true;
180	}
181	close(newsocket);
182	return false;
183#else
184	return true;
185#endif
186}
187
188
189//=============================================================================
190
191qboolean NET_GetPacket (void)
192{
193	int 	ret;
194	struct sockaddr_in	from;
195	socklen_t		fromlen;
196
197	fromlen = sizeof(from);
198	ret = recvfrom (net_socket, net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr *)&from, &fromlen);
199	if (ret == -1) {
200		if (errno == EWOULDBLOCK)
201			return false;
202		if (errno == ECONNREFUSED)
203			return false;
204		Sys_Printf ("NET_GetPacket: %s\n", strerror(errno));
205		return false;
206	}
207
208	net_message.cursize = ret;
209	SockadrToNetadr (&from, &net_from);
210
211	return ret;
212}
213
214//=============================================================================
215
216void NET_SendPacket (int length, void *data, netadr_t to)
217{
218	int ret;
219	struct sockaddr_in	addr;
220
221	NetadrToSockadr (&to, &addr);
222
223	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
224	if (ret == -1) {
225		if (errno == EWOULDBLOCK)
226			return;
227		if (errno == ECONNREFUSED)
228			return;
229		Sys_Printf ("NET_SendPacket: %s\n", strerror(errno));
230	}
231}
232
233//=============================================================================
234
235int UDP_OpenSocket (int port)
236{
237	int newsocket;
238	struct sockaddr_in address;
239	qboolean _true = true;
240	int i;
241
242	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
243		Sys_Error ("UDP_OpenSocket: socket:", strerror(errno));
244	if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1)
245		Sys_Error ("UDP_OpenSocket: ioctl FIONBIO:", strerror(errno));
246	address.sin_family = AF_INET;
247//ZOID -- check for interface binding option
248	if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc) {
249		address.sin_addr.s_addr = inet_addr(com_argv[i+1]);
250		Con_Printf("Binding to IP Interface Address of %s\n",
251				inet_ntoa(address.sin_addr));
252	} else
253		address.sin_addr.s_addr = INADDR_ANY;
254	if (port == PORT_ANY)
255		address.sin_port = 0;
256	else
257		address.sin_port = htons((short)port);
258	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
259		Sys_Error ("UDP_OpenSocket: bind: %s", strerror(errno));
260
261	return newsocket;
262}
263
264void NET_GetLocalAddress (void)
265{
266	char	buff[MAXHOSTNAMELEN];
267	struct sockaddr_in	address;
268	socklen_t namelen;
269
270	gethostname(buff, MAXHOSTNAMELEN);
271	buff[MAXHOSTNAMELEN-1] = 0;
272
273	NET_StringToAdr (buff, &net_local_adr);
274
275	namelen = sizeof(address);
276	if (getsockname (net_socket, (struct sockaddr *)&address, &namelen) == -1)
277		Sys_Error ("NET_Init: getsockname:", strerror(errno));
278	net_local_adr.port = address.sin_port;
279
280	Con_Printf("IP address %s\n", NET_AdrToString (net_local_adr) );
281}
282
283/*
284====================
285NET_Init
286====================
287*/
288void NET_Init (int port)
289{
290	//
291	// open the single socket to be used for all communications
292	//
293	net_socket = UDP_OpenSocket (port);
294
295	//
296	// init the message buffer
297	//
298	net_message.maxsize = sizeof(net_message_buffer);
299	net_message.data = net_message_buffer;
300
301	//
302	// determine my name & address
303	//
304	NET_GetLocalAddress ();
305
306	Con_Printf("UDP Initialized\n");
307}
308
309/*
310====================
311NET_Shutdown
312====================
313*/
314void	NET_Shutdown (void)
315{
316	close (net_socket);
317}
318
319