fteqw/engine/common/net_wins.c
Spoike 9ae7e2621d SOFTWARE RENDERING IS BROKEN: DO NOT USE ASM VERSION.
Lots of changes.
CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit.
Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit.
Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
2005-02-28 07:16:19 +00:00

1275 lines
28 KiB
C

/*
Copyright (C) 1996-1997 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_wins.c
struct sockaddr;
#include "quakedef.h"
#ifdef _WIN32
#ifdef _MSC_VER
#define USEIPX
#endif
#include "winquake.h"
#ifdef USEIPX
#include "wsipx.h"
#endif
#ifdef IPPROTO_IPV6
#include "ws2tcpip.h"
#endif
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EMSGSIZE WSAEMSGSIZE
#define ECONNRESET WSAECONNRESET
#define ECONNABORTED WSAECONNABORTED
#define ECONNREFUSED WSAECONNREFUSED
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#ifdef sun
#include <sys/filio.h>
#endif
#ifdef NeXT
#include <libc.h>
#endif
#define closesocket close
#define ioctlsocket ioctl
#endif
#ifdef _WIN32
#define qerrno WSAGetLastError() //windows errors are retrieved via WSAGetLastError
#else
#define qerrno errno //linux and single threaded oses are happy with errno as a global
#endif
netadr_t net_local_ipadr;
netadr_t net_local_ip6adr;
netadr_t net_from;
sizebuf_t net_message;
//#define MAX_UDP_PACKET (MAX_MSGLEN*2) // one more than msg + header
#define MAX_UDP_PACKET 8192 // one more than msg + header
qbyte net_message_buffer[MAX_UDP_PACKET];
#ifdef _WIN32
WSADATA winsockdata;
#endif
#ifdef IPPROTO_IPV6
#ifdef _WIN32
int (WINAPI *pgetaddrinfo) (
const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res
);
void (WSAAPI *pfreeaddrinfo) (struct addrinfo*);
#else
#define pgetaddrinfo getaddrinfo
#define pfreeaddrinfo freeaddrinfo
/*int (*pgetaddrinfo)
(
const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res
);
void (*pfreeaddrinfo) (struct addrinfo*);
*/
#endif
#endif
extern cvar_t sv_public;
#define MAX_LOOPBACK 4
typedef struct
{
qbyte data[MAX_UDP_PACKET];
int datalen;
} loopmsg_t;
typedef struct
{
loopmsg_t msgs[MAX_LOOPBACK];
int get, send;
} loopback_t;
loopback_t loopbacks[2];
//=============================================================================
void NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s)
{
switch(a->type)
{
case NA_BROADCAST_IP:
memset (s, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in*)s)->sin_family = AF_INET;
*(int *)&((struct sockaddr_in*)s)->sin_addr = INADDR_BROADCAST;
((struct sockaddr_in*)s)->sin_port = a->port;
break;
case NA_IP:
memset (s, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in*)s)->sin_family = AF_INET;
*(int *)&((struct sockaddr_in*)s)->sin_addr = *(int *)&a->ip;
((struct sockaddr_in*)s)->sin_port = a->port;
break;
#ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6:
memset (s, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in6*)s)->sin6_family = AF_INET6;
memset((int *)&((struct sockaddr_in6*)s)->sin6_addr, 0, sizeof(*(int *)&((struct sockaddr_in6*)s)->sin6_addr));
((struct sockaddr_in6*)s)->sin6_addr.s6_addr[0] = 0xff;
((struct sockaddr_in6*)s)->sin6_addr.s6_addr[1] = 0x02;
((struct sockaddr_in6*)s)->sin6_addr.s6_addr[15] = 0x01;
((struct sockaddr_in6*)s)->sin6_port = a->port;
break;
case NA_IPV6:
memset (s, 0, sizeof(struct sockaddr_in));
((struct sockaddr_in6*)s)->sin6_family = AF_INET6;
memcpy(&((struct sockaddr_in6*)s)->sin6_addr, 0, sizeof(struct in6_addr));
((struct sockaddr_in6*)s)->sin6_port = a->port;
break;
#endif
#ifdef USEIPX
case NA_IPX:
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
((struct sockaddr_ipx *)s)->sa_socket = a->port;
break;
case NA_BROADCAST_IPX:
memset (s, 0, sizeof(struct sockaddr_ipx));
((struct sockaddr_ipx*)s)->sa_family = AF_IPX;
memset(&((struct sockaddr_ipx*)s)->sa_netnum, 0, 4);
memset(&((struct sockaddr_ipx*)s)->sa_nodenum, 0xff, 6);
((struct sockaddr_ipx*)s)->sa_socket = a->port;
break;
#endif
default:
Sys_Error("Bad type - needs fixing");
}
}
void SockadrToNetadr (struct sockaddr_qstorage *s, netadr_t *a)
{
switch (((struct sockaddr*)s)->sa_family)
{
case AF_INET:
a->type = NA_IP;
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
a->port = ((struct sockaddr_in *)s)->sin_port;
break;
#ifdef IPPROTO_IPV6
case AF_INET6:
a->type = NA_IPV6;
memcpy((struct sockaddr_in6 *)&a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(struct sockaddr_in6));
a->port = ((struct sockaddr_in6 *)s)->sin6_port;
break;
#endif
#ifdef USEIPX
case AF_IPX:
a->type = NA_IPX;
*(int *)a->ip = 0xffffffff;
memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
a->port = ((struct sockaddr_ipx *)s)->sa_socket;
break;
#endif
case AF_UNSPEC:
memset(a, 0, sizeof(*a));
a->type = NA_INVALID;
break;
default:
Sys_Error("SockadrToNetadr: bad socket family");
}
}
qboolean NET_CompareAdr (netadr_t a, netadr_t b)
{
if (a.type != b.type)
return false;
if (a.type == NA_LOOPBACK)
return true;
if (a.type == NA_IP || a.type == NA_BROADCAST_IP)
{
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
return true;
return false;
}
#ifdef IPPROTO_IPV6
if (a.type == NA_IPV6 || a.type == NA_BROADCAST_IP6)
{
if ((memcmp(a.ip6, b.ip6, 16) == 0) && a.port == b.port)
return true;
return false;
}
#endif
if (a.type == NA_IPX || a.type == NA_BROADCAST_IPX)
{
if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
return true;
return false;
}
Sys_Error("NET_CompareAdr: Bad address type");
return false;
}
/*
===================
NET_CompareBaseAdr
Compares without the port
===================
*/
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
{
if (a.type != b.type)
return false;
if (a.type == NA_LOOPBACK)
return true;
if (a.type == NA_IP)
{
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
return true;
return false;
}
#ifdef IPPROTO_IPV6
if (a.type == NA_IPV6 || a.type == NA_BROADCAST_IP6)
{
if ((memcmp(a.ip6, b.ip6, 16) == 0))
return true;
return false;
}
#endif
if (a.type == NA_IPX)
{
if ((memcmp(a.ipx, b.ipx, 10) == 0))
return true;
return false;
}
Sys_Error("NET_CompareBaseAdr: Bad address type");
return false;
}
char *NET_AdrToString (netadr_t a)
{
static char s[64];
switch(a.type)
{
case NA_BROADCAST_IP:
case NA_IP:
sprintf (s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
break;
#ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6:
case NA_IPV6:
sprintf (s, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%i", a.ip6[0], a.ip6[1], a.ip6[2], a.ip6[3], a.ip6[4], a.ip6[5], a.ip6[6], a.ip6[7], a.ip6[8], a.ip6[9], a.ip6[10], a.ip6[11], a.ip6[12], a.ip6[13], a.ip6[14], a.ip6[15], ntohs(a.port));
break;
#endif
#ifdef USEIPX
case NA_BROADCAST_IPX:
case NA_IPX:
sprintf (s, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
break;
#endif
case NA_LOOPBACK:
sprintf (s, "LocalHost");
break;
default:
sprintf (s, "invalid netadr_t type");
// Sys_Error("NET_AdrToString: Bad netadr_t type");
}
return s;
}
char *NET_BaseAdrToString (netadr_t a)
{
static char s[64];
switch(a.type)
{
case NA_BROADCAST_IP:
case NA_IP:
sprintf (s, "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
break;
#ifdef IPPROTO_IPV6
case NA_BROADCAST_IP6:
case NA_IPV6:
sprintf (s, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a.ip6[0], a.ip6[1], a.ip6[2], a.ip6[3], a.ip6[4], a.ip6[5], a.ip6[6], a.ip6[7], a.ip6[8], a.ip6[9], a.ip6[10], a.ip6[11], a.ip6[12], a.ip6[13], a.ip6[14], a.ip6[15]);
break;
#endif
#ifdef USEIPX
case NA_BROADCAST_IPX:
case NA_IPX:
sprintf (s, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9]);
break;
#endif
case NA_LOOPBACK:
sprintf (s, "LocalHost");
break;
default:
Sys_Error("NET_BaseAdrToString: Bad netadr_t type");
}
return s;
}
/*
=============
NET_StringToAdr
idnewt
idnewt:28000
192.246.40.70
192.246.40.70:28000
any form of ipv6, including port number.
=============
*/
#define DO(src,dest) \
copy[0] = s[src]; \
copy[1] = s[src + 1]; \
sscanf (copy, "%x", &val); \
((struct sockaddr_ipx *)sadr)->dest = val
qboolean NET_StringToSockaddr (char *s, struct sockaddr_qstorage *sadr)
{
struct hostent *h;
char *colon;
char copy[128];
memset (sadr, 0, sizeof(*sadr));
#ifdef USEIPX
if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':')) // check for an IPX address
{
unsigned int val;
((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
copy[2] = 0;
DO(0, sa_netnum[0]);
DO(2, sa_netnum[1]);
DO(4, sa_netnum[2]);
DO(6, sa_netnum[3]);
DO(9, sa_nodenum[0]);
DO(11, sa_nodenum[1]);
DO(13, sa_nodenum[2]);
DO(15, sa_nodenum[3]);
DO(17, sa_nodenum[4]);
DO(19, sa_nodenum[5]);
sscanf (&s[22], "%u", &val);
((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
}
else
#endif
#ifdef IPPROTO_IPV6
if (pgetaddrinfo)
{
struct addrinfo *addrinfo, *pos;
struct addrinfo udp6hint;
int error;
char *port;
char dupbase[256];
int len;
memset(&udp6hint, 0, sizeof(udp6hint));
udp6hint.ai_family = 0;//Any... AF_INET6;
udp6hint.ai_socktype = SOCK_DGRAM;
udp6hint.ai_protocol = IPPROTO_UDP;
port = s + strlen(s);
while(port >= s)
{
if (*port == ':')
break;
port--;
}
if (port == s)
port = NULL;
if (port)
{
len = port - s;
if (len >= sizeof(dupbase))
len = sizeof(dupbase)-1;
strncpy(dupbase, s, len);
dupbase[len] = '\0';
error = pgetaddrinfo(dupbase, port+1, &udp6hint, &addrinfo);
}
else
error = EAI_NONAME;
if (error) //failed, try string with no port.
error = pgetaddrinfo(s, NULL, &udp6hint, &addrinfo); //remember, this func will return any address family that could be using the udp protocol... (ip4 or ip6)
if (error)
{
return false;
}
((struct sockaddr*)sadr)->sa_family = 0;
for (pos = addrinfo; pos; pos = pos->ai_next)
{
switch(pos->ai_family)
{
case AF_INET6:
if (((struct sockaddr_in *)sadr)->sin_family == AF_INET6)
break; //first one should be best...
case AF_INET:
memcpy(sadr, addrinfo->ai_addr, addrinfo->ai_addrlen);
if (pos->ai_family == AF_INET)
goto dblbreak; //don't try finding any more, this is quake, they probably prefer ip4...
break;
}
}
dblbreak:
pfreeaddrinfo (addrinfo);
if (!((struct sockaddr*)sadr)->sa_family)
return false;
}
else
#endif
{
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
((struct sockaddr_in *)sadr)->sin_port = 0;
strcpy (copy, s);
// strip off a trailing :port if present
for (colon = copy ; *colon ; colon++)
if (*colon == ':')
{
*colon = 0;
((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
}
if (copy[0] >= '0' && copy[0] <= '9') //this is the wrong way to test. a server name may start with a number.
{
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
}
else
{
if (! (h = gethostbyname(copy)) )
return 0;
if (h->h_addrtype != AF_INET)
return 0;
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
}
}
return true;
}
#undef DO
qboolean NET_StringToAdr (char *s, netadr_t *a)
{
struct sockaddr_qstorage sadr;
if (!strcmp (s, "internalserver"))
{
memset (a, 0, sizeof(*a));
a->type = NA_LOOPBACK;
return true;
}
if (!NET_StringToSockaddr (s, &sadr))
return false;
SockadrToNetadr (&sadr, a);
return true;
}
// Returns true if we can't bind the address locally--in other words,
// the IP is NOT one of our interfaces.
qboolean NET_IsClientLegal(netadr_t *adr)
{
#if 0
struct sockaddr_in sadr;
int newsocket;
if (adr->ip[0] == 127)
return false; // no local connections period
NetadrToSockadr (adr, &sadr);
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
Sys_Error ("NET_IsClientLegal: socket:", strerror(qerrno));
sadr.sin_port = 0;
if( bind (newsocket, (void *)&sadr, sizeof(sadr)) == -1)
{
// It is not a local address
close(newsocket);
return true;
}
close(newsocket);
return false;
#else
return true;
#endif
}
qboolean NET_IsLoopBackAddress (netadr_t adr)
{
// return (!strcmp(cls.servername, NET_AdrToString(net_local_adr)) || !strcmp(cls.servername, "local");
return adr.type == NA_LOOPBACK;
}
/////////////////////////////////////////////
//loopback stuff
qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *from, sizebuf_t *message)
{
int i;
loopback_t *loop;
loop = &loopbacks[sock];
if (loop->send - loop->get > MAX_LOOPBACK)
loop->get = loop->send - MAX_LOOPBACK;
if (loop->get >= loop->send)
return false;
i = loop->get & (MAX_LOOPBACK-1);
loop->get++;
if (message->maxsize < loop->msgs[i].datalen)
Sys_Error("NET_SendLoopPacket: Loopback buffer was too big");
memcpy (message->data, loop->msgs[i].data, loop->msgs[i].datalen);
message->cursize = loop->msgs[i].datalen;
memset (from, 0, sizeof(*from));
from->type = NA_LOOPBACK;
message->packing = SZ_RAWBYTES;
message->currentbit = 0;
return true;
}
void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
{
int i;
loopback_t *loop;
loop = &loopbacks[sock^1];
i = loop->send & (MAX_LOOPBACK-1);
loop->send++;
if (length > sizeof(loop->msgs[i].data))
Sys_Error("NET_SendLoopPacket: Loopback buffer is too small");
memcpy (loop->msgs[i].data, data, length);
loop->msgs[i].datalen = length;
}
//=============================================================================
qboolean NET_GetPacket (netsrc_t netsrc)
{
int ret;
struct sockaddr_qstorage from;
int fromlen;
int i;
int socket;
if (NET_GetLoopPacket(netsrc, &net_from, &net_message))
return true;
for (i = 0; i < 3; i++)
{
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_GetPacket: Bad netsrc");
socket = 0;
#else
if (i == 0)
socket = svs.socketip;
else if (i == 1)
socket = svs.socketip6;
else
socket = svs.socketipx;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_GetPacket: Bad netsrc");
socket = 0;
#else
if (i == 0)
socket = cls.socketip;
else if (i == 1)
socket = cls.socketip6;
else
socket = cls.socketipx;
#endif
}
if (!socket)
continue;
fromlen = sizeof(from);
ret = recvfrom (socket, (char *)net_message_buffer, sizeof(net_message_buffer), 0, (struct sockaddr*)&from, &fromlen);
if (ret == -1)
{
if (qerrno == EWOULDBLOCK)
continue;
if (qerrno == EMSGSIZE)
{
SockadrToNetadr (&from, &net_from);
Con_TPrintf (TL_OVERSIZEPACKETFROM,
NET_AdrToString (net_from));
continue;
}
if (qerrno == ECONNABORTED || qerrno == ECONNRESET)
{
Con_TPrintf (TL_CONNECTIONLOSTORABORTED); //server died/connection lost.
#ifndef SERVERONLY
if (cls.state != ca_disconnected && netsrc == NS_CLIENT)
{
if (cls.lastarbiatarypackettime+5 < Sys_DoubleTime()) //too many mvdsv
Cbuf_AddText("disconnect\nreconnect\n", RESTRICT_LOCAL); //retry connecting.
else
Con_Printf("Packet was not delivered - server might be badly configured\n");
break;
}
#endif
continue;
}
Con_TPrintf (TL_NETGETPACKETERROR, strerror(qerrno));
continue;
}
SockadrToNetadr (&from, &net_from);
net_message.packing = SZ_RAWBYTES;
net_message.currentbit = 0;
net_message.cursize = ret;
if (net_message.cursize == sizeof(net_message_buffer) )
{
Con_TPrintf (TL_OVERSIZEPACKETFROM, NET_AdrToString (net_from));
return false;
}
return ret;
}
return false;
}
//=============================================================================
void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t to)
{
int ret;
struct sockaddr_qstorage addr;
int socket;
if (to.type == NA_LOOPBACK)
{
// if (Cvar_Get("drop", "0", 0, "network debugging")->value)
// if ((rand()&15)==15) //simulate PL
// return;
NET_SendLoopPacket(netsrc, length, data, to);
return;
}
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_SendPacket: bad netsrc");
socket = 0;
#else
#ifdef USEIPX
if (to.type == NA_BROADCAST_IPX || to.type == NA_IPX)
socket = svs.socketipx;
else
#endif
#ifdef IPPROTO_IPV6
if (to.type == NA_IPV6)
socket = svs.socketip6;
else
#endif
socket = svs.socketip;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_SendPacket: bad netsrc");
socket = 0;
#else
#ifdef USEIPX
if (to.type == NA_BROADCAST_IPX || to.type == NA_IPX)
socket = cls.socketipx;
else
#endif
#ifdef IPPROTO_IPV6
if (to.type == NA_BROADCAST_IP6 || to.type == NA_IPV6)
socket = cls.socketip6;
else
#endif
socket = cls.socketip;
#endif
}
NetadrToSockadr (&to, &addr);
ret = sendto (socket, data, length, 0, (struct sockaddr*)&addr, sizeof(addr) );
if (ret == -1)
{
// wouldblock is silent
if (qerrno == EWOULDBLOCK)
return;
if (qerrno == ECONNREFUSED)
return;
#ifndef SERVERONLY
if (qerrno == EADDRNOTAVAIL)
Con_DPrintf("NET_SendPacket Warning: %i\n", qerrno);
else
#endif
Con_TPrintf (TL_NETSENDERROR, qerrno);
}
}
//=============================================================================
int UDP_OpenSocket (int port, qboolean bcast)
{
int newsocket;
struct sockaddr_in address;
unsigned long _true = true;
int i;
int maxport = port + 100;
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
Sys_Error ("UDP_OpenSocket: socket: %s", strerror(qerrno));
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno));
if (bcast)
{
_true = true;
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
{
Con_Printf("Cannot create broadcast socket\n");
return 0;
}
}
address.sin_family = AF_INET;
//ZOID -- check for interface binding option
if ((i = COM_CheckParm("-ip")) != 0 && i < com_argc) {
address.sin_addr.s_addr = inet_addr(com_argv[i+1]);
Con_TPrintf(TL_NETBINDINTERFACE,
inet_ntoa(address.sin_addr));
} else
address.sin_addr.s_addr = INADDR_ANY;
for(;;)
{
if (port == PORT_ANY)
address.sin_port = 0;
else
address.sin_port = htons((short)port);
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
{
if (!port)
Sys_Error ("UDP_OpenSocket: bind: %s", strerror(qerrno));
port++;
if (port > maxport)
Sys_Error ("UDP_OpenSocket: bind: %s", strerror(qerrno));
}
else
break;
}
return newsocket;
}
#ifdef IPPROTO_IPV6
int UDP6_OpenSocket (int port, qboolean bcast)
{
int newsocket;
struct sockaddr_in6 address;
unsigned long _true = true;
// int i;
int maxport = port + 100;
if ((newsocket = socket (PF_INET6, SOCK_DGRAM, 0)) == -1)
{
Con_Printf("IPV6 is not supported: %s\n", strerror(qerrno));
return 0;
}
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
Sys_Error ("UDP_OpenSocket: ioctl FIONBIO: %s", strerror(qerrno));
if (bcast)
{
// address.sin6_addr
// _true = true;
// if (setsockopt(newsocket, SOL_SOCKET, IP_ADD_MEMBERSHIP, (char *)&_true, sizeof(_true)) == -1)
// {
Con_Printf("Cannot create broadcast socket\n");
closesocket(newsocket);
return 0;
// }
}
address.sin6_family = AF_INET6;
//ZOID -- check for interface binding option
// if ((i = COM_CheckParm("-ip6")) != 0 && i < com_argc) {
// address.sin6_addr = inet_addr(com_argv[i+1]);
/// Con_TPrintf(TL_NETBINDINTERFACE,
// inet_ntoa(address.sin6_addr));
// } else
memset(&address.sin6_addr, 0, sizeof(struct in6_addr));
for(;;)
{
if (port == PORT_ANY)
address.sin6_port = 0;
else
address.sin6_port = htons((short)port);
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
{
if (!port)
Sys_Error ("UDP6_OpenSocket: bind: %s", strerror(qerrno));
port++;
if (port > maxport)
Sys_Error ("UDP6_OpenSocket: bind: %s", strerror(qerrno));
}
else
break;
}
return newsocket;
}
#endif
void UDP_CloseSocket (int socket)
{
closesocket(socket);
}
int IPX_OpenSocket (int port, qboolean bcast)
{
#ifndef USEIPX
return 0;
#else
int newsocket;
struct sockaddr_ipx address;
u_long _true = 1;
if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
{
if (qerrno != EAFNOSUPPORT)
Con_Printf ("WARNING: IPX_Socket: socket: %s\n", qerrno);
return 0;
}
// make it non-blocking
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
{
Con_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", qerrno);
return 0;
}
if (bcast)
{
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
{
Con_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", qerrno);
return 0;
}
}
address.sa_family = AF_IPX;
memset (address.sa_netnum, 0, 4);
memset (address.sa_nodenum, 0, 6);
if (port == PORT_ANY)
address.sa_socket = 0;
else
address.sa_socket = htons((short)port);
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
{
Con_Printf ("WARNING: IPX_Socket: bind: %i\n", qerrno);
closesocket (newsocket);
return 0;
}
return newsocket;
#endif
}
void IPX_CloseSocket (int socket)
{
#ifdef USEIPX
closesocket(socket);
#endif
}
// sleeps msec or until net socket is ready
//stdin can sometimes be a socket. As a result,
//we give the option to select it for nice console imput with timeouts.
#ifndef CLIENTONLY
qboolean NET_Sleep(int msec, qboolean stdinissocket)
{
struct timeval timeout;
fd_set fdset;
int i;
FD_ZERO(&fdset);
if (stdinissocket)
FD_SET(0, &fdset);
i = 0;
if (svs.socketip)
{
FD_SET(svs.socketip, &fdset); // network socket
i = svs.socketip;
}
if (svs.socketip6)
{
FD_SET(svs.socketip6, &fdset); // network socket
if (svs.socketip6 > i)
i = svs.socketip6;
i = svs.socketip6;
}
#ifdef USEIPX
if (svs.socketipx)
{
FD_SET(svs.socketipx, &fdset); // network socket
if (svs.socketipx > i)
i = svs.socketipx;
}
#endif
timeout.tv_sec = msec/1000;
timeout.tv_usec = (msec%1000)*1000;
select(i+1, &fdset, NULL, NULL, &timeout);
if (stdinissocket)
return FD_ISSET(0, &fdset);
return true;
}
#endif
void NET_GetLocalIP6Address (int socket)
{
// char buff[512];
struct sockaddr_qstorage address;
int namelen;
// netadr_t adr;
// gethostname(buff, 512);
// buff[512-1] = 0;
// NET_StringToAdr (buff, &adr);
namelen = sizeof(address);
if (getsockname (socket, (struct sockaddr *)&address, &namelen) == -1)
Sys_Error ("NET_Init: getsockname:", strerror(qerrno));
SockadrToNetadr(&address, &net_local_ip6adr);
/* if (!*(int*)net_local_ip6adr.ip) //socket was set to auto
*(int *)net_local_ip6adr.ip = *(int *)adr.ip; //change it to what the machine says it is, rather than the socket.
*/
Con_TPrintf(TL_IPADDRESSIS, NET_AdrToString (net_local_ip6adr) );
}
void NET_GetLocalIPAddress (int socket)
{
char buff[512];
struct sockaddr_qstorage address;
int namelen;
netadr_t adr;
gethostname(buff, 512);
buff[512-1] = 0;
NET_StringToAdr (buff, &adr);
namelen = sizeof(address);
if (getsockname (socket, (struct sockaddr *)&address, &namelen) == -1)
Sys_Error ("NET_Init: getsockname:", strerror(qerrno));
SockadrToNetadr(&address, &net_local_ipadr);
if (!*(int*)net_local_ipadr.ip) //socket was set to auto
*(int *)net_local_ipadr.ip = *(int *)adr.ip; //change it to what the machine says it is, rather than the socket.
Con_TPrintf(TL_IPADDRESSIS, NET_AdrToString (net_local_ipadr) );
}
void NET_GetLocalIPXAddress (int socket)
{
//we don't really care... this is for lans
/* char buff[512];
struct sockaddr address;
int namelen;
netadr_t adr;
gethostname(buff, 512);
buff[512-1] = 0;
NET_StringToAdr (buff, &adr);
namelen = sizeof(address);
if (getsockname (socket, (struct sockaddr *)&address, &namelen) == -1)
Sys_Error ("NET_Init: getsockname:", strerror(qerrno));
SockadrToNetadr(&address, &net_local_adr);
if (!*(int*)net_local_ipadr.ip)
*(int *)net_local_ipadr.ip = *(int *)adr.ip;
if (net_local_adr.type == NA_IP)
Con_TPrintf(TL_IPADDRESSIS, NET_AdrToString (net_local_adr) );
else
Con_Printf("IPX Address: %s\n", NET_AdrToString (net_local_adr) );
*/
}
/*
====================
NET_Init
====================
*/
void NET_Init (void)
{
#ifdef _WIN32
WORD wVersionRequested;
int r;
#ifdef IPPROTO_IPV6
HMODULE ws2_32dll;
ws2_32dll = LoadLibrary("ws2_32.dll");
if (ws2_32dll)
{
pfreeaddrinfo = (void *)GetProcAddress(ws2_32dll, "freeaddrinfo");
pgetaddrinfo = (void *)GetProcAddress(ws2_32dll, "getaddrinfo");
if (!pgetaddrinfo || !pfreeaddrinfo)
{
pgetaddrinfo = NULL;
pfreeaddrinfo = NULL;
FreeLibrary(ws2_32dll);
}
}
else
pgetaddrinfo = NULL;
#endif
wVersionRequested = MAKEWORD(1, 1);
r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
if (r)
Sys_Error ("Winsock initialization failed.");
#endif
Con_TPrintf(TL_UDPINITED);
#ifdef NQPROT
NQ_NET_Init();
#endif
}
#ifndef SERVERONLY
void NET_InitClient(void)
{
int port;
int p;
port = PORT_CLIENT;
p = COM_CheckParm ("-port");
if (p && p < com_argc)
{
port = atoi(com_argv[p+1]);
}
//
// open the single socket to be used for all communications
//
cls.socketip = UDP_OpenSocket (port, false);
#ifdef IPPROTO_IPV6
cls.socketip6 = UDP6_OpenSocket (port, false);
#endif
#ifdef USEIPX
cls.socketipx = IPX_OpenSocket (port, false);
#endif
//
// init the message buffer
//
net_message.maxsize = sizeof(net_message_buffer);
net_message.data = net_message_buffer;
//
// determine my name & address
//
NET_GetLocalIPAddress (cls.socketip);
Con_TPrintf(TL_CLIENTPORTINITED);
}
#endif
#ifndef CLIENTONLY
void NET_CloseServer(void)
{
if (svs.socketip)
{
UDP_CloseSocket(svs.socketip);
svs.socketip = 0;
}
if (svs.socketip6)
{
UDP_CloseSocket(svs.socketip);
svs.socketip = 0;
}
#ifdef USEIPX
if (svs.socketipx)
{
IPX_CloseSocket(svs.socketipx);
svs.socketipx = 0;
}
#endif
net_local_ipadr.type = NA_LOOPBACK;
}
void NET_InitServer(void)
{
int port;
int p;
port = PORT_SERVER;
if (sv_public.value)
{
p = COM_CheckParm ("-svport");
if (p && p < com_argc)
{
port = atoi(com_argv[p+1]);
}
p = COM_CheckParm ("-port");
if (p && p < com_argc)
{
port = atoi(com_argv[p+1]);
}
//
// open the single socket to be used for all communications
//
if (!svs.socketip)
{
svs.socketip = UDP_OpenSocket (port, false);
NET_GetLocalIPAddress (svs.socketip);
}
#ifdef IPPROTO_IPV6
if (!svs.socketip6)
{
svs.socketip6 = UDP6_OpenSocket (port, false);
if (svs.socketip6)
NET_GetLocalIP6Address (svs.socketip6);
}
#endif
#ifdef USEIPX
if (!svs.socketipx)
{
svs.socketipx = IPX_OpenSocket (port, false);
NET_GetLocalIPXAddress (svs.socketipx);
}
#endif
}
else
NET_CloseServer();
//
// init the message buffer
//
net_message.maxsize = sizeof(net_message_buffer);
net_message.data = net_message_buffer;
}
#endif
/*
====================
NET_Shutdown
====================
*/
void NET_Shutdown (void)
{
#ifndef CLIENTONLY
NET_CloseServer();
#endif
#ifndef SERVERONLY
UDP_CloseSocket (cls.socketip);
UDP_CloseSocket (cls.socketip6);
#ifdef USEIPX
IPX_CloseSocket (cls.socketipx);
#endif
#endif
#ifdef NQPROT
NQ_NET_Shutdown();
#endif
#ifdef _WIN32
#ifdef SERVERTONLY
if (!serverthreadID) //running as subsystem of client. Don't close all of it's sockets too.
#endif
WSACleanup ();
#endif
}