Skip to content
Snippets Groups Projects
Select Git revision
  • few-kart-lua-changes
  • next default protected
  • sugoi-2
  • Sugoi-2
  • SRB2_Discord
  • SRB2-Stuff
  • patch-refactor
  • delfile2
  • fruits-clipper
  • improve-download-refuse-message
  • kill-hud-feetoffset
  • raise-side-limits
  • renderhitbox-nightsitems
  • any-resolution
  • udmf-nophysicsequation
  • master
  • sector-portals
  • 2213
  • 2_2_12
  • maretimers
  • quick-intro
  • SRB2_release_2.2.13
  • SRB2_release_2.2.12
  • SRB2_release_2.2.11
  • SRB2_release_2.2.10
  • SRB2_release_2.2.9
  • SRB2_release_2.2.8
  • SRB2_release_2.2.7
  • SRB2_release_2.2.6
  • SRB2_release_2.2.5
  • SRB2_release_2.2.4
  • SRB2_release_2.2.3
  • SRB2_release_2.2.2
  • SRB2_release_2.2.1
  • SRB2_release_2.2.0
  • SRB2_release_2.1.25
  • SRB2_release_2.1.24
  • SRB2_release_2.1.23
  • SRB2_release_2.1.22
  • SRB2_release_2.1.21
  • SRB2_release_2.1.20
41 results

depcomp

