Code: Select all
// Returns the address family of an address or hostname.
// AF_INET, AF_INET6, or AF_UNSPEC if unknown.
int getaddrfamily (const char *addr)
{
int ret;
struct addrinfo hint = {0}, *info =0;
//memset(&hint, 0, sizeof(hint));
if (!addr) return AF_UNSPEC;
hint.ai_family = AF_UNSPEC;
// TODO: We have DNS lookup disabled, do we always want this behavior?
hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo (addr, 0, &hint, &info);
if (ret)
return AF_UNSPEC;;
ret = info->ai_family;
freeaddrinfo (info);
return ret;
}
// Determines from address
void sock_set (struct sockaddr_storage *sas, const char *_addr, int *port)
{
const char *addr = _addr ? _addr : "localhost";
int _familyadr = getaddrfamily (addr);
int _familysas = (_familyadr == AF_UNSPEC) ? sas->ss_family : _familyadr;
int family = (_familysas == AF_UNSPEC) ? AF_INET6 : _familysas;
unsigned short _usport = (unsigned short)*port;
struct sockaddr_in *sas_in4 = (struct sockaddr_in *)sas;
struct sockaddr_in6 *sas_in6 = (struct sockaddr_in6 *)sas;
switch (family)
{
case AF_INET:
if (!strcasecmp("localhost", addr)) addr = "127.0.0.1";
sas_in4->sin_family = AF_INET;
inet_pton (AF_INET, addr ? addr : "0.0.0.0", &sas_in4->sin_addr);
sas_in4->sin_port = htons(_usport);
break;
default: // <--- Unspecified gets IPv6, although we set this above
case AF_INET6:
if (!strcasecmp("localhost", addr)) addr = "::1";
sas_in6->sin6_family = AF_INET6;
inet_pton (AF_INET6, addr ? addr : "0.0.0.0", &sas_in6->sin6_addr);
sas_in6->sin6_port = htons(_usport);
break;
}
}
void sock_set_any (struct sockaddr_storage *sas, int *port)
{
int _familysas = sas->ss_family;
int family = (_familysas == AF_UNSPEC) ? AF_INET6 : _familysas;
unsigned short _usport = (unsigned short)*port;
struct sockaddr_in *sas_in4 = (struct sockaddr_in *)sas;
struct sockaddr_in6 *sas_in6 = (struct sockaddr_in6 *)sas;
switch (family)
{
case AF_INET:
sas_in4->sin_family = AF_INET;
INETADDR_SETANY((struct sockaddr *)sas);
sas_in4->sin_port = htons(_usport);
break;
default: // <--- Unspecified gets IPv6, although we set this above
case AF_INET6:
sas_in6->sin6_family = AF_INET6;
INETADDR_SETANY((struct sockaddr *)sas);
sas_in6->sin6_port = htons(_usport);
break;
}
}
// preferably address length is INET_ADDRSTRLEN6 or longer
void sock_get (struct sockaddr_storage *sas, char *addr, size_t len, int *port)
{
unsigned short _usport;
struct sockaddr_in *sas_in4 = (struct sockaddr_in *)sas;
struct sockaddr_in6 *sas_in6 = (struct sockaddr_in6 *)sas;
switch(sas->ss_family)
{
case AF_INET:
inet_ntop (AF_INET, &sas_in4->sin_addr, addr, len);
_usport = ntohs (sas_in4->sin_port);
break;
case AF_INET6:
inet_ntop (AF_INET6, &sas_in6->sin6_addr, addr, len);
_usport = ntohs (sas_in6->sin6_port);
break;
default:
Core_Error ("sockaddr_storage_set unknown type");
}
if (port) *port = _usport;
}
void sock_string (struct sockaddr_storage *sas, char *addr, size_t len)
{
char str[SYSTEM_STRING_SIZE];
int port;
sock_get (sas, str, sizeof str, &port);
c_snprintfc (addr, len, "%s port %i", str, port);
}
// not thread safe (the static)
const char *sock_string_nts_ (struct sockaddr_storage *sas)
{
static char str[SYSTEM_STRING_SIZE];
int port;
sock_get (sas, str, sizeof(str), &port);
c_strlcat (str, va (" port %i", port));
return (const char*)str;
}
void sock_string_addr (struct sockaddr_storage *sas, char *addr, size_t len)
{
char str[SYSTEM_STRING_SIZE];
sock_get (sas, str, sizeof str, NULL);
strlcpy (addr, str, len);
}
// not thread safe
const char *sock_string_addr_nts_ (struct sockaddr_storage *sas)
{
static char str[SYSTEM_STRING_SIZE];
sock_get (sas, str, sizeof str, NULL);
return (const char*)str;
}
cbool Net_SetSocketNonBlocking (sys_socket_t sockfd)
{
cbool result = true;
int on = 1, off = 0;
#ifndef PLATFORM_WINDOWS
int flags = fcntl(fd, F_GETFL, 0);
if ((fcntl (sockfd, F_SETFL, O_NONBLOCK)) == -1)
result = false;
#endif
if (sys_ioctlsocket (sockfd, FIONBIO, &on) == -1)
result = false;
return result;
}
cbool sock_cmp (struct sockaddr_storage *sas1, struct sockaddr_storage *sas2)
{
if (sas1->ss_family == sas2->ss_family)
{
struct sockaddr_in *sas1_in4 = (struct sockaddr_in *)sas1;
struct sockaddr_in6 *sas1_in6 = (struct sockaddr_in6 *)sas1;
struct sockaddr_in *sas2_in4 = (struct sockaddr_in *)sas2;
struct sockaddr_in6 *sas2_in6 = (struct sockaddr_in6 *)sas2;
switch (sas1->ss_family)
{
case AF_INET:
if (memcmp (&sas1_in4->sin_addr, &sas2_in4->sin_addr, sizeof(struct in_addr)) != 0)
return false; // No match
// IP address matches, now compare port
return (sas1_in4->sin_port == sas2_in4->sin_port);
case AF_INET6:
if (memcmp (&sas1_in6->sin6_addr, &sas2_in6->sin6_addr, sizeof(struct in6_addr)) != 0)
return false; // No match
// IP address matches, now compare port
return (sas1_in6->sin6_port == sas2_in6->sin6_port);
default:
Core_Error ("sock_cmp " "ss_family unknown");
}
}
return false;
}
cbool sock_cmp_addr (struct sockaddr_storage *sas1, struct sockaddr_storage *sas2)
{
if (sas1->ss_family == sas2->ss_family)
{
struct sockaddr_in *sas1_in4 = (struct sockaddr_in *)sas1;
struct sockaddr_in6 *sas1_in6 = (struct sockaddr_in6 *)sas1;
struct sockaddr_in *sas2_in4 = (struct sockaddr_in *)sas2;
struct sockaddr_in6 *sas2_in6 = (struct sockaddr_in6 *)sas2;
switch (sas1->ss_family)
{
case AF_INET:
return (memcmp (&sas1_in4->sin_addr, &sas2_in4->sin_addr, sizeof(struct in_addr)) == 0);
case AF_INET6:
return (memcmp (&sas1_in6->sin6_addr, &sas2_in6->sin6_addr, sizeof(struct in6_addr)) == 0);
default:
Core_Error ("sock_cmp_addr " "ss_family unknown");
}
}
return false;
}
int sock_getport (struct sockaddr_storage *sas)
{
struct sockaddr_in *sas_in4 = (struct sockaddr_in *)sas;
struct sockaddr_in6 *sas_in6 = (struct sockaddr_in6 *)sas;
switch (sas->ss_family)
{
case AF_INET:
return (int)ntohs(sas_in4->sin_port);
case AF_INET6:
return (int)ntohs(sas_in6->sin6_port);
default:
Core_Error ("sock_getport " "ss_family unknown");
return 0; // often unreachable, depends on Core_Error assignment
}
}
void sock_setport (struct sockaddr_storage *sas, int port)
{
unsigned short _usport = (unsigned short)port;
struct sockaddr_in *sas_in4 = (struct sockaddr_in *)sas;
struct sockaddr_in6 *sas_in6 = (struct sockaddr_in6 *)sas;
switch (sas->ss_family)
{
case AF_INET:
sas_in4->sin_port = htons(_usport);
return;
case AF_INET6:
sas_in6->sin6_port = htons(_usport);
return;
default:
Core_Error ("sock_setport " "ss_family unknown");
}
}
Outstanding stuff: make use single port for serving (true NAT fix).
Not sure what to do about "status" command, and "test" and 'test2" commands. I will need to find out if using IP6 addresses break those queries. test and test2 are used by server browsers. Many other small issues I need to address. Not sure how to handle ban lists, etc or the idea that in NetQuake you mask (out) the final octet for some level of privacy (I don't think, for example, Quakeworld reveals anything about player ip addresses except to admins).
Other outstanding item -ip x.x.x.x in server command line.