1 // net_wins.c
2 
3 #include "../qcommon/qcommon.h"
4 
5 #include <unistd.h>
6 #include <sys/socket.h>
7 #include <sys/time.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <netdb.h>
11 #include <sys/param.h>
12 #include <sys/ioctl.h>
13 #include <sys/uio.h>
14 #include <errno.h>
15 
16 #ifdef __linux__
17 #include <linux/types.h>
18 #include <linux/errqueue.h>
19 #else
20 #include <sys/types.h>
21 #endif
22 
23 #ifdef NeXT
24 #include <libc.h>
25 #endif
26 
27 static unsigned int net_inittime;
28 
29 static unsigned long long net_total_in;
30 static unsigned long long net_total_out;
31 static unsigned long long net_packets_in;
32 static unsigned long long net_packets_out;
33 
34 int			server_port;
35 //netadr_t	net_local_adr;
36 
37 static int			ip_sockets[2];
38 
39 char *NET_ErrorString (void);
40 
41 cvar_t	*net_no_recverr;
42 
43 //Aiee...
44 #include "../qcommon/net_common.c"
45 
46 /*
47 =============
48 NET_StringToAdr
49 
50 localhost
51 idnewt
52 idnewt:28000
53 192.246.40.70
54 192.246.40.70:28000
55 =============
56 */
57 /*qboolean	NET_StringToSockaddr (char *s, struct sockaddr *sadr)
58 {
59 	int		isip = 0;
60 	char	*p;
61 	struct hostent	*h;
62 	char	*colon;
63 	char	copy[128];
64 
65 	memset (sadr, 0, sizeof(*sadr));
66 
67 	//r1: better than just the first digit for ip validity :)
68 	p = s;
69 	while (*p) {
70 		if (*p == '.') {
71 			isip++;
72 		} else if (*p == ':') {
73 			break;
74 		} else if (!isdigit(*p)) {
75 			isip = 0;
76 			break;
77 		}
78 		p++;
79 	}
80 
81 	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
82 	((struct sockaddr_in *)sadr)->sin_port = 0;
83 
84 	strncpy (copy, s, sizeof(copy)-1);
85 
86 	// strip off a trailing :port if present
87 	for (colon = copy ; *colon ; colon++)
88 		if (*colon == ':')
89 		{
90 			*colon = 0;
91 			((struct sockaddr_in *)sadr)->sin_port = htons((int16)atoi(colon+1));
92 		}
93 
94 	if (isip)
95 	{
96 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
97 	}
98 	else
99 	{
100 		if (! (h = gethostbyname(copy)) )
101 			return 0;
102 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
103 	}
104 
105 	return true;
106 }*/
107 
108 /*
109 =============
110 NET_StringToAdr
111 
112 localhost
113 idnewt
114 idnewt:28000
115 192.246.40.70
116 192.246.40.70:28000
117 =============
118 */
119 /*qboolean	NET_StringToAdr (char *s, netadr_t *a)
120 {
121 	struct sockaddr_in sadr;
122 
123 	if (!strcmp (s, "localhost"))
124 	{
125 		memset (a, 0, sizeof(*a));
126 		a->type = NA_LOOPBACK;
127 		return true;
128 	}
129 
130 	if (!NET_StringToSockaddr (s, (struct sockaddr *)&sadr))
131 		return false;
132 
133 	SockadrToNetadr (&sadr, a);
134 
135 	return true;
136 }*/
137 
Net_Stats_f(void)138 void Net_Stats_f (void)
139 {
140 	int now = time(0);
141 	int diff = now - net_inittime;
142 
143 	Com_Printf ("Network up for %i seconds.\n"
144 				"%llu bytes in %llu packets received (av: %i kbps)\n"
145 				"%llu bytes in %llu packets sent (av: %i kbps)\n", LOG_NET,
146 
147 				diff,
148 				net_total_in, net_packets_in, (int)(((net_total_in * 8) / 1024) / diff),
149 				net_total_out, net_packets_out, (int)((net_total_out * 8) / 1024) / diff);
150 }
151 
152 /*
153 =============================================================================
154 
155 LOOPBACK BUFFERS FOR LOCAL PLAYER
156 
157 =============================================================================
158 */
159 
160 
161 //=============================================================================
162 
163 struct probehdr
164 {
165 	uint32_t ttl;
166 	struct timeval tv;
167 };
168 
NET_GetPacket(netsrc_t sock,netadr_t * net_from,sizebuf_t * net_message)169 int	NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
170 {
171 	int 	ret;
172 	struct sockaddr_in	from;
173 	uint32	fromlen;
174 	int		net_socket;
175 	int		err;
176 
177 #ifndef DEDICATED_ONLY
178 	if (NET_GetLoopPacket (sock, net_from, net_message))
179 		return 1;
180 #endif
181 
182 	net_socket = ip_sockets[sock];
183 
184 	if (!net_socket)
185 		return 0;
186 
187 	fromlen = sizeof(from);
188 
189 	ret = recvfrom (net_socket, net_message->data, net_message->maxsize
190 		, 0, (struct sockaddr *)&from, &fromlen);
191 
192 	if (ret == -1)
193 	{
194 #ifdef __linux__
195 		//linux makes this needlessly complex, couldn't just return the source of the error in from, oh no...
196 		struct probehdr	rcvbuf;
197 		struct iovec	iov;
198 		struct msghdr	msg;
199 		struct cmsghdr	*cmsg;
200 
201 		char		cbuf[1024];
202 
203 		struct sock_extended_err *e;
204 
205 		err = errno;
206 
207 		memset (&rcvbuf, 0, sizeof(rcvbuf));
208 
209 		iov.iov_base = &rcvbuf;
210 		iov.iov_len = sizeof (rcvbuf);
211 
212 		memset (&from, 0, sizeof(from));
213 
214 		msg.msg_name = (void *)&from;
215 		msg.msg_namelen = sizeof (from);
216 		msg.msg_iov = &iov;
217 		msg.msg_iovlen = 1;
218 		msg.msg_flags = 0;
219 		msg.msg_control = cbuf;
220 		msg.msg_controllen = sizeof (cbuf);
221 
222 		for (;;)
223 		{
224 			ret = recvmsg (net_socket, &msg, MSG_ERRQUEUE);
225 			if (ret == -1)
226 			{
227 				if (errno == EWOULDBLOCK || errno == EAGAIN)
228 				{
229 					if (err == EWOULDBLOCK || err == EAGAIN)
230 					{
231 						return 0;
232 					}
233 					else
234 					{
235 						errno = err;
236 						Com_Printf ("NET_GetPacket: %s\n", LOG_NET, NET_ErrorString());
237 						return 0;
238 					}
239 				}
240 				else
241 				{
242 					Com_DPrintf ("NET_GetPacket: recvmsg(): %s\n", NET_ErrorString());
243 					return 0;
244 				}
245 			}
246 			else if (!ret)
247 			{
248 				Com_DPrintf ("NET_GetPacket: recvmsg(): EOF\n");
249 				return 0;
250 			}
251 
252 			errno = err;
253 			Com_DPrintf ("NET_GetPacket: Called recvmsg() for extended error details for %s\n", NET_ErrorString());
254 
255 			//linux 2.2 (maybe others) fails to properly fill in the msg_name structure.
256 			Com_DPrintf ("(msgname) family %d, host: %s, port: %d, flags: %d\n", from.sin_family, inet_ntoa (from.sin_addr), from.sin_port, msg.msg_flags);
257 
258 			e = NULL;
259 
260 			for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
261 			{
262 				if (cmsg->cmsg_level == SOL_IP)
263 				{
264 					if (cmsg->cmsg_type == IP_RECVERR)
265 					{
266 						e = (struct sock_extended_err *) CMSG_DATA (cmsg);
267 					}
268 					else
269 						Com_DPrintf ("cmsg type = %d\n", cmsg->cmsg_type);
270 				}
271 			}
272 
273 			if (!e)
274 			{
275 				Com_DPrintf ("NET_GetPacket: recvmsg(): no extended info available\n");
276 				continue;
277 			}
278 
279 			if (e->ee_origin == SO_EE_ORIGIN_ICMP)
280 			{
281 				//for some unknown reason, the kernel zeroes out the port in SO_EE_OFFENDER, so this is pretty much useless
282 				struct sockaddr_in *sin = (struct sockaddr_in *)SO_EE_OFFENDER(e);
283 				Com_DPrintf ("(ICMP) family %d, host: %s, port: %d\n", sin->sin_family, inet_ntoa (sin->sin_addr), sin->sin_port);
284 
285 				//but better than nothing if using  buggy kernel?
286 				if (from.sin_family == AF_UNSPEC)
287 				{
288 					memcpy (&from, sin, sizeof(from));
289 					//can't trust port, may be buggy kernel (again)
290 					from.sin_port = 0;
291 				}
292 			}
293 			else
294 			{
295 				Com_DPrintf ("NET_GetPacket: recvmsg(): error origin is %d\n", e->ee_origin);
296 				continue;
297 			}
298 
299 			SockadrToNetadr (&from, net_from);
300 
301 			switch (e->ee_errno)
302 			{
303 				case ECONNREFUSED:
304 				case EHOSTUNREACH:
305 				case ENETUNREACH:
306 					Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, strerror(e->ee_errno), NET_AdrToString (net_from));
307 					if (net_ignore_icmp->intvalue)
308 						return 0;
309 					else
310 						return -1;
311 				default:
312 					Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, strerror(e->ee_errno), NET_AdrToString (net_from));
313 					continue;
314 			}
315 		}
316 #else
317 		err = errno;
318 
319 		if (err == EWOULDBLOCK)
320 			return 0;
321 		if (err == ECONNREFUSED)
322 		{
323 			SockadrToNetadr (&from, net_from);
324 			Com_Printf ("NET_GetPacket: %s from %s\n", LOG_NET, NET_ErrorString(), NET_AdrToString (net_from));
325 			return -1;
326 		}
327 		Com_Printf ("NET_GetPacket: %s\n", LOG_NET, NET_ErrorString());
328 #endif
329 		return 0;
330 	}
331 
332 	net_packets_in++;
333 	net_total_in += ret;
334 
335 	SockadrToNetadr (&from, net_from);
336 
337 	if (ret == net_message->maxsize)
338 	{
339 		Com_Printf ("Oversize packet from %s\n", LOG_NET, NET_AdrToString (net_from));
340 		return 0;
341 	}
342 
343 	net_message->cursize = ret;
344 
345 	return 1;
346 }
347 
348 
349 //=============================================================================
350 
NET_SendPacket(netsrc_t sock,int length,const void * data,netadr_t * to)351 int NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t *to)
352 {
353 	int		ret;
354 	struct sockaddr_in	addr;
355 	int		net_socket;
356 
357 	if (to->type == NA_IP)
358 	{
359 		net_socket = ip_sockets[sock];
360 		if (!net_socket)
361 			return 0;
362 	}
363 #ifndef DEDICATED_ONLY
364 	else if ( to->type == NA_LOOPBACK )
365 	{
366 		NET_SendLoopPacket (sock, length, data);
367 		return 1;
368 	}
369 #endif
370 	else if (to->type == NA_BROADCAST)
371 	{
372 		net_socket = ip_sockets[sock];
373 		if (!net_socket)
374 			return 0;
375 	}
376 	else
377 	{
378 		Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
379 		return 0;
380 	}
381 
382 	NetadrToSockadr (to, &addr);
383 
384 	ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) );
385 	if (ret == -1)
386 	{
387 		Com_Printf ("NET_SendPacket to %s: ERROR: %s\n", LOG_NET, NET_AdrToString(to), NET_ErrorString());
388 		return 0;
389 	}
390 
391 	net_packets_out++;
392 	net_total_out += ret;
393 	return 1;
394 }
395 
396 //=============================================================================
397 
398 /*
399 ====================
400 NET_Init
401 ====================
402 */
NET_Init(void)403 void NET_Init (void)
404 {
405 	NET_Common_Init ();
406 	net_no_recverr = Cvar_Get ("net_no_recverr", "0", 0);
407 }
408 
409 
410 /*
411 ====================
412 NET_Socket
413 ====================
414 */
NET_IPSocket(char * net_interface,int port)415 int NET_IPSocket (char *net_interface, int port)
416 {
417 	int newsocket;
418 	struct sockaddr_in address;
419 	qboolean _true = true;
420 	int	i = 1;
421 
422 	if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
423 	{
424 		Com_Printf ("UDP_OpenSocket: Couldn't make socket: %s\n", LOG_NET, NET_ErrorString());
425 		return 0;
426 	}
427 
428 	if (newsocket >= FD_SETSIZE)
429 		Com_Error (ERR_FATAL, "NET_IPSocket: socket is higher than FD_SETSIZE");
430 
431 	// make it non-blocking
432 	if (ioctl (newsocket, FIONBIO, &_true) == -1)
433 	{
434 		Com_Printf ("UDP_OpenSocket: Couldn't make non-blocking: %s\n", LOG_NET, NET_ErrorString());
435 		return 0;
436 	}
437 
438 	// make it broadcast capable
439 	if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
440 	{
441 		Com_Printf ("UDP_OpenSocket: Couldn't set SO_BROADCAST: %s\n", LOG_NET, NET_ErrorString());
442 		return 0;
443 	}
444 
445 #ifdef __linux__
446 	// r1: accept icmp unreachables for quick disconnects
447 	if (!net_no_recverr->intvalue)
448 	{
449 		if (setsockopt (newsocket, IPPROTO_IP, IP_RECVERR, (char *)&i, sizeof(i)) == -1)
450 		{
451 			Com_Printf ("UDP_OpenSocket: Couldn't set IP_RECVERR: %s\n", LOG_NET, NET_ErrorString());
452 		}
453 	}
454 #endif
455 
456 	if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost"))
457 		address.sin_addr.s_addr = INADDR_ANY;
458 	else
459 		NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
460 
461 	if (port == PORT_ANY)
462 		address.sin_port = 0;
463 	else
464 		address.sin_port = htons((uint16)port);
465 
466 	address.sin_family = AF_INET;
467 
468 	if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
469 	{
470 		close (newsocket);
471 		Com_Printf ("UDP_OpenSocket: Couldn't bind to UDP port %d: %s\n", LOG_NET, port, NET_ErrorString());
472 		return 0;
473 	}
474 
475 	return newsocket;
476 }
477 
478 
479 /*
480 ====================
481 NET_Shutdown
482 ====================
483 */
NET_Shutdown(void)484 void	NET_Shutdown (void)
485 {
486 	NET_Config (NET_NONE);	// close sockets
487 }
488 
489 
490 /*
491 ====================
492 NET_ErrorString
493 ====================
494 */
NET_ErrorString(void)495 char *NET_ErrorString (void)
496 {
497 	int		code;
498 
499 	code = errno;
500 	return strerror (code);
501 }
502 
503 
504