Blame
  • Forked from STJr / SRB2
    Source project has a limited visibility.
    i_tcp.c 32.83 KiB
    // SONIC ROBO BLAST 2
    //-----------------------------------------------------------------------------
    // Copyright (C) 1998-2000 by DooM Legacy Team.
    // Copyright (C) 1999-2014 by Sonic Team Junior.
    //
    // This program is free software distributed under the
    // terms of the GNU General Public License, version 2.
    // See the 'LICENSE' file for more details.
    //-----------------------------------------------------------------------------
    /// \file  i_tcp.c
    /// \brief TCP driver, socket code.
    ///        This is not really OS-dependent because all OSes have the same socket API.
    ///        Just use ifdef for OS-dependent parts.
    
    #include <stdlib.h>
    #include <string.h>
    #include <stdio.h>
    #ifdef __GNUC__
    #include <unistd.h>
    #endif
    #ifdef __OS2__
    #include <sys/types.h>
    #include <sys/time.h>
    #endif // __OS2__
    
    #ifdef _PS3
    #define NO_IPV6 // PSL1GHT v2 do not have IPv6 support
    #endif
    
    #ifndef NO_IPV6
    #define HAVE_IPV6
    #endif
    
    #if defined (_WIN32) || defined (_WIN32_WCE)
    #define USE_WINSOCK
    #if defined (_WIN64) || defined (HAVE_IPV6)
    #define USE_WINSOCK2
    #else //_WIN64/HAVE_IPV6
    #define USE_WINSOCK1
    #endif
    #endif //WIN32 OS
    
    #ifdef _XBOX // XBox have on WinSock API?
    #undef USE_WINSOCK
    #undef USE_WINSOCK1
    #undef USE_WINSOCK2
    #endif
    
    #ifdef USE_WINSOCK2
    #include <ws2tcpip.h>
    #endif
    
    #include "doomdef.h"
    
    #if defined (NOMD5) && !defined (NONET)
    //#define NONET
    #endif
    
    #ifndef NONET
    #ifdef USE_WINSOCK1
    #include <winsock.h>
    #elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)
    #ifdef HAVE_LWIP
    #include <lwip/inet.h>
    #elif !defined (USE_WINSOCK)
    #include <arpa/inet.h>
    #endif //normal BSD API
    
    #ifdef HAVE_LWIP
    #include <lwip/sockets.h>
    #define ioctl lwip_ioctl
    #elif !defined (USE_WINSOCK) //!HAVE_LWIP
    #ifdef __APPLE_CC__
    #ifndef _BSD_SOCKLEN_T_
    #define _BSD_SOCKLEN_T_
    #endif //_BSD_SOCKLEN_T_
    #endif //__APPLE_CC__
    #include <sys/socket.h>
    #include <netinet/in.h>
    #endif //normal BSD API
    
    #if defined(_arch_dreamcast) && !defined(HAVE_LWIP)
    #include <kos/net.h>
    #elif defined(HAVE_LWIP)
    #include <lwip/lwip.h>
    #elif defined (_PS3)
    #include <net/select.h>
    #include <net/net.h>
    #elif !defined(USE_WINSOCK) //!HAVE_LWIP
    #include <netdb.h>
    #include <sys/ioctl.h>
    #endif //normal BSD API
    
    #include <errno.h>
    #include <time.h>
    
    #ifdef _arch_dreamcast
    #include "sdl/SRB2DC/dchelp.h"
    #endif
    
    #if (defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)
    	#include <sys/time.h>
    #endif // UNIXCOMMON
    #endif // !NONET
    
    #ifdef USE_WINSOCK
    	// some undefined under win32
    	#undef errno
    	//#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
    	#define errno h_errno // some very strange things happen when not using h_error?!?
    	#ifdef EWOULDBLOCK
    	#undef EWOULDBLOCK
    	#endif
    	#define EWOULDBLOCK WSAEWOULDBLOCK
    	#ifdef EMSGSIZE
    	#undef EMSGSIZE
    	#endif
    	#define EMSGSIZE WSAEMSGSIZE
    	#ifdef ECONNREFUSED
    	#undef ECONNREFUSED
    	#endif
    	#define ECONNREFUSED WSAECONNREFUSED
    	#ifdef ETIMEDOUT
    	#undef ETIMEDOUT
    	#endif
    	#define ETIMEDOUT WSAETIMEDOUT
    	#ifndef IOC_VENDOR
    	#define IOC_VENDOR 0x18000000
    	#endif
    	#ifndef _WSAIOW
    	#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
    	#endif
    	#ifndef SIO_UDP_CONNRESET
    	#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
    	#endif
    	#ifndef AI_ADDRCONFIG
    	#define AI_ADDRCONFIG 0x00000400
    	#endif
    	#ifndef STATUS_INVALID_PARAMETER
    	#define STATUS_INVALID_PARAMETER 0xC000000D
    	#endif
    #endif
    
    #ifdef __DJGPP__
    #ifdef WATTCP // Alam_GBC: Wattcp may need this
    #include <tcp.h>
    #define strerror strerror_s
    #else // wattcp
    #include <lsck/lsck.h>
    #endif // libsocket
    #endif // djgpp
    
    typedef union
    {
    	struct sockaddr     any;
    	struct sockaddr_in  ip4;
    #ifdef HAVE_IPV6
    	struct sockaddr_in6 ip6;
    #endif
    } mysockaddr_t;
    
    #ifdef HAVE_MINIUPNPC
    #ifdef STATIC_MINIUPNPC
    #define STATICLIB
    #endif
    #include "miniupnpc/miniwget.h"
    #include "miniupnpc/miniupnpc.h"
    #include "miniupnpc/upnpcommands.h"
    #undef STATICLIB
    static UINT8 UPNP_support = TRUE;
    #endif
    
    #endif // !NONET
    
    #define MAXBANS 100
    
    #include "i_system.h"
    #include "i_net.h"
    #include "d_net.h"
    #include "i_tcp.h"
    #include "m_argv.h"
    
    #include "doomstat.h"
    
    // win32 or djgpp
    #if defined (USE_WINSOCK) || defined (__DJGPP__)
    	// winsock stuff (in winsock a socket is not a file)
    	#define ioctl ioctlsocket
    	#define close closesocket
    
    	#ifdef _WIN32_WCE
    	#include "sdl/SRB2CE/cehelp.h"
    	#endif
    
    #endif
    
    #include "i_addrinfo.h"
    
    #ifdef __DJGPP__
    
    #ifdef WATTCP
    #define SELECTTEST
    #endif
    
    #elif defined(HAVE_LWIP)
    #define SELECTTEST
    #elif !defined( _arch_dreamcast)
    #define SELECTTEST
    #endif
    
    #define DEFAULTPORT "5029"
    
    #if defined (USE_WINSOCK) && !defined (NONET)
    typedef SOCKET SOCKET_TYPE;
    #define BADSOCKET INVALID_SOCKET
    #define ERRSOCKET (SOCKET_ERROR)
    #else
    #if (defined (__unix__) && !defined (MSDOS)) || defined (__APPLE__) || defined (__HAIKU__) || defined(_PS3)
    typedef int SOCKET_TYPE;
    #else
    typedef unsigned long SOCKET_TYPE;
    #endif
    #define BADSOCKET (SOCKET_TYPE)(~0)
    #define ERRSOCKET (-1)
    #endif
    
    #if (defined (WATTCP) && !defined (__libsocket_socklen_t)) || defined (USE_WINSOCK1)
    typedef int socklen_t;
    #endif
    
    #ifndef NONET
    static SOCKET_TYPE mysockets[MAXNETNODES+1] = {BADSOCKET};
    static size_t mysocketses = 0;
    static int myfamily[MAXNETNODES+1] = {0};
    static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {BADSOCKET};
    static mysockaddr_t clientaddress[MAXNETNODES+1];
    static mysockaddr_t broadcastaddress[MAXNETNODES+1];
    static size_t broadcastaddresses = 0;
    static boolean nodeconnected[MAXNETNODES+1];
    static mysockaddr_t banned[MAXBANS];
    static UINT8 bannedmask[MAXBANS];
    #endif
    
    static size_t numbans = 0;
    static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
    static boolean init_tcp_driver = false;
    
    static char port_name[8] = DEFAULTPORT;
    
    #ifndef NONET
    
    #ifdef WATTCP
    static void wattcp_outch(char s)
    {
    	static char old = '\0';
    	char pr[2] = {s,0};
    	if (s == old && old == ' ') return;
    	else old = s;
    	if (s == '\r') CONS_Printf("\n");
    	else if (s != '\n') CONS_Printf(pr);
    }
    #endif
    
    #ifdef USE_WINSOCK2
    #define inet_ntop inet_ntopA
    #define HAVE_NTOP
    static const char* inet_ntopA(short af, const void *cp, char *buf, socklen_t len)
    {
    	DWORD Dlen = len, AFlen = 0;
    	SOCKADDR_STORAGE any;
    	LPSOCKADDR anyp = (LPSOCKADDR)&any;
    	LPSOCKADDR_IN any4 = (LPSOCKADDR_IN)&any;
    	LPSOCKADDR_IN6 any6 = (LPSOCKADDR_IN6)&any;
    
    	if (!buf)
    	{
    		WSASetLastError(STATUS_INVALID_PARAMETER);
    		return NULL;
    	}
    
    	if (af != AF_INET && af != AF_INET6)
    	{
    		WSASetLastError(WSAEAFNOSUPPORT);
    		return NULL;
    	}
    
    	ZeroMemory(&any, sizeof(SOCKADDR_STORAGE));
    	any.ss_family = af;
    
    	switch (af)
    	{
    		case AF_INET:
    		{
    			CopyMemory(&any4->sin_addr, cp, sizeof(IN_ADDR));
    			AFlen = sizeof(SOCKADDR_IN);
    			break;
    		}
    		case AF_INET6:
    		{
    			CopyMemory(&any6->sin6_addr, cp, sizeof(IN6_ADDR));
    			AFlen = sizeof(SOCKADDR_IN6);
    			break;
    		}
    	}
    
    	if (WSAAddressToStringA(anyp, AFlen, NULL, buf, &Dlen) == SOCKET_ERROR)
    		return NULL;
    	return buf;
    }
    #elif !defined (USE_WINSOCK1)
    #define HAVE_NTOP
    #endif
    
    #ifdef HAVE_MINIUPNPC // based on old XChat patch
    static struct UPNPUrls urls;
    static struct IGDdatas data;
    static char lanaddr[64];
    
    static void I_ShutdownUPnP(void)
    {
    	FreeUPNPUrls(&urls);
    }
    
    static inline void I_InitUPnP(void)
    {
    	struct UPNPDev * devlist = NULL;
    	int upnp_error = -2;
    	CONS_Printf(M_GetText("Looking for UPnP Internet Gateway Device\n"));
    	devlist = upnpDiscover(2000, NULL, NULL, 0, false, &upnp_error);
    	if (devlist)
    	{
    		struct UPNPDev *dev = devlist;
    		char * descXML;
    		int descXMLsize = 0;
    		while (dev)
    		{
    			if (strstr (dev->st, "InternetGatewayDevice"))
    				break;
    			dev = dev->pNext;
    		}
    		if (!dev)
    			dev = devlist; /* defaulting to first device */
    
    		CONS_Printf(M_GetText("Found UPnP device:\n desc: %s\n st: %s\n"),
    		           dev->descURL, dev->st);
    
    		UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
    		CONS_Printf(M_GetText("Local LAN IP address: %s\n"), lanaddr);
    		descXML = miniwget(dev->descURL, &descXMLsize);
    		if (descXML)
    		{
    			parserootdesc(descXML, descXMLsize, &data);
    			free(descXML);
    			descXML = NULL;
    			memset(&urls, 0, sizeof(struct UPNPUrls));
    			memset(&data, 0, sizeof(struct IGDdatas));
    			GetUPNPUrls(&urls, &data, dev->descURL);
    			I_AddExitFunc(I_ShutdownUPnP);
    		}
    		freeUPNPDevlist(devlist);
    	}
    	else if (upnp_error == UPNPDISCOVER_SOCKET_ERROR)
    	{
    		CONS_Printf(M_GetText("No UPnP devices discovered\n"));
    	}
    }
    
    static inline void I_UPnP_add(const char * addr, const char *port, const char * servicetype)
    {
    	if (addr == NULL)
    		addr = lanaddr;
    	if (!urls.controlURL || urls.controlURL[0] == '\0')
    		return;
    	UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
    	                    port, port, addr, "SRB2", servicetype, NULL, NULL);
    }
    
    static inline void I_UPnP_rem(const char *port, const char * servicetype)
    {
    	if (!urls.controlURL || urls.controlURL[0] == '\0')
    		return;
    	UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype,
    	                       port, servicetype, NULL);
    }
    #endif
    
    static const char *SOCK_AddrToStr(mysockaddr_t *sk)
    {
    	static char s[64]; // 255.255.255.255:65535 or IPv6:65535
    #ifdef HAVE_NTOP
    	void *addr;
    
    	if(sk->any.sa_family == AF_INET)
    		addr = &sk->ip4.sin_addr;
    #ifdef HAVE_IPV6
    	else if(sk->any.sa_family == AF_INET6)
    		addr = &sk->ip6.sin6_addr;
    #endif
    	else
    		addr = NULL;
    
    	if(addr == NULL)
    		sprintf(s, "No address");
    	else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL)
    		sprintf(s, "Unknown family type, error #%u", errno);
    #ifdef HAVE_IPV6
    	else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0)
    		strcat(s, va(":%d", ntohs(sk->ip6.sin6_port)));
    #endif
    	else if(sk->any.sa_family == AF_INET  && sk->ip4.sin_port  != 0)
    		strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
    #else
    	if (sk->any.sa_family == AF_INET)
    	{
    		strcpy(s, inet_ntoa(sk->ip4.sin_addr));
    		if (sk->ip4.sin_port != 0) strcat(s, va(":%d", ntohs(sk->ip4.sin_port)));
    	}
    	else
    		sprintf(s, "Unknown type");
    #endif
    	return s;
    }
    #endif
    
    static const char *SOCK_GetNodeAddress(INT32 node)
    {
    	if (node == 0)
    		return "self";
    #ifdef NONET
    	return NULL;
    #else
    	if (!nodeconnected[node])
    		return NULL;
    	return SOCK_AddrToStr(&clientaddress[node]);
    #endif
    }
    
    static const char *SOCK_GetBanAddress(size_t ban)
    {
    	if (ban >= numbans)
    		return NULL;
    #ifdef NONET
    	return NULL;
    #else
    	return SOCK_AddrToStr(&banned[ban]);
    #endif
    }
    
    static const char *SOCK_GetBanMask(size_t ban)
    {
    #ifdef NONET
    	(void)ban;
    #else
    	static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
    	if (ban >= numbans)
    		return NULL;
    	if (sprintf(s,"%d",bannedmask[ban]) > 0)
    		return s;
    #endif
    	return NULL;
    }
    
    #ifndef NONET
    static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
    {
    	UINT32 bitmask = INADDR_NONE;
    
    	if (mask && mask < 32)
    		bitmask = htonl(-1 << (32 - mask));
    
    	if (b->any.sa_family == AF_INET)
    		return (a->ip4.sin_addr.s_addr & bitmask) == (b->ip4.sin_addr.s_addr & bitmask)
    			&& (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port));
    #ifdef HAVE_IPV6
    	else if (b->any.sa_family == AF_INET6)
    		return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr))
    			&& (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port));
    #endif
    	else
    		return false;
    }
    
    static SINT8 getfreenode(void)
    {
    	SINT8 j;
    
    	for (j = 0; j < MAXNETNODES; j++)
    		if (!nodeconnected[j])
    		{
    			nodeconnected[j] = true;
    			return j;
    		}
    	return -1;
    }
    
    // This is a hack. For some reason, nodes aren't being freed properly.
    // This goes through and cleans up what nodes were supposed to be freed.
    static void cleanupnodes(void)
    {
    	SINT8 j;
    
    	if (!Playing())
    		return;
    
    	// Why can't I start at zero?
    	for (j = 1; j < MAXNETNODES; j++)
    		if (!nodeingame[j])
    			nodeconnected[j] = false;
    }
    #endif
    
    #ifndef NONET
    static void SOCK_Get(void)
    {
    	size_t i, n;
    	int j;
    	ssize_t c;
    	mysockaddr_t fromaddress;
    	socklen_t fromlen;
    
    	for (n = 0; n < mysocketses; n++)
    	{
    		fromlen = (socklen_t)sizeof(fromaddress);
    		c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
    			(void *)&fromaddress, &fromlen);
    		if (c != ERRSOCKET)
    		{
    			// find remote node number
    			for (j = 0; j <= MAXNETNODES; j++) //include LAN
    			{
    				if (SOCK_cmpaddr(&fromaddress, &clientaddress[j], 0))
    				{
    					doomcom->remotenode = (INT16)j; // good packet from a game player
    					doomcom->datalength = (INT16)c;
    					nodesocket[j] = mysockets[n];
    					return;
    				}
    			}
    			// not found
    
    			// find a free slot
    			cleanupnodes();
    			j = getfreenode();
    			if (j > 0)
    			{
    				M_Memcpy(&clientaddress[j], &fromaddress, fromlen);
    				nodesocket[j] = mysockets[n];
    				DEBFILE(va("New node detected: node:%d address:%s\n", j,
    						SOCK_GetNodeAddress(j)));
    				doomcom->remotenode = (INT16)j; // good packet from a game player
    				doomcom->datalength = (INT16)c;
    
    				// check if it's a banned dude so we can send a refusal later
    				for (i = 0; i < numbans; i++)
    				{
    					if (SOCK_cmpaddr(&fromaddress, &banned[i], bannedmask[i]))
    					{
    						SOCK_bannednode[j] = true;
    						DEBFILE("This dude has been banned\n");
    						break;
    					}
    				}
    				if (i == numbans)
    					SOCK_bannednode[j] = false;
    				return;
    			}
    			else
    				DEBFILE("New node detected: No more free slots\n");
    
    		}
    	}
    	doomcom->remotenode = -1; // no packet
    }
    #endif
    
    // check if we can send (do not go over the buffer)
    #ifndef NONET
    
    static fd_set masterset;
    
    #ifdef SELECTTEST
    static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len)
    {
    	size_t i;
    	boolean testset = false;
    	FD_ZERO(dst);
    	for (i = 0; i < len;i++)
    	{
    		if(fd[i] != BADSOCKET && fd[i] != (SOCKET_TYPE)ERRSOCKET &&
    		   FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups
    		{
    			FD_SET(fd[i], dst);
    			testset = true;
    		}
    	}
    	return testset;
    }
    
    static boolean SOCK_CanSend(void)
    {
    	struct timeval timeval_for_select = {0, 0};
    	fd_set tset;
    	int wselect;
    
    	if(!FD_CPY(&masterset, &tset, mysockets, mysocketses))
    		return false;
    	wselect = select(255, NULL, &tset, NULL, &timeval_for_select);
    	if (wselect >= 1)
    		return true;
    	return false;
    }
    
    static boolean SOCK_CanGet(void)
    {
    	struct timeval timeval_for_select = {0, 0};
    	fd_set tset;
    	int rselect;
    
    	if(!FD_CPY(&masterset, &tset, mysockets, mysocketses))
    		return false;
    	rselect = select(255, &tset, NULL, NULL, &timeval_for_select);
    	if (rselect >= 1)
    		return true;
    	return false;
    }
    #endif
    #endif
    
    #ifndef NONET
    static void SOCK_Send(void)
    {
    	ssize_t c = ERRSOCKET;
    	socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
    #ifdef HAVE_IPV6
    	socklen_t d6 = (socklen_t)sizeof(struct sockaddr_in6);
    #endif
    	socklen_t d, da = (socklen_t)sizeof(mysockaddr_t);
    	size_t i, j;
    
    	if (!nodeconnected[doomcom->remotenode])
    		return;
    
    	if (doomcom->remotenode == BROADCASTADDR)
    	{
    		for (i = 0; i < mysocketses; i++)
    		{
    			for (j = 0; j < broadcastaddresses; j++)
    			{
    				if (myfamily[i] == broadcastaddress[j].any.sa_family)
    				{
    					if (broadcastaddress[i].any.sa_family == AF_INET)
    						d = d4;
    #ifdef HAVE_IPV6
    					else if (broadcastaddress[i].any.sa_family == AF_INET6)
    						d = d6;
    #endif
    					else
    						d = da;
    
    					c = sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0,
    						&broadcastaddress[j].any, d);
    				}
    			}
    		}
    		return;
    	}
    	else if (nodesocket[doomcom->remotenode] == BADSOCKET)
    	{
    		for (i = 0; i < mysocketses; i++)
    		{
    			if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family)
    			{
    				if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET)
    					d = d4;
    #ifdef HAVE_IPV6
    				else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
    					d = d6;
    #endif
    				else
    					d = da;
    
    				sendto(mysockets[i], (char *)&doomcom->data, doomcom->datalength, 0,
    					&clientaddress[doomcom->remotenode].any, d);
    			}
    		}
    		return;
    	}
    	else
    	{
    		if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET)
    			d = d4;
    #ifdef HAVE_IPV6
    		else if (clientaddress[doomcom->remotenode].any.sa_family == AF_INET6)
    			d = d6;
    #endif
    		else
    			d = da;
    
    		c = sendto(nodesocket[doomcom->remotenode], (char *)&doomcom->data, doomcom->datalength, 0,
    			&clientaddress[doomcom->remotenode].any, d);
    	}
    
    	if (c == ERRSOCKET && errno != ECONNREFUSED && errno != EWOULDBLOCK)
    		I_Error("SOCK_Send, error sending to node %d (%s) #%u: %s", doomcom->remotenode,
    			SOCK_GetNodeAddress(doomcom->remotenode), errno, strerror(errno));
    }
    #endif
    
    #ifndef NONET
    static void SOCK_FreeNodenum(INT32 numnode)
    {
    	// can't disconnect from self :)
    	if (!numnode || numnode > MAXNETNODES)
    		return;
    
    	DEBFILE(va("Free node %d (%s)\n", numnode, SOCK_GetNodeAddress(numnode)));
    
    	nodeconnected[numnode] = false;
    	nodesocket[numnode] = BADSOCKET;
    
    	// put invalid address
    	memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
    }
    #endif
    
    //
    // UDPsocket
    //
    #ifndef NONET
    
    // allocate a socket
    static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen)
    {
    	SOCKET_TYPE s = socket(family, SOCK_DGRAM, IPPROTO_UDP);
    	int opt;
    	socklen_t opts;
    #ifdef FIONBIO
    #ifdef WATTCP
    	char trueval = true;
    #else
    	unsigned long trueval = true;
    #endif
    #endif
    	mysockaddr_t straddr;
    
    	if (s == (SOCKET_TYPE)ERRSOCKET || s == BADSOCKET)
    		return (SOCKET_TYPE)ERRSOCKET;
    #ifdef USE_WINSOCK
    	{ // Alam_GBC: disable the new UDP connection reset behavior for Win2k and up
    #ifdef USE_WINSOCK2
    		DWORD dwBytesReturned = 0;
    		BOOL bfalse = FALSE;
    		WSAIoctl(s, SIO_UDP_CONNRESET, &bfalse, sizeof(bfalse),
    		         NULL, 0, &dwBytesReturned, NULL, NULL);
    #else
    		unsigned long falseval = false;
    		ioctl(s, SIO_UDP_CONNRESET, &falseval);
    #endif
    	}
    #endif
    
    	straddr.any = *addr;
    	I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr));
    
    	if (family == AF_INET)
    	{
    		mysockaddr_t tmpaddr;
    		tmpaddr.any = *addr ;
    		if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY))
    		{
    			opt = true;
    			opts = (socklen_t)sizeof(opt);
    			setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts);
    		}
    		// make it broadcastable
    		opt = true;
    		opts = (socklen_t)sizeof(opt);
    		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&opt, opts))
    		{
    			CONS_Alert(CONS_WARNING, M_GetText("Could not get broadcast rights\n")); // I do not care anymore
    		}
    	}
    #ifdef HAVE_IPV6
    	else if (family == AF_INET6)
    	{
    		if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL
    		{
    			opt = true;
    			opts = (socklen_t)sizeof(opt);
    			setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, opts);
    		}
    #ifdef IPV6_V6ONLY
    		// make it IPv6 ony
    		opt = true;
    		opts = (socklen_t)sizeof(opt);
    		if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts))
    		{
    			CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore
    		}
    #endif
    	}
    #endif
    
    	if (bind(s, addr, addrlen) == ERRSOCKET)
    	{
    		close(s);
    		I_OutputMsg("Binding failed\n");
    		return (SOCKET_TYPE)ERRSOCKET;
    	}
    
    #ifdef FIONBIO
    	// make it non blocking
    	opt = true;
    	if (ioctl(s, FIONBIO, &trueval) != 0)
    	{
    		close(s);
    		I_OutputMsg("Seting FIOBIO on failed\n");
    		return (SOCKET_TYPE)ERRSOCKET;
    	}
    #endif
    
    	opts = (socklen_t)sizeof(opt);
    	getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts);
    	CONS_Printf(M_GetText("Network system buffer: %dKb\n"), opt>>10);
    
    	if (opt < 64<<10) // 64k
    	{
    		opt = 64<<10;
    		opts = (socklen_t)sizeof(opt);
    		setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, opts);
    		getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&opt, &opts);
    		if (opt < 64<<10)
    			CONS_Alert(CONS_WARNING, M_GetText("Can't set buffer length to 64k, file transfer will be bad\n"));
    		else
    			CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10);
    	}
    
    	return s;
    }
    
    static boolean UDP_Socket(void)
    {
    	const char *sock_port = NULL;
    	size_t s;
    	struct my_addrinfo *ai, *runp, hints;
    	int gaie;
    #ifdef HAVE_IPV6
    	const INT32 b_ipv6 = M_CheckParm("-ipv6");
    #endif
    
    
    	for (s = 0; s < mysocketses; s++)
    		mysockets[s] = BADSOCKET;
    	for (s = 0; s < MAXNETNODES+1; s++)
    		nodesocket[s] = BADSOCKET;
    	FD_ZERO(&masterset);
    	s = 0;
    
    	memset(&hints, 0x00, sizeof (hints));
    	hints.ai_flags = AI_NUMERICHOST;
    	hints.ai_family = AF_INET;
    	hints.ai_socktype = SOCK_DGRAM;
    	hints.ai_protocol = IPPROTO_UDP;
    
    	if (M_CheckParm("-clientport"))
    	{
    		if (!M_IsNextParm())
    			I_Error("syntax: -clientport <portnum>");
    		sock_port = M_GetNextParm();
    	}
    	else
    		sock_port = port_name;
    
    	if (M_CheckParm("-bindaddr"))
    	{
    		while (M_IsNextParm())
    		{
    			gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai);
    			if (gaie == 0)
    			{
    				runp = ai;
    				while (runp != NULL && s < MAXNETNODES+1)
    				{
    					mysockets[s] = UDP_Bind(runp->ai_family, runp->ai_addr, (socklen_t)runp->ai_addrlen);
    					if (mysockets[s] != (SOCKET_TYPE)ERRSOCKET)
    					{
    						FD_SET(mysockets[s], &masterset);
    						myfamily[s] = hints.ai_family;
    						s++;
    					}
    					runp = runp->ai_next;
    				}
    				I_freeaddrinfo(ai);
    			}
    		}
    	}
    	else
    	{
    		gaie = I_getaddrinfo("0.0.0.0", sock_port, &hints, &ai);
    		if (gaie == 0)
    		{
    			runp = ai;
    			while (runp != NULL && s < MAXNETNODES+1)
    			{
    				mysockets[s] = UDP_Bind(runp->ai_family, runp->ai_addr, (socklen_t)runp->ai_addrlen);
    				if (mysockets[s] != (SOCKET_TYPE)ERRSOCKET)
    				{
    					FD_SET(mysockets[s], &masterset);
    					myfamily[s] = hints.ai_family;
    					s++;
    #ifdef HAVE_MINIUPNPC
    					if (UPNP_support)
    					{
    						I_UPnP_rem(sock_port, "UDP");
    						I_UPnP_add(NULL, sock_port, "UDP");
    					}
    #endif
    				}
    				runp = runp->ai_next;
    			}
    			I_freeaddrinfo(ai);
    		}
    	}
    #ifdef HAVE_IPV6
    	if (b_ipv6)
    	{
    		hints.ai_family = AF_INET6;
    		if (M_CheckParm("-bindaddr6"))
    		{
    			while (M_IsNextParm())
    			{
    				gaie = I_getaddrinfo(M_GetNextParm(), sock_port, &hints, &ai);
    				if (gaie == 0)
    				{
    					runp = ai;
    					while (runp != NULL && s < MAXNETNODES+1)
    					{
    						mysockets[s] = UDP_Bind(runp->ai_family, runp->ai_addr, (socklen_t)runp->ai_addrlen);
    						if (mysockets[s] != (SOCKET_TYPE)ERRSOCKET)
    						{
    							FD_SET(mysockets[s], &masterset);
    							myfamily[s] = hints.ai_family;
    							s++;
    						}
    						runp = runp->ai_next;
    					}
    					I_freeaddrinfo(ai);
    				}
    			}
    		}
    		else
    		{
    			gaie = I_getaddrinfo("::", sock_port, &hints, &ai);
    			if (gaie == 0)
    			{
    				runp = ai;
    				while (runp != NULL && s < MAXNETNODES+1)
    				{
    					mysockets[s] = UDP_Bind(runp->ai_family, runp->ai_addr, (socklen_t)runp->ai_addrlen);
    					if (mysockets[s] != (SOCKET_TYPE)ERRSOCKET)
    					{
    						FD_SET(mysockets[s], &masterset);
    						myfamily[s] = hints.ai_family;
    						s++;
    					}
    					runp = runp->ai_next;
    				}
    				I_freeaddrinfo(ai);
    			}
    		}
    	}
    #endif
    
    	mysocketses = s;
    	if (s == 0) // no sockets?
    		return false;
    
    	s = 0;
    
    	// ip + udp
    	packetheaderlength = 20 + 8; // for stats
    
    	hints.ai_family = AF_INET;
    	gaie = I_getaddrinfo("127.0.0.1", "0", &hints, &ai);
    	if (gaie == 0)
    	{
    		runp = ai;
    		while (runp != NULL)
    		{
    			memcpy(&clientaddress[s], runp->ai_addr, runp->ai_addrlen);
    			s++;
    			runp = runp->ai_next;
    		}
    		I_freeaddrinfo(ai);
    	}
    	else
    	{
    		clientaddress[s].any.sa_family = AF_INET;
    		clientaddress[s].ip4.sin_port = htons(0);
    		clientaddress[s].ip4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //GetLocalAddress(); // my own ip
    		s++;
    	}
    	// setup broadcast adress to BROADCASTADDR entry
    	gaie = I_getaddrinfo("255.255.255.255", "0", &hints, &ai);
    	if (gaie == 0)
    	{
    		runp = ai;
    		while (runp != NULL)
    		{
    			memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen);
    			s++;
    			runp = runp->ai_next;
    		}
    		I_freeaddrinfo(ai);
    	}
    	else
    	{
    		broadcastaddress[s].any.sa_family = AF_INET;
    		broadcastaddress[s].ip4.sin_port = htons(0);
    		broadcastaddress[s].ip4.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    		s++;
    	}
    #ifdef HAVE_IPV6
    	if (b_ipv6)
    	{
    		hints.ai_family = AF_INET6;
    		gaie = I_getaddrinfo("ff02::1", "0", &hints, &ai);
    		if (gaie == 0)
    		{
    			runp = ai;
    			while (runp != NULL)
    			{
    				memcpy(&broadcastaddress[s], runp->ai_addr, runp->ai_addrlen);
    				s++;
    				runp = runp->ai_next;
    			}
    			I_freeaddrinfo(ai);
    		}
    	}
    #endif
    
    	broadcastaddresses = s;
    
    	doomcom->extratics = 1; // internet is very high ping
    
    	return true;
    }
    #endif
    
    boolean I_InitTcpDriver(void)
    {
    	boolean tcp_was_up = init_tcp_driver;
    #ifndef NONET
    	if (!init_tcp_driver)
    	{
    #ifdef USE_WINSOCK
    #ifdef USE_WINSOCK2
    		const WORD VerNeed = MAKEWORD(2,2);
    #else
    		const WORD VerNeed = MAKEWORD(1,1);
    #endif
    		WSADATA WSAData;
    		const int WSAresult = WSAStartup(VerNeed, &WSAData);
    		if (WSAresult != 0)
    		{
    			LPCSTR WSError = NULL;
    			switch (WSAresult)
    			{
    				case WSASYSNOTREADY:
    					WSError = "The underlying network subsystem is not ready for network communication";
    					break;
    				case WSAEINPROGRESS:
    					WSError = "A blocking Windows Sockets 1.1 operation is in progress";
    					break;
    				case WSAEPROCLIM:
    					WSError = "Limit on the number of tasks supported by the Windows Sockets implementation has been reached";
    					break;
    				case WSAEFAULT:
    					WSError = "WSAData is not a valid pointer? What kind of setup do you have?";
    					break;
    				default:
    					WSError = va("Error code %u",WSAresult);
    					break;
    			}
    			if (WSAresult != WSAVERNOTSUPPORTED)
    				CONS_Debug(DBG_NETPLAY, "WinSock(TCP/IP) error: %s\n",WSError);
    		}
    #ifdef USE_WINSOCK2
    		if(LOBYTE(WSAData.wVersion) != 2 ||
    			HIBYTE(WSAData.wVersion) != 2)
    		{
    			WSACleanup();
    			CONS_Debug(DBG_NETPLAY, "No WinSock(TCP/IP) 2.2 driver detected\n");
    		}
    #else
    		if (LOBYTE(WSAData.wVersion) != 1 ||
    			HIBYTE(WSAData.wVersion) != 1)
    		{
    			WSACleanup();
    			CONS_Debug(DBG_NETPLAY, "No WinSock(TCP/IP) 1.1 driver detected\n");
    		}
    #endif
    		CONS_Debug(DBG_NETPLAY, "WinSock description: %s\n",WSAData.szDescription);
    		CONS_Debug(DBG_NETPLAY, "WinSock System Status: %s\n",WSAData.szSystemStatus);
    #endif
    #ifdef HAVE_LWIP
    		lwip_kos_init();
    #elif defined(_arch_dreamcast)
    		//return;
    		net_init();
    #endif
    #ifdef __DJGPP__
    #ifdef WATTCP // Alam_GBC: survive bootp, dhcp, rarp and wattcp/pktdrv from failing to load
    		survive_eth   = 1; // would be needed to not exit if pkt_eth_init() fails
    		survive_bootp = 1; // ditto for BOOTP
    		survive_dhcp  = 1; // ditto for DHCP/RARP
    		survive_rarp  = 1;
    		//_watt_do_exit = false;
    		//_watt_handle_cbreak = false;
    		//_watt_no_config = true;
    		_outch = wattcp_outch;
    		init_misc();
    //#ifdef DEBUGFILE
    		dbug_init();
    //#endif
    		switch (sock_init())
    		{
    			case 0:
    				init_tcp_driver = true;
    				break;
    			case 3:
    				CONS_Debug(DBG_NETPLAY, "No packet driver detected\n");
    				break;
    			case 4:
    				CONS_Debug(DBG_NETPLAY, "Error while talking to packet driver\n");
    				break;
    			case 5:
    				CONS_Debug(DBG_NETPLAY, "BOOTP failed\n");
    				break;
    			case 6:
    				CONS_Debug(DBG_NETPLAY, "DHCP failed\n");
    				break;
    			case 7:
    				CONS_Debug(DBG_NETPLAY, "RARP failed\n");
    				break;
    			case 8:
    				CONS_Debug(DBG_NETPLAY, "TCP/IP failed\n");
    				break;
    			case 9:
    				CONS_Debug(DBG_NETPLAY, "PPPoE login/discovery failed\n");
    				break;
    			default:
    				CONS_Debug(DBG_NETPLAY, "Unknown error with TCP/IP stack\n");
    				break;
    		}
    		hires_timer(0);
    #else // wattcp
    		if (__lsck_init())
    			init_tcp_driver = true;
    		else
    			CONS_Debug(DBG_NETPLAY, "No TCP/IP driver detected\n");
    #endif // libsocket
    #endif // __DJGPP__
    #ifdef _PS3
    		netInitialize();
    #endif
    #ifndef __DJGPP__
    		init_tcp_driver = true;
    #endif
    	}
    #endif
    	if (!tcp_was_up && init_tcp_driver)
    	{
    		I_AddExitFunc(I_ShutdownTcpDriver);
    #ifdef HAVE_MINIUPNPC
    		if (M_CheckParm("-useUPnP"))
    			I_InitUPnP();
    		else
    			UPNP_support = false;
    #endif
    	}
    	return init_tcp_driver;
    }
    
    #ifndef NONET
    static void SOCK_CloseSocket(void)
    {
    	size_t i;
    	for (i=0; i < MAXNETNODES+1; i++)
    	{
    		if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET
    		 && mysockets[i] != BADSOCKET
    		 && FD_ISSET(mysockets[i], &masterset))
    		{
    #if !defined (__DJGPP__) || defined (WATTCP)
    			FD_CLR(mysockets[i], &masterset);
    			close(mysockets[i]);
    #endif
    		}
    		mysockets[i] = BADSOCKET;
    	}
    }
    #endif
    
    void I_ShutdownTcpDriver(void)
    {
    #ifndef NONET
    	SOCK_CloseSocket();
    
    	CONS_Printf("I_ShutdownTcpDriver: ");
    #ifdef USE_WINSOCK
    	WS_addrinfocleanup();
    	WSACleanup();
    #endif
    #ifdef HAVE_LWIP
    	lwip_kos_shutdown();
    #elif defined(_arch_dreamcast)
    	net_shutdown();
    #endif
    #ifdef __DJGPP__
    #ifdef WATTCP // wattcp
    	//_outch = NULL;
    	sock_exit();
    #else
    	__lsck_uninit();
    #endif // libsocket
    #endif // __DJGPP__
    #ifdef _PS3
    	netDeinitialize();
    #endif
    	CONS_Printf("shut down\n");
    	init_tcp_driver = false;
    #endif
    }
    
    #ifndef NONET
    static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
    {
    	SINT8 newnode = -1;
    	struct my_addrinfo *ai, *runp, hints;
    	int gaie;
    
    	 if (!port || !port[0])
    		port = port_name;
    
    	DEBFILE(va("Creating new node: %s@%s\n", address, port));
    
    	memset (&hints, 0x00, sizeof (hints));
    	hints.ai_flags = 0;
    	hints.ai_family = AF_UNSPEC;
    	hints.ai_socktype = SOCK_DGRAM;
    	hints.ai_protocol = IPPROTO_UDP;
    
    	gaie = I_getaddrinfo(address, port, &hints, &ai);
    	if (gaie == 0)
    	{
    		cleanupnodes();
    		newnode = getfreenode();
    	}
    	if (newnode == -1)
    	{
    		I_freeaddrinfo(ai);
    		return -1;
    	}
    	else
    		runp = ai;
    
    	while (runp != NULL)
    	{
    		// find ip of the server
    		memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen);
    		runp = NULL;
    	}
    	I_freeaddrinfo(ai);
    	return newnode;
    }
    #endif
    
    static boolean SOCK_OpenSocket(void)
    {
    #ifndef NONET
    	size_t i;
    
    	memset(clientaddress, 0, sizeof (clientaddress));
    
    	nodeconnected[0] = true; // always connected to self
    	for (i = 1; i < MAXNETNODES; i++)
    		nodeconnected[i] = false;
    	nodeconnected[BROADCASTADDR] = true;
    	I_NetSend = SOCK_Send;
    	I_NetGet = SOCK_Get;
    	I_NetCloseSocket = SOCK_CloseSocket;
    	I_NetFreeNodenum = SOCK_FreeNodenum;
    	I_NetMakeNodewPort = SOCK_NetMakeNodewPort;
    
    #ifdef SELECTTEST
    	// seem like not work with libsocket : (
    	I_NetCanSend = SOCK_CanSend;
    	I_NetCanGet = SOCK_CanGet;
    #endif
    
    	// build the socket but close it first
    	SOCK_CloseSocket();
    	return UDP_Socket();
    #else
    	return false;
    #endif
    }
    
    static boolean SOCK_Ban(INT32 node)
    {
    	if (node > MAXNETNODES)
    		return false;
    #ifdef NONET
    	return false;
    #else
    	if (numbans == MAXBANS)
    		return false;
    
    	M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (mysockaddr_t));
    	if (banned[numbans].any.sa_family == AF_INET)
    	{
    		banned[numbans].ip4.sin_port = 0;
    		bannedmask[numbans] = 32;
    	}
    #ifdef HAVE_IPV6
    	else if (banned[numbans].any.sa_family == AF_INET6)
    	{
    		banned[numbans].ip6.sin6_port = 0;
    		bannedmask[numbans] = 128;
    	}
    #endif
    	numbans++;
    	return true;
    #endif
    }
    
    static boolean SOCK_SetBanAddress(const char *address, const char *mask)
    {
    #ifdef NONET
    	(void)address;
    	(void)mask;
    	return false;
    #else
    	struct my_addrinfo *ai, *runp, hints;
    	int gaie;
    
    	if (numbans == MAXBANS || !address)
    		return false;
    
    	memset(&hints, 0x00, sizeof(hints));
    	hints.ai_flags = 0;
    	hints.ai_family = AF_UNSPEC;
    	hints.ai_socktype = SOCK_DGRAM;
    	hints.ai_protocol = IPPROTO_UDP;
    
    	gaie = I_getaddrinfo(address, "0", &hints, &ai);
    	if (gaie != 0)
    		return false;
    
    	runp = ai;
    
    	while(runp != NULL && numbans != MAXBANS)
    	{
    		memcpy(&banned[numbans], runp->ai_addr, runp->ai_addrlen);
    
    		if (mask)
    			bannedmask[numbans] = (UINT8)atoi(mask);
    #ifdef HAVE_IPV6
    		else if (runp->ai_family == AF_INET6)
    			bannedmask[numbans] = 128;
    #endif
    		else
    			bannedmask[numbans] = 32;
    
    		if (bannedmask[numbans] > 32 && runp->ai_family == AF_INET)
    			bannedmask[numbans] = 32;
    #ifdef HAVE_IPV6
    		else if (bannedmask[numbans] > 128 && runp->ai_family == AF_INET6)
    			bannedmask[numbans] = 128;
    #endif
    		numbans++;
    		runp = runp->ai_next;
    	}
    
    	I_freeaddrinfo(ai);
    
    	return true;
    #endif
    }
    
    static void SOCK_ClearBans(void)
    {
    	numbans = 0;
    }
    
    boolean I_InitTcpNetwork(void)
    {
    	char serverhostname[255];
    	boolean ret = false;
    	// initilize the OS's TCP/IP stack
    	if (!I_InitTcpDriver())
    		return false;
    
    	if (M_CheckParm("-udpport"))
    	{
    		if (M_IsNextParm())
    			strcpy(port_name, M_GetNextParm());
    		else
    			strcpy(port_name, "0");
    	}
    	current_port = (UINT16)atoi(port_name);
    
    	// parse network game options,
    	if (M_CheckParm("-server") || dedicated)
    	{
    		server = true;
    
    		// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
    		// to connect before starting.
    		// If no number is specified here, the server starts with 1 client, and others can join
    		// in-game.
    		// Since Boris has implemented join in-game, there is no actual need for specifying a
    		// particular number here.
    		// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
    		if (dedicated)
    			doomcom->numnodes = 0;
    /*		else if (M_IsNextParm())
    			doomcom->numnodes = (INT16)atoi(M_GetNextParm());*/
    		else
    			doomcom->numnodes = 1;
    
    		if (doomcom->numnodes < 0)
    			doomcom->numnodes = 0;
    		if (doomcom->numnodes > MAXNETNODES)
    			doomcom->numnodes = MAXNETNODES;
    
    		// server
    		servernode = 0;
    		// FIXME:
    		// ??? and now ?
    		// server on a big modem ??? 4*isdn
    		net_bandwidth = 16000;
    		hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
    
    		ret = true;
    	}
    	else if (M_CheckParm("-connect"))
    	{
    		if (M_IsNextParm())
    			strcpy(serverhostname, M_GetNextParm());
    		else
    			serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
    
    		// server address only in ip
    		if (serverhostname[0])
    		{
    			COM_BufAddText("connect \"");
    			COM_BufAddText(serverhostname);
    			COM_BufAddText("\"\n");
    
    			// probably modem
    			hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
    		}
    		else
    		{
    			// so we're on a LAN
    			COM_BufAddText("connect any\n");
    
    			net_bandwidth = 800000;
    			hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
    		}
    	}
    
    	I_NetOpenSocket = SOCK_OpenSocket;
    	I_Ban = SOCK_Ban;
    	I_ClearBans = SOCK_ClearBans;
    	I_GetNodeAddress = SOCK_GetNodeAddress;
    	I_GetBanAddress = SOCK_GetBanAddress;
    	I_GetBanMask = SOCK_GetBanMask;
    	I_SetBanAddress = SOCK_SetBanAddress;
    	bannednode = SOCK_bannednode;
    
    	return ret;
    }
    
    #include "i_addrinfo.c"