1 /*
2 Copyright (C) 1997-2001 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 
21 //
22 // net.c
23 //
24 
25 #include "qcommon.h"
26 #include "net.h"
27 
28 #define	MAX_LOOPBACK	4
29 
30 typedef struct {
31 	byte	data[MAX_PACKETLEN];
32 	int		datalen;
33 } loopmsg_t;
34 
35 typedef struct {
36 	loopmsg_t	msgs[MAX_LOOPBACK];
37 	int			get;
38 	int			send;
39 } loopback_t;
40 
41 static cvar_t	*net_ip;
42 static cvar_t	*net_port;
43 static cvar_t	*net_clientport;
44 static cvar_t	*net_dropsim;
45 static cvar_t	*net_log_active;
46 static cvar_t	*net_log_name;
47 static cvar_t	*net_log_flush;
48 static cvar_t	*net_ignore_icmp;
49 
50 static loopback_t	loopbacks[NS_COUNT];
51 static SOCKET		sockets[NS_COUNT] = { INVALID_SOCKET, INVALID_SOCKET };
52 
53 static fileHandle_t	net_logFile;
54 static netflag_t	net_active;
55 
56 void NET_LogPacket( const netadr_t *address, qboolean send, const byte *data, int dataSize );
57 
58 //=============================================================================
59 
60 /*
61 ===================
62 NET_NetadrToSockadr
63 ===================
64 */
NET_NetadrToSockadr(const netadr_t * a,struct sockaddr * s)65 void NET_NetadrToSockadr( const netadr_t *a, struct sockaddr *s ) {
66 	memset( s, 0, sizeof( *s ) );
67 
68 	switch( a->type ) {
69 	case NA_BROADCAST:
70 		((struct sockaddr_in *)s)->sin_family = AF_INET;
71 		((struct sockaddr_in *)s)->sin_port = a->port;
72 		((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
73 		break;
74 	case NA_IP:
75 		((struct sockaddr_in *)s)->sin_family = AF_INET;
76 		((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
77 		((struct sockaddr_in *)s)->sin_port = a->port;
78 		break;
79 	default:
80 		Com_Error( ERR_FATAL, "NetadrToSockadr: bad address type" );
81 		break;
82 	}
83 }
84 
85 /*
86 ===================
87 NET_SockadrToNetadr
88 ===================
89 */
NET_SockadrToNetadr(const struct sockaddr * s,netadr_t * a)90 void NET_SockadrToNetadr( const struct sockaddr *s, netadr_t *a ) {
91 	memset( a, 0, sizeof( *a ) );
92 
93 	a->type = NA_IP;
94 	*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
95 	a->port = ((struct sockaddr_in *)s)->sin_port;
96 
97 }
98 
99 /*
100 =============
101 NET_StringToSockaddr
102 
103 localhost
104 idnewt
105 idnewt:28000
106 192.246.40.70
107 192.246.40.70:28000
108 =============
109 */
NET_StringToSockaddr(const char * s,struct sockaddr * sadr)110 qboolean NET_StringToSockaddr( const char *s, struct sockaddr *sadr ) {
111 	struct hostent	*h;
112 	char	*colon;
113 	char	copy[MAX_QPATH];
114 
115 	memset( sadr, 0, sizeof( *sadr ) );
116 
117 	((struct sockaddr_in *)sadr)->sin_family = AF_INET;
118 	((struct sockaddr_in *)sadr)->sin_port = 0;
119 
120 	Q_strncpyz( copy, s, sizeof( copy ) );
121 	// strip off a trailing :port if present
122 	for( colon = copy ; *colon ; colon++ )
123 		if( *colon == ':' ) {
124 			*colon = 0;
125 			((struct sockaddr_in *)sadr)->sin_port =
126                 htons( (u_short)atoi( colon + 1 ) );
127 		}
128 
129 	if( copy[0] >= '0' && copy[0] <= '9' ) {
130 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr( copy );
131 	} else {
132 		if( !( h = gethostbyname( copy ) ) )
133 			return qfalse;
134 		*(int *)&((struct sockaddr_in *)sadr)->sin_addr =
135             *(int *)h->h_addr_list[0];
136 	}
137 
138 
139 	return qtrue;
140 }
141 
142 /*
143 ===================
144 NET_IsEqualAdr
145 ===================
146 */
NET_IsEqualAdr(const netadr_t * a,const netadr_t * b)147 qboolean NET_IsEqualAdr( const netadr_t *a, const netadr_t *b ) {
148 	if( a->type != b->type ) {
149 		return qfalse;
150 	}
151 
152 	switch( a->type ) {
153 	case NA_LOOPBACK:
154 		return qtrue;
155 	case NA_IP:
156 	case NA_BROADCAST:
157 		if( *( uint32 * )a->ip == *( uint32 * )b->ip &&
158 			a->port == b->port )
159 		{
160 			return qtrue;
161 		}
162 		return qfalse;
163 	default:
164 		Com_Error( ERR_FATAL, "NET_IsEqualAdr: bad address type: %i", a->type );
165 		break;
166 	}
167 
168 	return qfalse;
169 }
170 
171 /*
172 ===================
173 NET_IsEqualBaseAdr
174 
175 Compares without the port
176 ===================
177 */
NET_IsEqualBaseAdr(const netadr_t * a,const netadr_t * b)178 qboolean NET_IsEqualBaseAdr( const netadr_t *a, const netadr_t *b ) {
179 	if( a->type != b->type ) {
180 		return qfalse;
181 	}
182 
183 	switch( a->type ) {
184 	case NA_LOOPBACK:
185 		return qtrue;
186 	case NA_IP:
187 	case NA_BROADCAST:
188 		if( *( uint32 * )a->ip == *( uint32 * )b->ip ) {
189 			return qtrue;
190 		}
191 		return qfalse;
192 	default:
193 		Com_Error( ERR_FATAL, "NET_IsEqualBaseAdr: bad address type: %i", a->type );
194 		break;
195 	}
196 
197 	return qfalse;
198 }
199 
200 /*
201 ===================
202 NET_IsLANAddress
203 ===================
204 */
NET_IsLANAddress(const netadr_t * adr)205 qboolean NET_IsLANAddress( const netadr_t *adr ) {
206 	switch( adr->type ) {
207 	case NA_LOOPBACK:
208 		return qtrue;
209 	case NA_IP:
210 	case NA_BROADCAST:
211 		if( adr->ip[0] == 127 || adr->ip[0] == 10 ) {
212 			return qtrue;
213 		}
214 		if( ( adr->ip[0] == 192 && adr->ip[1] == 168 ) ||
215 			( adr->ip[0] == 172 && adr->ip[1] == 16 ) )
216 		{
217 			return qtrue;
218 		}
219 		return qfalse;
220 	default:
221 		Com_Error( ERR_FATAL, "NET_IsLANAddress: bad address type: %i", adr->type );
222 		break;
223 	}
224 
225 	return qfalse;
226 }
227 
228 /*
229 ===================
230 NET_AdrToString
231 ===================
232 */
NET_AdrToString(const netadr_t * a)233 char *NET_AdrToString( const netadr_t *a ) {
234 	static	char	s[MAX_QPATH];
235 
236 	switch( a->type ) {
237 	case NA_LOOPBACK:
238 		Com_sprintf( s, sizeof( s ), "loopback" );
239 		return s;
240 	case NA_IP:
241 	case NA_BROADCAST:
242 		Com_sprintf( s, sizeof( s ), "%i.%i.%i.%i:%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3], ntohs( a->port ) );
243 		return s;
244 	default:
245 		Com_Error( ERR_FATAL, "NET_AdrToString: bad address type: %i", a->type );
246 		break;
247 	}
248 
249 	return NULL;
250 }
251 
252 /*
253 =============
254 NET_StringToAdr
255 
256 localhost
257 idnewt
258 idnewt:28000
259 192.246.40.70
260 192.246.40.70:28000
261 =============
262 */
NET_StringToAdr(const char * s,netadr_t * a)263 qboolean NET_StringToAdr( const char *s, netadr_t *a ) {
264 	struct sockaddr sadr;
265 
266 	if( !Q_stricmp( s, "localhost" ) ) {
267 		memset( a, 0, sizeof( *a ) );
268 		a->type = NA_LOOPBACK;
269 		return qtrue;
270 	}
271 
272 	if( !NET_StringToSockaddr( s, &sadr ) )
273 		return qfalse;
274 
275 	NET_SockadrToNetadr( &sadr, a );
276 
277 	return qtrue;
278 }
279 
280 /*
281 =============================================================================
282 
283 LOOPBACK BUFFERS FOR LOCAL PLAYER
284 
285 =============================================================================
286 */
287 
288 /*
289 =============
290 NET_GetLoopPacket
291 =============
292 */
NET_GetLoopPacket(netsrc_t sock)293 qboolean NET_GetLoopPacket( netsrc_t sock ) {
294 	loopback_t	*loop;
295 	loopmsg_t *loopmsg;
296 
297 	loop = &loopbacks[sock];
298 
299 	if( loop->send - loop->get > MAX_LOOPBACK - 1 ) {
300 		loop->get = loop->send - MAX_LOOPBACK + 1;
301 	}
302 
303 	if( loop->get >= loop->send ) {
304 		return qfalse;
305 	}
306 
307 	loopmsg = &loop->msgs[loop->get & (MAX_LOOPBACK-1)];
308 	loop->get++;
309 
310 	memcpy( msg_read.data, loopmsg->data, loopmsg->datalen );
311 	msg_read.cursize = loopmsg->datalen;
312 
313 	if( net_log_active->integer ) {
314 		NET_LogPacket( &net_from, qfalse, loopmsg->data, loopmsg->datalen );
315 	}
316 
317 	return qtrue;
318 
319 }
320 
321 
322 //=============================================================================
323 
NetLogFile_Close(void)324 static void NetLogFile_Close( void ) {
325 	if( !net_logFile ) {
326 		return;
327 	}
328 
329 	Com_Printf( "Closing %s\n", FS_GetFileName( net_logFile ) );
330 
331 	FS_FCloseFile( net_logFile );
332 	net_logFile = 0;
333 }
334 
NetLogFile_Open(void)335 static void NetLogFile_Open( void ) {
336 	uint32	mode;
337 
338 	mode = net_log_active->integer > 1 ? FS_MODE_APPEND : FS_MODE_WRITE;
339 
340 	if( net_log_flush->integer ) {
341 		mode |= FS_FLUSH_SYNC;
342 	}
343 
344 	FS_FOpenFile( net_log_name->string, &net_logFile, mode );
345 
346 	if( !net_logFile ) {
347 		Com_WPrintf( "Couldn't open %s\n", net_log_name->string );
348 		Cvar_SetInteger( "net_log_active", 0 );
349 		return;
350 	}
351 
352 	Com_Printf( "Logging network packets to %s\n", net_log_name->string );
353 }
354 
NetLogFileActive_OnChange(cvar_t * self,void * arg)355 static void NetLogFileActive_OnChange( cvar_t *self, void *arg ) {
356 	if( !self->integer ) {
357 		NetLogFile_Close();
358 	} else {
359 		NetLogFile_Open();
360 	}
361 }
362 
NetLogFileParam_OnChange(cvar_t * self,void * arg)363 static void NetLogFileParam_OnChange( cvar_t *self, void *arg ) {
364 	if( net_log_active->integer ) {
365 		NetLogFile_Close();
366 		NetLogFile_Open();
367 	}
368 }
369 
370 /*
371 =============
372 NET_LogPacket
373 =============
374 */
NET_LogPacket(const netadr_t * address,qboolean send,const byte * data,int dataSize)375 void NET_LogPacket( const netadr_t *address, qboolean send, const byte *data, int dataSize ) {
376 	int numRows;
377 	int i, j, c;
378 
379 	if( !net_logFile ) {
380 		return;
381 	}
382 
383 	FS_FPrintf( net_logFile, "%s : %s\n", send ? "send" : "recv", NET_AdrToString( address ) );
384 
385 	numRows = ( dataSize + 15 ) / 16;
386 	for( i = 0; i < numRows; i++ ) {
387 		FS_FPrintf( net_logFile, "%04x : ", i * 16 );
388 		for( j = 0; j < 16; j++ ) {
389 			if( i * 16 + j < dataSize ) {
390 				FS_FPrintf( net_logFile, "%02x ", data[i * 16 + j] );
391 			} else {
392 				FS_FPrintf( net_logFile, "   " );
393 			}
394 		}
395 		FS_FPrintf( net_logFile, ": ", i );
396 		for( j = 0; j < 16; j++ ) {
397 			if( i * 16 + j < dataSize ) {
398 				c = data[i * 16 + j];
399 				FS_FPrintf( net_logFile, "%c", ( c < 32 || c > 127 ) ? '.' : c );
400 			} else {
401 				FS_FPrintf( net_logFile, " " );
402 			}
403 		}
404 		FS_FPrintf( net_logFile, "\n" );
405 	}
406 
407 	FS_FPrintf( net_logFile, "\n" );
408 
409 }
410 
411 /*
412 =============
413 NET_GetPacket
414 
415 Fills current read buffer with packet contents
416 =============
417 */
NET_GetPacket(netsrc_t sock,netadr_t * fromAddress)418 int NET_GetPacket( netsrc_t sock, netadr_t *fromAddress ) {
419 	byte	buffer[MAX_PACKETLEN + 10];
420 	int 	ret;
421 	struct sockaddr from;
422 	uint32	fromlen;
423 	int		err;
424 
425 	if( sock >= NS_COUNT ) {
426 		Com_Error( ERR_FATAL, "NET_GetPacket: bad socket" );
427 	}
428 	if( sockets[sock] == INVALID_SOCKET ) {
429 		return 0;
430 	}
431 
432 	fromlen = sizeof( from );
433 	ret = recvfrom( sockets[sock], buffer, sizeof( buffer ), 0,
434 		( struct sockaddr * )&from, &fromlen );
435 
436 	NET_SockadrToNetadr( &from, fromAddress );
437 
438 	if( ret == -1 ) {
439 #ifdef WIN32
440 		err = WSAGetLastError();
441 
442 		switch( err ) {
443 		case WSAEWOULDBLOCK:
444 			// wouldblock is silent
445 			break;
446 		case WSAECONNRESET:
447 			if( !net_ignore_icmp->integer ) {
448 				return -1;
449 			}
450 			break;
451 		case WSAEMSGSIZE:
452 			Com_WPrintf( "NET_GetPacket: oversize packet from %s\n",
453 				NET_AdrToString( fromAddress ) );
454 			break;
455 		default:
456 			Com_EPrintf( "NET_GetPacket: %s from %s\n",
457 				Sys_NetErrorString(), NET_AdrToString( fromAddress ) );
458 			break;
459 		}
460 #else
461 		err = errno;
462 
463 		switch( err ) {
464 		case EWOULDBLOCK:
465 			// wouldblock is silent
466 			break;
467 		case ECONNREFUSED:
468 			if( !net_ignore_icmp->integer ) {
469 				return -1;
470 			}
471 			break;
472 		default:
473 			Com_EPrintf( "NET_GetPacket: %s from %s\n",
474 				Sys_NetErrorString(), NET_AdrToString( fromAddress ) );
475 			break;
476 		}
477 #endif
478 		return 0;
479 	}
480 
481 	if( net_log_active->integer ) {
482 		NET_LogPacket( fromAddress, qfalse, buffer, ret );
483 	}
484 
485 	if( ret > msg_read.maxsize ) {
486 		Com_WPrintf( "NET_GetPacket: oversize packet from %s\n",
487 			NET_AdrToString( fromAddress ) );
488 		return 0;
489 	}
490 
491 	memcpy( msg_read.data, buffer, ret );
492 	msg_read.cursize = ret;
493 
494 
495 
496 	return 1;
497 
498 }
499 
500 //=============================================================================
501 
502 /*
503 =============
504 NET_SendPacket
505 =============
506 */
NET_SendPacket(netsrc_t sock,const netadr_t * to,int length,const byte * data)507 int NET_SendPacket( netsrc_t sock, const netadr_t *to, int length, const byte *data ) {
508 	int		ret;
509 	struct sockaddr	addr;
510     int    err;
511 
512 	if( sock >= NS_COUNT ) {
513 		Com_Error( ERR_FATAL, "NET_GetPacket: bad socket" );
514 	}
515 	if( length < 0 ) {
516 		Com_Error( ERR_FATAL, "NET_SendPacket: bad length: %d\n", length );
517 	}
518 	if( length > MAX_PACKETLEN ) {
519 		Com_WPrintf( "NET_SendPacket: oversize packet: %d\n", length );
520 		return 0;
521 	}
522 
523 	switch( to->type ) {
524 	case NA_LOOPBACK: {
525 			loopback_t	*loop;
526 			loopmsg_t *msg;
527 
528 			if( net_dropsim->integer > 0 && ( rand() % 100 ) < net_dropsim->integer ) {
529 				return 0;
530 			}
531 
532 			loop = &loopbacks[sock ^ 1];
533 
534 			msg = &loop->msgs[loop->send & ( MAX_LOOPBACK - 1 )];
535 			loop->send++;
536 
537 			memcpy( msg->data, data, length );
538 			msg->datalen = length;
539 
540 			if( net_log_active->integer ) {
541 				NET_LogPacket( to, qtrue, data, length );
542 			}
543 		}
544 		return 1;
545 	case NA_IP:
546 	case NA_BROADCAST:
547 		break;
548 	default:
549 		Com_Error( ERR_FATAL, "NET_SendPacket: bad address type: %i", to->type );
550 		break;
551 	}
552 
553 	if( sockets[sock] == INVALID_SOCKET ) {
554 		return 0;
555 	}
556 
557 	NET_NetadrToSockadr( to, &addr );
558 
559 	ret = sendto( sockets[sock], data, length, 0, &addr, sizeof( addr ) );
560 	if( net_log_active->integer ) {
561 		NET_LogPacket( to, qtrue, data, length );
562 	}
563 
564 	if( ret == SOCKET_ERROR ) {
565 #ifdef WIN32
566 		err = WSAGetLastError();
567 
568 		switch( err ) {
569 		case WSAEWOULDBLOCK:
570 		case WSAEINTR:
571 			// wouldblock is silent
572 			break;
573 		case WSAECONNRESET:
574 		case WSAEHOSTUNREACH:
575 			if( !net_ignore_icmp->integer ) {
576 				return -1;
577 			}
578 			break;
579 		case WSAEADDRNOTAVAIL:
580 			// some PPP links do not allow broadcasts
581 			if( to->type == NA_BROADCAST ) {
582 				break;
583 			}
584 			// intentional fallthrough
585 		default:
586 			Com_EPrintf( "NET_SendPacket: %s to %s\n",
587 				Sys_NetErrorString(), NET_AdrToString( to ) );
588 			break;
589 		}
590 #else
591 		err = errno;
592 
593 		switch( err ) {
594 		case EWOULDBLOCK:
595 			// wouldblock is silent
596 			break;
597 		case ECONNRESET:
598         case EHOSTUNREACH:
599         case ENETUNREACH:
600         case ENETDOWN:
601             if( !net_ignore_icmp->integer ) {
602                 return -1;
603             }
604 			break;
605 		default:
606 			Com_EPrintf( "NET_SendPacket: %s (%d) to %s\n",
607 				Sys_NetErrorString(), err, NET_AdrToString( to ) );
608 			break;
609 		}
610 #endif
611 
612 		return 0;
613 
614 	}
615 
616 	return 1;
617 }
618 
619 
620 //=============================================================================
621 
622 /*
623 ====================
624 NET_OpenServerIP
625 ====================
626 */
NET_OpenServerIP(void)627 static void NET_OpenServerIP( void ) {
628 	int port;
629 
630 	for( port = 0; port < PORT_MAX_SEARCH; port++ ) {
631 		sockets[NS_SERVER] = Sys_IPSocket( net_ip->string, net_port->integer + port );
632 		if( sockets[NS_SERVER] != INVALID_SOCKET ) {
633 			if( port ) {
634 				Cvar_SetInteger( "net_port", net_port->integer + port );
635 			}
636 			// set this for compatibility with game mods
637 			Cvar_SetInteger( "port", net_port->integer + port );
638 			return;
639 		}
640 	}
641 
642 	if( dedicated->integer ) {
643 		Com_Error( ERR_FATAL, "Couldn't allocate dedicated server IP port" );
644 	}
645 
646 	Com_Error( ERR_DROP, "Couldn't allocate server IP port" );
647 
648 }
649 
650 /*
651 ====================
652 NET_OpenClientIP
653 ====================
654 */
NET_OpenClientIP(void)655 static void NET_OpenClientIP( void ) {
656 	sockets[NS_CLIENT] = Sys_IPSocket( net_ip->string, net_clientport->integer );
657 	if( sockets[NS_CLIENT] != INVALID_SOCKET ) {
658 		return;
659 	}
660 
661 	if( net_clientport->integer != PORT_ANY ) {
662 		sockets[NS_CLIENT] = Sys_IPSocket( net_ip->string, PORT_ANY );
663 		if( sockets[NS_CLIENT] != INVALID_SOCKET ) {
664 			Cvar_SetInteger( "net_clientport", PORT_ANY );
665 			return;
666 		}
667 	}
668 
669 	Com_Error( ERR_DROP, "Couldn't allocate client IP port" );
670 
671 }
672 
673 /*
674 ====================
675 NET_Sleep
676 
677 sleeps msec or until net socket is ready
678 ====================
679 */
NET_Sleep(int msec)680 void NET_Sleep( int msec ) {
681     struct timeval timeout;
682 	fd_set	fdset;
683 	SOCKET i;
684 
685 	FD_ZERO( &fdset );
686 	i = 0;
687 	FD_SET( 0, &fdset ); // stdin
688 	if( sockets[NS_SERVER] != INVALID_SOCKET ) {
689 		FD_SET( sockets[NS_SERVER], &fdset ); // network socket
690 		i = sockets[NS_SERVER];
691 	}
692 	timeout.tv_sec = msec / 1000;
693 	timeout.tv_usec = ( msec % 1000 ) * 1000;
694 	select( i + 1, &fdset, NULL, NULL, &timeout );
695 }
696 
697 //===================================================================
698 
699 /*
700 ====================
701 NET_DumpHostInfo
702 ====================
703 */
NET_DumpHostInfo(struct hostent * h)704 static void NET_DumpHostInfo( struct hostent *h ) {
705 	byte **list;
706 	int i;
707 
708 	Com_Printf( "Hostname: %s\n", h->h_name );
709 
710 	list = (byte **)h->h_aliases;
711 	for( i=0 ; list[i] ; i++ ) {
712 		Com_Printf( "Alias   : %s\n", list[i] );
713 	}
714 
715 	list = (byte **)h->h_addr_list;
716 	for( i=0 ; list[i] ; i++ ) {
717 		Com_Printf( "IP      : %d.%d.%d.%d\n",
718 			list[i][0] & 255,
719 			list[i][1] & 255,
720 			list[i][2] & 255,
721 			list[i][3] & 255 );
722 	}
723 }
724 
725 /*
726 ====================
727 NET_ShowIP_f
728 ====================
729 */
NET_ShowIP_f(void)730 static void NET_ShowIP_f( void ) {
731 	char buffer[256];
732 	struct hostent *h;
733 
734 	if( gethostname( buffer, sizeof( buffer ) ) == SOCKET_ERROR ) {
735 		Com_Printf( "Couldn't get machine hostname\n" );
736 		return;
737 	}
738 
739 	if( !( h = gethostbyname( buffer ) ) ) {
740 		Com_Printf( "Couldn't get machine hostname\n" );
741 		return;
742 	}
743 
744 	NET_DumpHostInfo( h );
745 }
746 
747 /*
748 ====================
749 NET_Dns_f
750 ====================
751 */
NET_Dns_f(void)752 static void NET_Dns_f( void ) {
753 	char buffer[MAX_QPATH];
754 	char *p;
755 	struct hostent *h;
756 	u_long address;
757 
758 	if( Cmd_Argc() != 2 ) {
759 		Com_Printf( "Usage: %s <address>\n", Cmd_Argv( 0 ) );
760 		return;
761 	}
762 
763 	Cmd_ArgvBuffer( 1, buffer, sizeof( buffer ) );
764 
765 	if( ( p = strchr( buffer, ':' ) ) != NULL ) {
766 		*p = 0;
767 	}
768 
769 	if( ( address = inet_addr( buffer ) ) != INADDR_NONE ) {
770 		h = gethostbyaddr( (const char *)&address, sizeof( address ), AF_INET );
771 	} else {
772 		h = gethostbyname( buffer );
773 	}
774 
775 	if( !h ) {
776 		Com_Printf( "Couldn't resolve %s\n", buffer );
777 		return;
778 	}
779 
780 	NET_DumpHostInfo( h );
781 
782 }
783 
784 /*
785 ====================
786 NET_Restart_f
787 ====================
788 */
NET_Restart_f(void)789 static void NET_Restart_f( void ) {
790 	netflag_t flag = net_active;
791 
792 	NET_Config( NET_NONE );
793 	NET_Config( flag );
794 }
795 
796 /*
797 ====================
798 NET_Config
799 ====================
800 */
NET_Config(netflag_t flag)801 void NET_Config( netflag_t flag ) {
802 	netsrc_t sock;
803 
804 	if( flag == net_active ) {
805 		return;
806 	}
807 
808 	if( flag == NET_NONE ) {
809 		// shut down any existing sockets
810 		for( sock = 0; sock < NS_COUNT; sock++ ) {
811 			if( sockets[sock] != INVALID_SOCKET ) {
812 				Sys_CloseSocket( sockets[sock] );
813 				sockets[sock] = INVALID_SOCKET;
814 			}
815 		}
816 		net_active = NET_NONE;
817 		return;
818 	}
819 
820 	if( flag & NET_CLIENT ) {
821 		if( sockets[NS_CLIENT] == INVALID_SOCKET ) {
822 			NET_OpenClientIP();
823 		}
824 	}
825 
826 	if( flag & NET_SERVER ) {
827 		if( sockets[NS_SERVER] == INVALID_SOCKET ) {
828 			NET_OpenServerIP();
829 		}
830 	}
831 
832 	net_active |= flag;
833 }
834 
835 /*
836 ====================
837 NET_Init
838 ====================
839 */
NET_Init(void)840 void NET_Init( void ) {
841 	if( !Sys_InitNetworking() ) {
842 		return;
843 	}
844 
845 	Cvar_Subsystem( CVAR_SYSTEM_NET );
846 
847 	net_ip = Cvar_Get( "net_ip", "localhost", 0 );
848 	net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), 0 );
849 	net_clientport = Cvar_Get( "net_clientport", va( "%i", PORT_ANY ), 0 );
850 	net_dropsim = Cvar_Get( "net_dropsim", "0", 0 );
851 	net_log_active = Cvar_Get( "net_log_active", "0", 0 );
852 	net_log_active->changedFunc = NetLogFileActive_OnChange;
853 	net_log_name = Cvar_Get( "net_log_name", "qnetwork.log", 0 );
854 	net_log_name->changedFunc = NetLogFileParam_OnChange;
855 	net_log_flush = Cvar_Get( "net_log_flush", "0", 0 );
856 	net_log_flush->changedFunc = NetLogFileParam_OnChange;
857 	net_ignore_icmp = Cvar_Get( "net_ignore_icmp", "0", 0 );
858 
859 	Cvar_Subsystem( CVAR_SYSTEM_GENERIC );
860 
861 	Cmd_AddCommand( "net_restart", NET_Restart_f );
862 	Cmd_AddCommand( "showip", NET_ShowIP_f );
863 	Cmd_AddCommand( "dns", NET_Dns_f );
864 
865 	NET_ShowIP_f();
866 }
867 
868 /*
869 ====================
870 NET_Shutdown
871 ====================
872 */
NET_Shutdown(void)873 void NET_Shutdown( void ) {
874 	if( net_logFile ) {
875 		FS_FCloseFile( net_logFile );
876 		net_logFile = 0;
877 	}
878 
879 	NET_Config( NET_NONE );
880 
881 	Sys_ShutdownNetworking();
882 
883 	Cmd_RemoveCommand( "net_restart" );
884 	Cmd_RemoveCommand( "showip" );
885 	Cmd_RemoveCommand( "dns" );
886 }
887 
888