summaryrefslogtreecommitdiff
path: root/source/net_common.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2010-09-15 22:41:27 +0400
committerAndrey Nazarov <skuller@skuller.net>2010-09-15 22:41:27 +0400
commitcd8d25aa0b96b48e1a6d0edf9893afe9cbf796c1 (patch)
tree322d2ed47d1ab4c7afdd5e70f34829f252877872 /source/net_common.c
parentde41ad148d857184ead919fa488fd58cec5b1864 (diff)
Renamed source tree subdirectory into ‘src’, moved ‘asm’ subdirectory there and renamed it into ‘i386’.
Diffstat (limited to 'source/net_common.c')
-rw-r--r--source/net_common.c1769
1 files changed, 0 insertions, 1769 deletions
diff --git a/source/net_common.c b/source/net_common.c
deleted file mode 100644
index b569f8f..0000000
--- a/source/net_common.c
+++ /dev/null
@@ -1,1769 +0,0 @@
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-//
-// net.c
-//
-
-#include "com_local.h"
-#include "protocol.h"
-#include "q_msg.h"
-#include "q_fifo.h"
-#include "net_sock.h"
-#include "net_stream.h"
-#ifdef _DEBUG
-#include "files.h"
-#endif
-#include "sys_public.h"
-#include "sv_public.h"
-#include "cl_public.h"
-#include "io_sleep.h"
-
-#if( defined _WIN32 )
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <winsock2.h>
-#define socklen_t int
-#define IOCTLSOCKET_PARAM u_long
-#define SETSOCKOPT_PARAM BOOL
-#ifdef _WIN32_WCE
-#define NET_GET_ERROR() ( net_error = GetLastError() )
-#else
-#define NET_GET_ERROR() ( net_error = WSAGetLastError() )
-#define NET_WOULD_BLOCK() ( NET_GET_ERROR() == WSAEWOULDBLOCK )
-#endif
-#elif( defined __unix__ )
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <arpa/inet.h>
-#ifdef __linux__
-#include <linux/types.h>
-#if USE_ICMP
-#include <linux/errqueue.h>
-#endif
-#endif
-#define SOCKET int
-#define INVALID_SOCKET -1
-#define closesocket close
-#define ioctlsocket ioctl
-#define IOCTLSOCKET_PARAM int
-#define SETSOCKOPT_PARAM int
-#define NET_GET_ERROR() ( net_error = errno )
-#define NET_WOULD_BLOCK() ( NET_GET_ERROR() == EWOULDBLOCK )
-#else
-#error Unknown target OS
-#endif
-
-#if USE_CLIENT
-
-#define MAX_LOOPBACK 4
-
-typedef struct {
- byte data[MAX_PACKETLEN];
- size_t datalen;
-} loopmsg_t;
-
-typedef struct {
- loopmsg_t msgs[MAX_LOOPBACK];
- unsigned get;
- unsigned send;
-} loopback_t;
-
-static loopback_t loopbacks[NS_COUNT];
-
-#endif
-
-cvar_t *net_ip;
-cvar_t *net_port;
-
-netadr_t net_from;
-
-#if USE_CLIENT
-static cvar_t *net_clientport;
-static cvar_t *net_dropsim;
-#endif
-
-#ifdef _DEBUG
-static cvar_t *net_log_enable;
-static cvar_t *net_log_name;
-static cvar_t *net_log_flush;
-#endif
-
-static cvar_t *net_tcp_ip;
-static cvar_t *net_tcp_port;
-static cvar_t *net_tcp_backlog;
-
-#if USE_ICMP
-static cvar_t *net_ignore_icmp;
-#endif
-
-static netflag_t net_active;
-static int net_error;
-
-static const char socketNames[NS_COUNT][8] = { "Client", "Server" };
-static SOCKET udp_sockets[NS_COUNT] = { INVALID_SOCKET, INVALID_SOCKET };
-static SOCKET tcp_socket = INVALID_SOCKET;
-#ifdef _DEBUG
-static qhandle_t net_logFile;
-#endif
-
-// current rate measurement
-static unsigned net_rate_time;
-static size_t net_rate_rcvd;
-static size_t net_rate_sent;
-static size_t net_rate_dn;
-static size_t net_rate_up;
-
-// lifetime statistics
-static uint64_t net_recv_errors;
-static uint64_t net_send_errors;
-#if USE_ICMP
-static uint64_t net_icmp_errors;
-#endif
-static uint64_t net_bytes_rcvd;
-static uint64_t net_bytes_sent;
-static uint64_t net_packets_rcvd;
-static uint64_t net_packets_sent;
-
-//=============================================================================
-
-/*
-===================
-NET_NetadrToSockadr
-===================
-*/
-static void NET_NetadrToSockadr( const netadr_t *a, struct sockaddr_in *s ) {
- memset( s, 0, sizeof( *s ) );
-
- switch( a->type ) {
- case NA_BROADCAST:
- s->sin_family = AF_INET;
- s->sin_addr.s_addr = INADDR_BROADCAST;
- s->sin_port = a->port;
- break;
- case NA_IP:
- s->sin_family = AF_INET;
- s->sin_addr.s_addr = *( uint32_t * )&a->ip;
- s->sin_port = a->port;
- break;
- default:
- Com_Error( ERR_FATAL, "%s: bad address type", __func__ );
- break;
- }
-}
-
-/*
-===================
-NET_SockadrToNetadr
-===================
-*/
-static void NET_SockadrToNetadr( const struct sockaddr_in *s, netadr_t *a ) {
- memset( a, 0, sizeof( *a ) );
-
- a->type = NA_IP;
- *( uint32_t * )&a->ip = s->sin_addr.s_addr;
- a->port = s->sin_port;
-}
-
-/*
-=============
-NET_StringToSockaddr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-static qboolean NET_StringToSockaddr( const char *s, struct sockaddr_in *sadr ) {
- struct hostent *h;
- char copy[MAX_QPATH], *p;
- int dots;
-
- memset( sadr, 0, sizeof( *sadr ) );
-
- sadr->sin_family = AF_INET;
- sadr->sin_port = 0;
-
- Q_strlcpy( copy, s, sizeof( copy ) );
- // strip off a trailing :port if present
- p = strchr( copy, ':' );
- if( p ) {
- *p = 0;
- sadr->sin_port = htons( ( u_short )atoi( p + 1 ) );
- }
- for( p = copy, dots = 0; *p; p++ ) {
- if( *p == '.' ) {
- dots++;
- } else if( !Q_isdigit( *p ) ) {
- break;
- }
- }
- if( *p == 0 && dots <= 3 ) {
- uint32_t addr = inet_addr( copy );
-
- if( addr == INADDR_NONE ) {
- return qfalse;
- }
- sadr->sin_addr.s_addr = addr;
- } else {
- if( !( h = gethostbyname( copy ) ) )
- return qfalse;
- sadr->sin_addr.s_addr = *( uint32_t * )h->h_addr_list[0];
- }
-
- return qtrue;
-}
-
-
-/*
-===================
-NET_AdrToString
-===================
-*/
-char *NET_AdrToString( const netadr_t *a ) {
- static char s[MAX_QPATH];
-
- switch( a->type ) {
- case NA_LOOPBACK:
- strcpy( s, "loopback" );
- return s;
- case NA_IP:
- case NA_BROADCAST:
- Q_snprintf( s, sizeof( s ), "%u.%u.%u.%u:%u",
- a->ip[0], a->ip[1], a->ip[2], a->ip[3], ntohs( a->port ) );
- return s;
- default:
- Com_Error( ERR_FATAL, "%s: bad address type", __func__ );
- break;
- }
-
- return NULL;
-}
-
-/*
-=============
-NET_StringToAdr
-
-localhost
-idnewt
-idnewt:28000
-192.246.40.70
-192.246.40.70:28000
-=============
-*/
-qboolean NET_StringToAdr( const char *s, netadr_t *a, int port ) {
- struct sockaddr_in sadr;
-
- if( !NET_StringToSockaddr( s, &sadr ) ) {
- return qfalse;
- }
-
- NET_SockadrToNetadr( &sadr, a );
-
- if( !a->port ) {
- a->port = BigShort( port );
- }
-
- return qtrue;
-}
-
-//=============================================================================
-
-#ifdef _DEBUG
-
-static void logfile_close( void ) {
- if( !net_logFile ) {
- return;
- }
-
- Com_Printf( "Closing network log.\n" );
-
- FS_FCloseFile( net_logFile );
- net_logFile = 0;
-}
-
-static void logfile_open( void ) {
- char buffer[MAX_OSPATH];
- unsigned mode;
- qhandle_t f;
-
- mode = net_log_enable->integer > 1 ? FS_MODE_APPEND : FS_MODE_WRITE;
- if( net_log_flush->integer ) {
- mode |= FS_FLUSH_SYNC;
- }
-
- f = FS_EasyOpenFile( buffer, sizeof( buffer ), mode,
- "logs/", net_log_name->string, ".log" );
- if( !f ) {
- Cvar_Set( "net_log_enable", "0" );
- return;
- }
-
- net_logFile = f;
- Com_Printf( "Logging network packets to %s\n", buffer );
-}
-
-static void net_log_enable_changed( cvar_t *self ) {
- logfile_close();
- if( self->integer ) {
- logfile_open();
- }
-}
-
-static void net_log_param_changed( cvar_t *self ) {
- if( net_log_enable->integer ) {
- logfile_close();
- logfile_open();
- }
-}
-
-/*
-=============
-NET_LogPacket
-=============
-*/
-static void NET_LogPacket( const netadr_t *address, const char *prefix,
- const byte *data, size_t length )
-{
- int numRows;
- int i, j, c;
-
- if( !net_logFile ) {
- return;
- }
-
- FS_FPrintf( net_logFile, "%s : %s\n", prefix, NET_AdrToString( address ) );
-
- numRows = ( length + 15 ) / 16;
- for( i = 0; i < numRows; i++ ) {
- FS_FPrintf( net_logFile, "%04x : ", i * 16 );
- for( j = 0; j < 16; j++ ) {
- if( i * 16 + j < length ) {
- FS_FPrintf( net_logFile, "%02x ", data[i * 16 + j] );
- } else {
- FS_FPrintf( net_logFile, " " );
- }
- }
- FS_FPrintf( net_logFile, ": " );
- for( j = 0; j < 16; j++ ) {
- if( i * 16 + j < length ) {
- c = data[i * 16 + j];
- FS_FPrintf( net_logFile, "%c", ( c < 32 || c > 127 ) ? '.' : c );
- } else {
- FS_FPrintf( net_logFile, " " );
- }
- }
- FS_FPrintf( net_logFile, "\n" );
- }
-
- FS_FPrintf( net_logFile, "\n" );
-}
-
-#endif
-
-#define RATE_SECS 3
-
-static void NET_UpdateStats( void ) {
- unsigned diff;
-
- if( net_rate_time > com_eventTime ) {
- net_rate_time = com_eventTime;
- }
- diff = com_eventTime - net_rate_time;
- if( diff < RATE_SECS * 1000 ) {
- return;
- }
- net_rate_time = com_eventTime;
-
- net_rate_dn = net_rate_rcvd / RATE_SECS;
- net_rate_up = net_rate_sent / RATE_SECS;
- net_rate_sent = 0;
- net_rate_rcvd = 0;
-}
-
-
-#if USE_CLIENT
-
-/*
-=============
-NET_GetLoopPacket
-=============
-*/
-qboolean NET_GetLoopPacket( netsrc_t sock ) {
- loopback_t *loop;
- loopmsg_t *loopmsg;
-
- NET_UpdateStats();
-
- loop = &loopbacks[sock];
-
- if( loop->send - loop->get > MAX_LOOPBACK - 1 ) {
- loop->get = loop->send - MAX_LOOPBACK + 1;
- }
-
- if( loop->get >= loop->send ) {
- return qfalse;
- }
-
- loopmsg = &loop->msgs[loop->get & (MAX_LOOPBACK-1)];
- loop->get++;
-
- memcpy( msg_read_buffer, loopmsg->data, loopmsg->datalen );
-
-#ifdef _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( &net_from, "LP recv", loopmsg->data, loopmsg->datalen );
- }
-#endif
- if( sock == NS_CLIENT ) {
- net_rate_rcvd += loopmsg->datalen;
- }
-
- SZ_Init( &msg_read, msg_read_buffer, sizeof( msg_read_buffer ) );
- msg_read.cursize = loopmsg->datalen;
-
- return qtrue;
-}
-
-#endif
-
-#if USE_ICMP
-
-// prevents infinite retry loops caused by broken TCP/IP stacks
-#define MAX_ERROR_RETRIES 64
-
-static void icmp_error_event( netsrc_t sock, int info ) {
- if( net_ignore_icmp->integer > 0 ) {
- return;
- }
-
- Com_DPrintf( "%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString( &net_from ) );
- net_icmp_errors++;
-
- switch( sock ) {
- case NS_SERVER:
- SV_ErrorEvent( info );
- break;
-#if USE_CLIENT
- case NS_CLIENT:
- CL_ErrorEvent();
- break;
-#endif
- default:
- break;
- }
-}
-
-#ifdef __linux__
-
-// Linux at least supports receiving ICMP errors on unconnected UDP sockets
-// via IP_RECVERR cruft below... What about BSD?
-//
-// Returns true if failed socket operation should be retried, extremely hacky :/
-static qboolean process_error_queue( netsrc_t sock, struct sockaddr_in *to ) {
- byte buffer[1024];
- struct sockaddr_in from;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- struct sock_extended_err *ee;
- int info;
- int tries;
- qboolean found;
-
- tries = 0;
- found = qfalse;
-
-retry:
- memset( &from, 0, sizeof( from ) );
-
- memset( &msg, 0, sizeof( msg ) );
- msg.msg_name = &from;
- msg.msg_namelen = sizeof( from );
- msg.msg_control = buffer;
- msg.msg_controllen = sizeof( buffer );
-
- if( recvmsg( udp_sockets[sock], &msg, MSG_ERRQUEUE ) == -1 ) {
- if( NET_WOULD_BLOCK() ) {
- // wouldblock is silent
- goto finish;
- }
- Com_EPrintf( "%s: %s\n", __func__, NET_ErrorString() );
- goto finish;
- }
-
- if( !( msg.msg_flags & MSG_ERRQUEUE ) ) {
- Com_DPrintf( "%s: no extended error received\n", __func__ );
- goto finish;
- }
-
- // find an ICMP error message
- for( cmsg = CMSG_FIRSTHDR( &msg );
- cmsg != NULL;
- cmsg = CMSG_NXTHDR( &msg, cmsg ) )
- {
- if( cmsg->cmsg_level != IPPROTO_IP ) {
- continue;
- }
- if( cmsg->cmsg_type != IP_RECVERR ) {
- continue;
- }
- ee = ( struct sock_extended_err * )CMSG_DATA( cmsg );
- if( ee->ee_origin == SO_EE_ORIGIN_ICMP ) {
- break;
- }
- }
-
- if( !cmsg ) {
- Com_DPrintf( "%s: no ICMP error found\n", __func__ );
- goto finish;
- }
-
- NET_SockadrToNetadr( &from, &net_from );
-
- // check if this error was caused by a packet sent to the given address
- // if so, do not retry send operation to prevent infinite loop
- if( to != NULL && from.sin_addr.s_addr == to->sin_addr.s_addr &&
- ( !from.sin_port || from.sin_port == to->sin_port ) )
- {
- Com_DPrintf( "%s: found offending address %s:%d\n",
- __func__, inet_ntoa( from.sin_addr ), BigShort( from.sin_port ) );
- found = qtrue;
- }
-
- // handle ICMP errors
- net_error = ee->ee_errno;
- info = 0;
-#if USE_PMTUDISC
- // for EMSGSIZE ee_info should hold discovered MTU
- if( net_error == EMSGSIZE && ee->ee_info >= 576 && ee->ee_info < 4096 ) {
- info = ee->ee_info;
- }
-#endif
- icmp_error_event( sock, info );
-
- if( ++tries < MAX_ERROR_RETRIES ) {
- goto retry;
- }
-
-finish:
- return !!tries && !found;
-}
-
-#endif // __linux__
-
-#endif // USE_ICMP
-
-/*
-=============
-NET_GetPacket
-
-Fills msg_read_buffer with packet contents,
-net_from variable receives source address.
-=============
-*/
-qboolean NET_GetPacket( netsrc_t sock ) {
- struct sockaddr_in from;
- socklen_t fromlen;
- int ret;
-#if USE_ICMP
- int tries;
-#ifndef _WIN32
- int saved_error;
-#endif
-#endif
- ioentry_t *e;
-
- if( udp_sockets[sock] == INVALID_SOCKET ) {
- return qfalse;
- }
-
- NET_UpdateStats();
-
- e = IO_Get( udp_sockets[sock] );
- if( !e->canread ) {
- return qfalse;
- }
-
-#if USE_ICMP
- tries = 0;
-
-retry:
-#endif
- memset( &from, 0, sizeof( from ) );
-
- fromlen = sizeof( from );
- ret = recvfrom( udp_sockets[sock], ( void * )msg_read_buffer,
- MAX_PACKETLEN, 0, ( struct sockaddr * )&from, &fromlen );
-
- if( !ret ) {
- return qfalse;
- }
-
- NET_SockadrToNetadr( &from, &net_from );
-
- if( ret == -1 ) {
- NET_GET_ERROR();
-
-#ifdef _WIN32
- switch( net_error ) {
- case WSAEWOULDBLOCK:
- // wouldblock is silent
- e->canread = qfalse;
- break;
-#if USE_ICMP
- case WSAECONNRESET:
- case WSAENETRESET:
- // winsock has already provided us with
- // a valid address from ICMP error packet
- icmp_error_event( sock, 0 );
- if( ++tries < MAX_ERROR_RETRIES ) {
- goto retry;
- }
- // intentional fallthrough
-#endif // USE_ICMP
- default:
- Com_DPrintf( "%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString( &net_from ) );
- net_recv_errors++;
- break;
- }
-#else // _WIN32
- switch( net_error ) {
- case EWOULDBLOCK:
- // wouldblock is silent
- e->canread = qfalse;
- break;
- default:
-#if USE_ICMP
- saved_error = net_error;
- // recvfrom() fails on Linux if there's an ICMP originated
- // pending error on socket. suck up error queue and retry...
- if( process_error_queue( sock, NULL ) ) {
- if( ++tries < MAX_ERROR_RETRIES ) {
- goto retry;
- }
- }
-#endif
- net_error = saved_error;
- Com_DPrintf( "%s: %s from %s\n", __func__,
- NET_ErrorString(), NET_AdrToString( &net_from ) );
- net_recv_errors++;
- break;
- }
-#endif // !_WIN32
- return qfalse;
- }
-
- if( ret > MAX_PACKETLEN ) {
- Com_EPrintf( "%s: oversize packet from %s\n", __func__,
- NET_AdrToString( &net_from ) );
- return qfalse;
- }
-
-#ifdef _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( &net_from, "UDP recv", msg_read_buffer, ret );
- }
-#endif
-
- SZ_Init( &msg_read, msg_read_buffer, sizeof( msg_read_buffer ) );
- msg_read.cursize = ret;
- net_rate_rcvd += ret;
- net_bytes_rcvd += ret;
- net_packets_rcvd++;
-
- return qtrue;
-}
-
-//=============================================================================
-
-/*
-=============
-NET_SendPacket
-
-=============
-*/
-qboolean NET_SendPacket( netsrc_t sock, const netadr_t *to, size_t length, const void *data ) {
- struct sockaddr_in addr;
- int ret;
-#if USE_ICMP && ( defined __linux__ )
- int tries;
- int saved_error;
-#endif
-
- if( !length ) {
- return qfalse;
- }
-
- if( length > MAX_PACKETLEN ) {
- Com_EPrintf( "%s: oversize packet to %s\n", __func__,
- NET_AdrToString( to ) );
- return qfalse;
- }
-
- switch( to->type ) {
-#if USE_CLIENT
- case NA_LOOPBACK: {
- loopback_t *loop;
- loopmsg_t *msg;
-
- if( net_dropsim->integer > 0 &&
- ( rand() % 100 ) < net_dropsim->integer )
- {
- return NET_AGAIN;
- }
-
- loop = &loopbacks[sock ^ 1];
-
- msg = &loop->msgs[loop->send & ( MAX_LOOPBACK - 1 )];
- loop->send++;
-
- memcpy( msg->data, data, length );
- msg->datalen = length;
-
-#ifdef _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( to, "LB send", data, length );
- }
-#endif
- if( sock == NS_CLIENT ) {
- net_rate_sent += length;
- }
- }
- return qtrue;
-#endif
- case NA_IP:
- case NA_BROADCAST:
- break;
- default:
- Com_Error( ERR_FATAL, "%s: bad address type", __func__ );
- break;
- }
-
- if( udp_sockets[sock] == INVALID_SOCKET ) {
- return qfalse;
- }
-
- NET_NetadrToSockadr( to, &addr );
-
-#if USE_ICMP && ( defined __linux__ )
- tries = 0;
-
-retry:
-#endif
- ret = sendto( udp_sockets[sock], data, length, 0,
- ( struct sockaddr * )&addr, sizeof( addr ) );
- if( ret == -1 ) {
- NET_GET_ERROR();
-
-#ifdef _WIN32
- switch( net_error ) {
- case WSAEWOULDBLOCK:
- case WSAEINTR:
- // wouldblock is silent
- break;
- case WSAEADDRNOTAVAIL:
- // some PPP links do not allow broadcasts
- if( to->type == NA_BROADCAST ) {
- break;
- }
- // intentional fallthrough
- default:
- Com_DPrintf( "%s: %s to %s\n", __func__,
- NET_ErrorString(), NET_AdrToString( to ) );
- net_send_errors++;
- break;
- }
-#else // _WIN32
- switch( net_error ) {
- case EWOULDBLOCK:
- // wouldblock is silent
- break;
- default:
-#if USE_ICMP
- saved_error = net_error;
- // sendto() fails on Linux if there's an ICMP originated
- // pending error on socket. suck up error queue and retry...
- //
- // this one is especially lame - how do I distingiush between
- // a failure caused by completely unrelated ICMP error sitting
- // in the queue and an error explicit to this sendto() call?
- //
- // on one hand, I don't want to drop packets to legitimate
- // clients because of this, and have to retry sendto() after
- // processing error queue, on another hand, infinite loop should be
- // avoided if this sendto() regenerates a message in error queue
- //
- // this mess is worked around by passing destination address
- // to process_error_queue() and checking if this address/port
- // pair is found in the queue. if it is found, or the queue
- // is empty, do not retry
- if( process_error_queue( sock, &addr ) ) {
- if( ++tries < MAX_ERROR_RETRIES ) {
- goto retry;
- }
- }
-#endif
- net_error = saved_error;
- Com_DPrintf( "%s: %s to %s\n", __func__,
- NET_ErrorString(), NET_AdrToString( to ) );
- net_send_errors++;
- break;
- }
-#endif // !_WIN32
- return qfalse;
- }
-
- if( ret != length ) {
- Com_WPrintf( "%s: short send to %s\n", __func__,
- NET_AdrToString( to ) );
- }
-
-#ifdef _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( to, "UDP send", data, ret );
- }
-#endif
- net_rate_sent += ret;
- net_bytes_sent += ret;
- net_packets_sent++;
-
- return qtrue;
-}
-
-
-//=============================================================================
-
-const char *NET_ErrorString( void ) {
-#ifdef _WIN32
- switch( net_error ) {
- case S_OK:
- return "NO ERROR";
- default:
- return "UNKNOWN ERROR";
-#include "wsaerr.h"
- }
-#else
- return strerror( net_error );
-#endif
-}
-
-static qboolean get_bind_addr( const char *iface, int port, struct sockaddr_in *sadr ) {
- if( *iface ) {
- if( !NET_StringToSockaddr( iface, sadr ) ) {
- return qfalse;
- }
- } else {
- // empty string binds to all interfaces
- memset( sadr, 0, sizeof( *sadr ) );
- sadr->sin_family = AF_INET;
- sadr->sin_addr.s_addr = INADDR_ANY;
- }
- if( port != PORT_ANY ) {
- sadr->sin_port = htons( ( u_short )port );
- }
-
- return qtrue;
-}
-
-static SOCKET create_socket( int type, int proto ) {
- SOCKET ret = socket( PF_INET, type, proto );
-
- NET_GET_ERROR();
- return ret;
-}
-
-static int set_option( SOCKET s, int level, int optname, int value ) {
- SETSOCKOPT_PARAM _value = value;
- int ret = setsockopt( s, level, optname, ( char * )&_value, sizeof( _value ) );
-
- NET_GET_ERROR();
- return ret;
-}
-
-#define enable_option(s,level,optname) set_option(s,level,optname,1)
-
-static int make_nonblock( SOCKET s ) {
- IOCTLSOCKET_PARAM _true = 1;
- int ret = ioctlsocket( s, FIONBIO, &_true );
-
- NET_GET_ERROR();
- return ret;
-}
-
-static int bind_socket( SOCKET s, struct sockaddr_in *sadr ) {
- int ret = bind( s, ( struct sockaddr * )sadr, sizeof( *sadr ) );
-
- NET_GET_ERROR();
- return ret;
-}
-
-static SOCKET UDP_OpenSocket( const char *iface, int port ) {
- SOCKET s;
- struct sockaddr_in sadr;
-#ifdef __linux__
- int pmtudisc;
-#endif
-
- Com_DPrintf( "Opening UDP socket: %s:%i\n", iface, port );
-
- s = create_socket( SOCK_DGRAM, IPPROTO_UDP );
- if( s == INVALID_SOCKET ) {
- Com_EPrintf( "%s: %s:%d: can't create socket: %s\n",
- __func__, iface, port, NET_ErrorString() );
- return INVALID_SOCKET;
- }
-
- // make it non-blocking
- if( make_nonblock( s ) == -1 ) {
- Com_EPrintf( "%s: %s:%d: can't make socket non-blocking: %s\n",
- __func__, iface, port, NET_ErrorString() );
- goto fail;
- }
-
- // make it broadcast capable
- if( enable_option( s, SOL_SOCKET, SO_BROADCAST ) == -1 ) {
- Com_WPrintf( "%s: %s:%d: can't make socket broadcast capable: %s\n",
- __func__, iface, port, NET_ErrorString() );
- }
-
-#ifdef __linux__
- pmtudisc = IP_PMTUDISC_DONT;
-
-#if USE_ICMP
- // enable ICMP error queue
- if( net_ignore_icmp->integer <= 0 ) {
- if( enable_option( s, IPPROTO_IP, IP_RECVERR ) == -1 ) {
- Com_WPrintf( "%s: %s:%d: can't enable ICMP error queue: %s\n",
- __func__, iface, port, NET_ErrorString() );
- Cvar_Set( "net_ignore_icmp", "1" );
- }
-
-#if USE_PMTUDISC
- // overload negative values to enable path MTU discovery
- switch( net_ignore_icmp->integer ) {
- case -1: pmtudisc = IP_PMTUDISC_WANT; break;
- case -2: pmtudisc = IP_PMTUDISC_DO; break;
-#ifdef IP_PMTUDISC_PROBE
- case -3: pmtudisc = IP_PMTUDISC_PROBE; break;
-#endif
- }
-#endif // USE_PMTUDISC
- }
-#endif // USE_ICMP
-
- // disable or enable path MTU discovery
- if( set_option( s, IPPROTO_IP, IP_MTU_DISCOVER, pmtudisc ) == -1 ) {
- Com_WPrintf( "%s: %s:%d: can't %sable path MTU discovery: %s\n",
- __func__, iface, port, pmtudisc == IP_PMTUDISC_DONT ? "dis" : "en",
- NET_ErrorString() );
- }
-
-#endif // __linux__
-
- // resolve iface sadr
- if( !get_bind_addr( iface, port, &sadr ) ) {
- Com_EPrintf( "%s: %s:%d: bad interface address\n",
- __func__, iface, port );
- goto fail;
- }
-
- if( bind_socket( s, &sadr ) == -1 ) {
- Com_EPrintf( "%s: %s:%d: can't bind socket: %s\n",
- __func__, iface, port, NET_ErrorString() );
- goto fail;
- }
-
- return s;
-
-fail:
- closesocket( s );
- return INVALID_SOCKET;
-}
-
-static SOCKET TCP_OpenSocket( const char *iface, int port, netsrc_t who ) {
- SOCKET s;
- struct sockaddr_in sadr;
-
- Com_DPrintf( "Opening TCP socket: %s:%i\n", iface, port );
-
- s = create_socket( SOCK_STREAM, IPPROTO_TCP );
- if( s == INVALID_SOCKET ) {
- Com_EPrintf( "%s: %s:%d: can't create socket: %s\n",
- __func__, iface, port, NET_ErrorString() );
- return INVALID_SOCKET;
- }
-
- // make it non-blocking
- if( make_nonblock( s ) == -1 ) {
- Com_EPrintf( "%s: %s:%d: can't make socket non-blocking: %s\n",
- __func__, iface, port, NET_ErrorString() );
- goto fail;
- }
-
- // give it a chance to reuse previous port
- if( who == NS_SERVER ) {
- if( enable_option( s, SOL_SOCKET, SO_REUSEADDR ) == -1 ) {
- Com_WPrintf( "%s: %s:%d: can't force socket to reuse address: %s\n",
- __func__, iface, port, NET_ErrorString() );
- }
- }
-
- if( !get_bind_addr( iface, port, &sadr ) ) {
- Com_EPrintf( "%s: %s:%d: bad interface address\n",
- __func__, iface, port );
- goto fail;
- }
-
- if( bind_socket( s, &sadr ) == -1 ) {
- Com_EPrintf( "%s: %s:%d: can't bind socket: %s\n",
- __func__, iface, port, NET_ErrorString() );
- goto fail;
- }
-
- return s;
-
-fail:
- closesocket( s );
- return INVALID_SOCKET;
-}
-
-static void NET_OpenServer( void ) {
- static int saved_port;
- ioentry_t *e;
- SOCKET s;
-
- s = UDP_OpenSocket( net_ip->string, net_port->integer );
- if( s != INVALID_SOCKET ) {
- saved_port = net_port->integer;
- udp_sockets[NS_SERVER] = s;
- e = IO_Add( s );
- e->wantread = qtrue;
- return;
- }
-
- if( saved_port && saved_port != net_port->integer ) {
- // revert to the last valid port
- Com_Printf( "Reverting to the last valid port %d...\n", saved_port );
- Cbuf_AddText( &cmd_buffer, va( "set net_port %d\n", saved_port ) );
- return;
- }
-
-#if USE_CLIENT
- if( !dedicated->integer ) {
- Com_WPrintf( "Couldn't open server UDP port.\n" );
- return;
- }
-#endif
-
- Com_Error( ERR_FATAL, "Couldn't open dedicated server UDP port" );
-}
-
-#if USE_CLIENT
-static void NET_OpenClient( void ) {
- ioentry_t *e;
- SOCKET s;
- struct sockaddr_in sadr;
- socklen_t len;
-
- s = UDP_OpenSocket( net_ip->string, net_clientport->integer );
- if( s == INVALID_SOCKET ) {
- // now try with random port
- if( net_clientport->integer != PORT_ANY ) {
- s = UDP_OpenSocket( net_ip->string, PORT_ANY );
- }
- if( s == INVALID_SOCKET ) {
- Com_WPrintf( "Couldn't open client UDP port.\n" );
- return;
- }
- len = sizeof( sadr );
- getsockname( s, ( struct sockaddr * )&sadr, &len );
- Com_WPrintf( "Client bound to UDP port %d.\n", ntohs( sadr.sin_port ) );
- Cvar_SetByVar( net_clientport, va( "%d", PORT_ANY ), FROM_CODE );
- }
-
- udp_sockets[NS_CLIENT] = s;
- e = IO_Add( s );
- e->wantread = qtrue;
-}
-#endif
-
-//=============================================================================
-
-void NET_Close( netstream_t *s ) {
- if( !s->state ) {
- return;
- }
-
- IO_Remove( s->socket );
- closesocket( s->socket );
- s->socket = INVALID_SOCKET;
- s->state = NS_DISCONNECTED;
-}
-
-neterr_t NET_Listen( qboolean arg ) {
- SOCKET s;
- ioentry_t *e;
-
- if( !arg ) {
- if( tcp_socket != INVALID_SOCKET ) {
- IO_Remove( tcp_socket );
- closesocket( tcp_socket );
- tcp_socket = INVALID_SOCKET;
- }
- return NET_OK;
- }
-
- if( tcp_socket != INVALID_SOCKET ) {
- return NET_OK;
- }
-
- s = TCP_OpenSocket( net_tcp_ip->string,
- net_tcp_port->integer, NS_SERVER );
- if( s == INVALID_SOCKET ) {
- return NET_ERROR;
- }
- if( listen( s, net_tcp_backlog->integer ) == -1 ) {
- NET_GET_ERROR();
- closesocket( s );
- return NET_ERROR;
- }
-
- tcp_socket = s;
- e = IO_Add( s );
- e->wantread = qtrue;
-
- return NET_OK;
-}
-
-// net_from variable receives source address
-neterr_t NET_Accept( netstream_t *s ) {
- struct sockaddr_in from;
- socklen_t fromlen;
- SOCKET newsocket;
- ioentry_t *e;
-
- if( tcp_socket == INVALID_SOCKET ) {
- return NET_AGAIN;
- }
-
- e = IO_Get( tcp_socket );
- if( !e->canread ) {
- return NET_AGAIN;
- }
-
- memset( &from, 0, sizeof( from ) );
- fromlen = sizeof( from );
- newsocket = accept( tcp_socket, ( struct sockaddr * )&from, &fromlen );
-
- NET_SockadrToNetadr( &from, &net_from );
-
- if( newsocket == -1 ) {
- if( NET_WOULD_BLOCK() ) {
- // wouldblock is silent
- e->canread = qfalse;
- return NET_AGAIN;
- }
- return NET_ERROR;
- }
-
- // make it non-blocking
- if( make_nonblock( newsocket ) == -1 ) {
- closesocket( newsocket );
- return NET_ERROR;
- }
-
- // initialize stream
- memset( s, 0, sizeof( *s ) );
- s->socket = newsocket;
- s->address = net_from;
- s->state = NS_CONNECTED;
-
- // initialize io entry
- e = IO_Add( newsocket );
- //e->wantwrite = qtrue;
- e->wantread = qtrue;
-
- return NET_OK;
-}
-
-neterr_t NET_Connect( const netadr_t *peer, netstream_t *s ) {
- SOCKET socket;
- ioentry_t *e;
- struct sockaddr_in sadr;
- int ret;
-
- // always bind to `net_ip' for outgoing TCP connections
- // to avoid problems with AC or MVD/GTV auth on a multi IP system
- socket = TCP_OpenSocket( net_ip->string, PORT_ANY, NS_CLIENT );
- if( socket == INVALID_SOCKET ) {
- return NET_ERROR;
- }
-
- NET_NetadrToSockadr( peer, &sadr );
-
- ret = connect( socket, ( struct sockaddr * )&sadr, sizeof( sadr ) );
- if( ret == -1 ) {
-#ifdef _WIN32
- if( NET_GET_ERROR() != WSAEWOULDBLOCK ) {
-#else
- if( NET_GET_ERROR() != EINPROGRESS ) {
-#endif
- // wouldblock is silent
- closesocket( socket );
- return NET_ERROR;
- }
- }
-
- // initialize stream
- memset( s, 0, sizeof( *s ) );
- s->state = NS_CONNECTING;
- s->address = *peer;
- s->socket = socket;
-
- // initialize io entry
- e = IO_Add( socket );
- e->wantwrite = qtrue;
-#ifdef _WIN32
- e->wantexcept = qtrue;
-#endif
-
- return NET_OK;
-}
-
-neterr_t NET_RunConnect( netstream_t *s ) {
- socklen_t len;
- int ret, err;
- ioentry_t *e;
-
- if( s->state != NS_CONNECTING ) {
- return NET_AGAIN;
- }
-
- e = IO_Get( s->socket );
- if( !e->canwrite
-#ifdef _WIN32
- && !e->canexcept
-#endif
- )
- {
- return NET_AGAIN;
- }
-
- len = sizeof( err );
- ret = getsockopt( s->socket, SOL_SOCKET, SO_ERROR, ( char * )&err, &len );
- if( ret == -1 ) {
- goto error1;
- }
- if( err ) {
- net_error = err;
- goto error2;
- }
-
- e->wantwrite = qfalse;
- e->wantread = qtrue;
-#ifdef _WIN32
- e->wantexcept = qfalse;
-#endif
- s->state = NS_CONNECTED;
- return NET_OK;
-
-error1:
- NET_GET_ERROR();
-error2:
- s->state = NS_BROKEN;
- e->wantwrite = qfalse;
- e->wantread = qfalse;
-#ifdef _WIN32
- e->wantexcept = qfalse;
-#endif
- return NET_ERROR;
-}
-
-// updates wantread/wantwrite
-void NET_UpdateStream( netstream_t *s ) {
- size_t len;
- ioentry_t *e;
-
- if( s->state != NS_CONNECTED ) {
- return;
- }
-
- e = IO_Get( s->socket );
-
- FIFO_Reserve( &s->recv, &len );
- e->wantread = len ? qtrue : qfalse;
-
- FIFO_Peek( &s->send, &len );
- e->wantwrite = len ? qtrue : qfalse;
-}
-
-// returns NET_OK only when there was some data read
-neterr_t NET_RunStream( netstream_t *s ) {
- int ret;
- size_t len;
- void *data;
- neterr_t result = NET_AGAIN;
- ioentry_t *e;
-
- if( s->state != NS_CONNECTED ) {
- return result;
- }
-
- e = IO_Get( s->socket );
- if( e->wantread && e->canread ) {
- // read as much as we can
- data = FIFO_Reserve( &s->recv, &len );
- if( len ) {
- ret = recv( s->socket, data, len, 0 );
- if( !ret ) {
- goto closed;
- }
- if( ret == -1 ) {
- if( NET_WOULD_BLOCK() ) {
- // wouldblock is silent
- e->canread = qfalse;
- } else {
- goto error;
- }
- } else {
- FIFO_Commit( &s->recv, ret );
-#if _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( &s->address, "TCP recv", data, ret );
- }
-#endif
- net_rate_rcvd += ret;
- net_bytes_rcvd += ret;
-
- result = NET_OK;
-
- // now see if there's more space to read
- FIFO_Reserve( &s->recv, &len );
- if( !len ) {
- e->wantread = qfalse;
- }
- }
- }
- }
-
- if( e->wantwrite && e->canwrite ) {
- // write as much as we can
- data = FIFO_Peek( &s->send, &len );
- if( len ) {
- ret = send( s->socket, data, len, 0 );
- if( !ret ) {
- goto closed;
- }
- if( ret == -1 ) {
- if( NET_WOULD_BLOCK() ) {
- // wouldblock is silent
- e->canwrite = qfalse;
- } else {
- goto error;
- }
- } else {
- FIFO_Decommit( &s->send, ret );
-#if _DEBUG
- if( net_log_enable->integer ) {
- NET_LogPacket( &s->address, "TCP send", data, ret );
- }
-#endif
- net_rate_sent += ret;
- net_bytes_sent += ret;
-
- //result = NET_OK;
-
- // now see if there's more data to write
- FIFO_Peek( &s->send, &len );
- if( !len ) {
- e->wantwrite = qfalse;
- }
-
- }
- }
- }
-
- return result;
-
-closed:
- s->state = NS_CLOSED;
- e->wantread = qfalse;
- return NET_CLOSED;
-
-error:
- s->state = NS_BROKEN;
- e->wantread = qfalse;
- e->wantwrite = qfalse;
- return NET_ERROR;
-}
-
-//===================================================================
-
-/*
-====================
-NET_Stats_f
-====================
-*/
-static void NET_Stats_f( void ) {
- time_t diff, now = time( NULL );
- char buffer[MAX_QPATH];
-
- if( com_startTime > now ) {
- com_startTime = now;
- }
- diff = now - com_startTime;
- if( diff < 1 ) {
- diff = 1;
- }
-
- Com_FormatTime( buffer, sizeof( buffer ), diff );
- Com_Printf( "Network uptime: %s\n", buffer );
- Com_Printf( "Bytes sent: %"PRIu64" (%"PRIu64" bytes/sec)\n",
- net_bytes_sent, net_bytes_sent / diff );
- Com_Printf( "Bytes rcvd: %"PRIu64" (%"PRIu64" bytes/sec)\n",
- net_bytes_rcvd, net_bytes_rcvd / diff );
- Com_Printf( "Packets sent: %"PRIu64" (%"PRIu64" packets/sec)\n",
- net_packets_sent, net_packets_sent / diff );
- Com_Printf( "Packets rcvd: %"PRIu64" (%"PRIu64" packets/sec)\n",
- net_packets_rcvd, net_packets_rcvd / diff );
-#if USE_ICMP
- Com_Printf( "Total errors: %"PRIu64"/%"PRIu64"/%"PRIu64" (send/recv/icmp)\n",
- net_send_errors, net_recv_errors, net_icmp_errors );
-#else
- Com_Printf( "Total errors: %"PRIu64"/%"PRIu64" (send/recv)\n",
- net_send_errors, net_recv_errors );
-#endif
- Com_Printf( "Current upload rate: %"PRIz" bytes/sec\n", net_rate_up );
- Com_Printf( "Current download rate: %"PRIz" bytes/sec\n", net_rate_dn );
-}
-
-/*
-====================
-NET_DumpHostInfo
-====================
-*/
-static void NET_DumpHostInfo( struct hostent *h ) {
- byte **list;
- int i;
-
- Com_Printf( "Hostname: %s\n", h->h_name );
-
- list = ( byte ** )h->h_aliases;
- for( i = 0; list[i]; i++ ) {
- Com_Printf( "Alias : %s\n", list[i] );
- }
-
- list = ( byte ** )h->h_addr_list;
- for( i = 0; list[i]; i++ ) {
- Com_Printf( "IP : %u.%u.%u.%u\n",
- list[i][0], list[i][1], list[i][2], list[i][3] );
- }
-}
-
-static void dump_socket( SOCKET s, const char *s1, const char *s2 ) {
- struct sockaddr_in sadr;
- socklen_t len;
- netadr_t adr;
-
- len = sizeof( sadr );
- if( getsockname( s, ( struct sockaddr * )&sadr, &len ) == -1 ) {
- NET_GET_ERROR();
- Com_EPrintf( "%s: getsockname: %s\n", __func__, NET_ErrorString() );
- return;
- }
- NET_SockadrToNetadr( &sadr, &adr );
- Com_Printf( "%s %s socket bound to %s\n", s1, s2, NET_AdrToString( &adr ) );
-}
-
-/*
-====================
-NET_ShowIP_f
-====================
-*/
-static void NET_ShowIP_f( void ) {
- char buffer[256];
- struct hostent *h;
- netsrc_t sock;
-
- if( gethostname( buffer, sizeof( buffer ) ) == -1 ) {
- NET_GET_ERROR();
- Com_EPrintf( "%s: gethostname: %s\n", __func__, NET_ErrorString() );
- return;
- }
-
- if( !( h = gethostbyname( buffer ) ) ) {
- NET_GET_ERROR();
- Com_EPrintf( "%s: gethostbyname: %s\n", __func__, NET_ErrorString() );
- return;
- }
-
- NET_DumpHostInfo( h );
-
- for( sock = 0; sock < NS_COUNT; sock++ ) {
- if( udp_sockets[sock] != INVALID_SOCKET ) {
- dump_socket( udp_sockets[sock], socketNames[sock], "UDP" );
- }
- }
- if( tcp_socket != INVALID_SOCKET ) {
- dump_socket( tcp_socket, socketNames[NS_SERVER], "TCP" );
- }
-}
-
-/*
-====================
-NET_Dns_f
-====================
-*/
-static void NET_Dns_f( void ) {
- char buffer[MAX_QPATH];
- char *p;
- struct hostent *h;
- u_long address;
-
- if( Cmd_Argc() != 2 ) {
- Com_Printf( "Usage: %s <address>\n", Cmd_Argv( 0 ) );
- return;
- }
-
- Cmd_ArgvBuffer( 1, buffer, sizeof( buffer ) );
-
- if( ( p = strchr( buffer, ':' ) ) != NULL ) {
- *p = 0;
- }
-
- if( ( address = inet_addr( buffer ) ) != INADDR_NONE ) {
- h = gethostbyaddr( ( const char * )&address, sizeof( address ), AF_INET );
- } else {
- h = gethostbyname( buffer );
- }
-
- if( !h ) {
- Com_Printf( "Couldn't resolve %s\n", buffer );
- return;
- }
-
- NET_DumpHostInfo( h );
-
-}
-
-/*
-====================
-NET_Restart_f
-====================
-*/
-static void NET_Restart_f( void ) {
- netflag_t flag = net_active;
- qboolean listen = tcp_socket != INVALID_SOCKET;
-
- Com_DPrintf( "%s\n", __func__ );
-
- if( listen ) {
- NET_Listen( qfalse );
- }
- NET_Config( NET_NONE );
- NET_Config( flag );
- if( listen ) {
- NET_Listen( qtrue );
- }
-
-#if USE_SYSCON
- SV_SetConsoleTitle();
-#endif
-}
-
-/*
-====================
-NET_Config
-====================
-*/
-void NET_Config( netflag_t flag ) {
- netsrc_t sock;
-
- if( flag == net_active ) {
- return;
- }
-
- if( flag == NET_NONE ) {
- // shut down any existing sockets
- for( sock = 0; sock < NS_COUNT; sock++ ) {
- if( udp_sockets[sock] != INVALID_SOCKET ) {
- IO_Remove( udp_sockets[sock] );
- closesocket( udp_sockets[sock] );
- udp_sockets[sock] = INVALID_SOCKET;
- }
- }
- net_active = NET_NONE;
- return;
- }
-
-#if USE_CLIENT
- if( ( flag & NET_CLIENT ) && udp_sockets[NS_CLIENT] == INVALID_SOCKET ) {
- NET_OpenClient();
- }
-#endif
-
- if( ( flag & NET_SERVER ) && udp_sockets[NS_SERVER] == INVALID_SOCKET ) {
- NET_OpenServer();
- }
-
- net_active |= flag;
-}
-
-qboolean NET_GetAddress( netsrc_t sock, netadr_t *adr ) {
- struct sockaddr_in sadr;
- socklen_t len;
- SOCKET s = udp_sockets[sock];
-
- if( s == INVALID_SOCKET ) {
- return qfalse;
- }
-
- len = sizeof( sadr );
- if( getsockname( s, ( struct sockaddr * )&sadr, &len ) == -1 ) {
- return qfalse;
- }
-
- NET_SockadrToNetadr( &sadr, adr );
-
- return qtrue;
-}
-
-static size_t NET_UpRate_m( char *buffer, size_t size ) {
- return Q_scnprintf( buffer, size, "%"PRIz, net_rate_up );
-}
-
-static size_t NET_DnRate_m( char *buffer, size_t size ) {
- return Q_scnprintf( buffer, size, "%"PRIz, net_rate_dn );
-}
-
-static void net_udp_param_changed( cvar_t *self ) {
- // keep TCP socket vars in sync unless modified by user
- if( !( net_tcp_ip->flags & CVAR_MODIFIED ) ) {
- Cvar_SetByVar( net_tcp_ip, net_ip->string, FROM_CODE );
- }
- if( !( net_tcp_port->flags & CVAR_MODIFIED ) ) {
- Cvar_SetByVar( net_tcp_port, net_port->string, FROM_CODE );
- }
-
- NET_Restart_f();
-}
-
-static void net_tcp_param_changed( cvar_t *self ) {
- if( tcp_socket != INVALID_SOCKET ) {
- NET_Listen( qfalse );
- NET_Listen( qtrue );
- }
-}
-
-/*
-====================
-NET_Init
-====================
-*/
-void NET_Init( void ) {
-#ifdef _WIN32
- WSADATA ws;
- int ret;
-
- ret = WSAStartup( MAKEWORD( 1, 1 ), &ws );
- if( ret ) {
- Com_Error( ERR_FATAL, "Winsock initialization failed, returned %d", ret );
- }
-
- Com_DPrintf( "Winsock Initialized\n" );
-#endif
-
- net_ip = Cvar_Get( "net_ip", "", 0 );
- net_ip->changed = net_udp_param_changed;
- net_port = Cvar_Get( "net_port", PORT_SERVER_STRING, 0 );
- net_port->changed = net_udp_param_changed;
-#if USE_CLIENT
- net_clientport = Cvar_Get( "net_clientport", PORT_ANY_STRING, 0 );
- net_clientport->changed = net_udp_param_changed;
- net_dropsim = Cvar_Get( "net_dropsim", "0", 0 );
-#endif
-#if _DEBUG
- net_log_enable = Cvar_Get( "net_log_enable", "0", 0 );
- net_log_enable->changed = net_log_enable_changed;
- net_log_name = Cvar_Get( "net_log_name", "network", 0 );
- net_log_name->changed = net_log_param_changed;
- net_log_flush = Cvar_Get( "net_log_flush", "0", 0 );
- net_log_flush->changed = net_log_param_changed;
-#endif
-#if USE_ICMP
- net_ignore_icmp = Cvar_Get( "net_ignore_icmp", "0", 0 );
-#endif
- net_tcp_ip = Cvar_Get( "net_tcp_ip", net_ip->string, 0 );
- net_tcp_ip->changed = net_tcp_param_changed;
- net_tcp_port = Cvar_Get( "net_tcp_port", net_port->string, 0 );
- net_tcp_port->changed = net_tcp_param_changed;
- net_tcp_backlog = Cvar_Get( "net_tcp_backlog", "4", 0 );
-
-#if _DEBUG
- net_log_enable_changed( net_log_enable );
-#endif
-
- net_rate_time = com_eventTime;
-
- Cmd_AddCommand( "net_restart", NET_Restart_f );
- Cmd_AddCommand( "net_stats", NET_Stats_f );
- Cmd_AddCommand( "showip", NET_ShowIP_f );
- Cmd_AddCommand( "dns", NET_Dns_f );
-
- Cmd_AddMacro( "net_uprate", NET_UpRate_m );
- Cmd_AddMacro( "net_dnrate", NET_DnRate_m );
-}
-
-/*
-====================
-NET_Shutdown
-====================
-*/
-void NET_Shutdown( void ) {
-#if _DEBUG
- if( net_logFile ) {
- FS_FCloseFile( net_logFile );
- net_logFile = 0;
- }
-#endif
-
- NET_Listen( qfalse );
- NET_Config( NET_NONE );
-
-#ifdef _WIN32
- WSACleanup();
-#endif
-
- Cmd_RemoveCommand( "net_restart" );
- Cmd_RemoveCommand( "net_stats" );
- Cmd_RemoveCommand( "showip" );
- Cmd_RemoveCommand( "dns" );
-}
-