2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
net_udp.c
|
|
|
|
|
2011-07-26 05:15:41 +00:00
|
|
|
UDP lan driver.
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-09-07 04:41:13 +00:00
|
|
|
#include <sys/types.h>
|
2001-05-09 05:41:34 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
2001-04-10 23:17:47 +00:00
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
# include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
2002-08-09 02:44:23 +00:00
|
|
|
# define model_t sun_model_t
|
2001-04-10 23:17:47 +00:00
|
|
|
# include <netinet/in.h>
|
2002-08-09 02:44:23 +00:00
|
|
|
# undef model_t
|
2001-04-10 23:17:47 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETDB_H
|
|
|
|
# include <netdb.h>
|
|
|
|
#endif
|
2011-08-11 09:32:39 +00:00
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
# include <ifaddrs.h>
|
|
|
|
#endif
|
2001-04-10 23:17:47 +00:00
|
|
|
#ifdef HAVE_SYS_PARAM_H
|
|
|
|
# include <sys/param.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_IOCTL_H
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2001-08-27 07:13:32 +00:00
|
|
|
# include <unistd.h>
|
2001-02-19 21:15:25 +00:00
|
|
|
#endif
|
2012-08-18 12:49:30 +00:00
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
# include <fcntl.h>
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
#ifdef __sun__
|
2001-08-27 07:13:32 +00:00
|
|
|
# include <sys/filio.h>
|
2001-02-19 21:15:25 +00:00
|
|
|
#endif
|
|
|
|
#ifdef NeXT
|
2001-08-27 07:13:32 +00:00
|
|
|
# include <libc.h>
|
2001-02-19 21:15:25 +00:00
|
|
|
#endif
|
|
|
|
|
2021-04-04 05:03:58 +00:00
|
|
|
#include <ctype.h>
|
2001-08-27 07:13:32 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
2012-08-18 12:49:30 +00:00
|
|
|
#ifdef HAVE_SYS_IOCTL_H
|
2005-04-27 03:34:38 +00:00
|
|
|
#include <sys/ioctl.h>
|
2012-08-18 12:49:30 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NET_IF_H
|
2005-04-27 03:34:38 +00:00
|
|
|
#include <net/if.h>
|
2012-08-18 12:49:30 +00:00
|
|
|
#endif
|
2001-08-27 07:13:32 +00:00
|
|
|
|
2001-05-31 03:41:35 +00:00
|
|
|
#include "QF/cvar.h"
|
2003-07-08 22:39:45 +00:00
|
|
|
#include "QF/dstring.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/qargs.h"
|
|
|
|
#include "QF/sys.h"
|
2003-07-08 22:39:45 +00:00
|
|
|
#include "QF/va.h"
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-08-27 07:13:32 +00:00
|
|
|
#include "compat.h"
|
2003-02-11 22:48:57 +00:00
|
|
|
#include "netmain.h"
|
2011-08-24 00:14:02 +00:00
|
|
|
#include "net_udp.h"
|
2001-05-31 03:41:35 +00:00
|
|
|
|
2013-01-29 03:13:59 +00:00
|
|
|
#ifdef HAVE_IN_PKTINFO
|
|
|
|
# ifndef SOL_IP // BSD-based stacks don't define this.
|
|
|
|
# define SOL_IP IPPROTO_IP
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 23:17:47 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
# undef EWOULDBLOCK
|
|
|
|
# define EWOULDBLOCK WSAEWOULDBLOCK
|
|
|
|
# undef ECONNREFUSED
|
|
|
|
# define ECONNREFUSED WSAECONNREFUSED
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef MAXHOSTNAMELEN
|
|
|
|
# define MAXHOSTNAMELEN 512
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef HAVE_SOCKLEN_T
|
2013-01-22 04:27:39 +00:00
|
|
|
# ifdef _WIN64
|
|
|
|
typedef int socklen_t;
|
2001-04-10 23:17:47 +00:00
|
|
|
# else
|
2013-01-22 04:27:39 +00:00
|
|
|
# ifdef HAVE_SIZE
|
|
|
|
typedef size_t socklen_t;
|
|
|
|
# else
|
2001-08-27 07:13:32 +00:00
|
|
|
typedef unsigned int socklen_t;
|
2013-01-22 04:27:39 +00:00
|
|
|
# endif
|
2001-04-10 23:17:47 +00:00
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
#define ADDR_SIZE 4
|
|
|
|
|
|
|
|
typedef union address {
|
2012-08-18 12:49:30 +00:00
|
|
|
#ifdef HAVE_SS_LEN
|
2011-09-04 00:00:42 +00:00
|
|
|
struct sockaddr_storage ss;
|
2012-08-18 12:49:30 +00:00
|
|
|
#endif
|
2011-09-04 00:00:42 +00:00
|
|
|
struct sockaddr sa;
|
|
|
|
struct sockaddr_in s4;
|
|
|
|
} AF_address_t;
|
|
|
|
|
|
|
|
#undef SA_LEN
|
|
|
|
#undef SS_LEN
|
|
|
|
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
#define SA_LEN(sa) (sa)->sa_len
|
|
|
|
#else
|
2011-09-04 00:48:16 +00:00
|
|
|
#define SA_LEN(sa) (sizeof(struct sockaddr_in))
|
2011-09-04 00:00:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SS_LEN
|
|
|
|
#define SS_LEN(ss) (ss)->ss_len
|
|
|
|
#else
|
2011-09-04 00:48:16 +00:00
|
|
|
#define SS_LEN(ss) (sizeof(struct sockaddr_in))
|
2011-09-04 00:00:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
NetadrToSockadr (netadr_t *a, AF_address_t *s)
|
|
|
|
{
|
|
|
|
memset (s, 0, sizeof (*s));
|
|
|
|
s->s4.sin_family = AF_INET;
|
|
|
|
|
|
|
|
memcpy (&s->s4.sin_addr, &a->ip, ADDR_SIZE);
|
|
|
|
s->s4.sin_port = a->port;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
SockadrToNetadr (AF_address_t *s, netadr_t *a)
|
|
|
|
{
|
|
|
|
memcpy (&a->ip, &s->s4.sin_addr, ADDR_SIZE);
|
|
|
|
a->port = s->s4.sin_port;
|
|
|
|
a->family = s->s4.sin_family;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
static int net_acceptsocket = -1; // socket for fielding new
|
|
|
|
// connections
|
|
|
|
static int net_controlsocket;
|
|
|
|
static int net_broadcastsocket = 0;
|
2011-09-04 00:00:42 +00:00
|
|
|
static netadr_t broadcastaddr;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-08-11 09:32:39 +00:00
|
|
|
static uint32_t myAddr;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-08-06 09:57:53 +00:00
|
|
|
static int num_ifaces;
|
|
|
|
uint32_t *ifaces;
|
|
|
|
uint32_t *default_iface;
|
2011-08-06 11:30:56 +00:00
|
|
|
uint32_t *last_iface;
|
2011-08-06 09:57:53 +00:00
|
|
|
|
2005-04-27 03:34:38 +00:00
|
|
|
static int
|
2011-08-06 09:57:53 +00:00
|
|
|
get_iface_list (int sock)
|
2005-04-27 03:34:38 +00:00
|
|
|
{
|
2011-08-11 09:32:39 +00:00
|
|
|
#ifdef HAVE_GETIFADDRS
|
|
|
|
struct ifaddrs *ifa_head;
|
|
|
|
struct ifaddrs *ifa;
|
2011-08-16 01:03:43 +00:00
|
|
|
int index;
|
2011-08-11 09:32:39 +00:00
|
|
|
|
|
|
|
if (getifaddrs (&ifa_head) < 0)
|
|
|
|
goto no_ifaddrs;
|
|
|
|
for (ifa = ifa_head; ifa; ifa = ifa->ifa_next) {
|
2022-03-30 15:31:15 +00:00
|
|
|
if (!(ifa->ifa_flags & IFF_UP))
|
2011-08-11 09:32:39 +00:00
|
|
|
continue;
|
|
|
|
if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
2011-08-16 01:03:43 +00:00
|
|
|
index = if_nametoindex (ifa->ifa_name);
|
|
|
|
if (index > num_ifaces)
|
|
|
|
num_ifaces = index;
|
2011-08-11 09:32:39 +00:00
|
|
|
}
|
|
|
|
ifaces = malloc (num_ifaces * sizeof (uint32_t));
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "%d interfaces\n", num_ifaces);
|
2011-08-11 09:32:39 +00:00
|
|
|
for (ifa = ifa_head; ifa; ifa = ifa->ifa_next) {
|
|
|
|
struct sockaddr_in *sa;
|
|
|
|
|
2022-03-30 15:31:15 +00:00
|
|
|
if (!(ifa->ifa_flags & IFF_UP))
|
2011-08-11 09:32:39 +00:00
|
|
|
continue;
|
|
|
|
if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
|
|
|
|
continue;
|
2011-08-16 01:03:43 +00:00
|
|
|
index = if_nametoindex (ifa->ifa_name) - 1;
|
2011-08-11 09:32:39 +00:00
|
|
|
sa = (struct sockaddr_in *) ifa->ifa_addr;
|
|
|
|
memcpy (&ifaces[index], &sa->sin_addr, sizeof (uint32_t));
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, " %-10s %s\n", ifa->ifa_name,
|
2011-08-11 09:32:39 +00:00
|
|
|
inet_ntoa (sa->sin_addr));
|
|
|
|
if (!default_iface && ifaces[index] != htonl (0x7f000001))
|
|
|
|
default_iface = &ifaces[index];
|
2005-04-27 03:34:38 +00:00
|
|
|
}
|
2011-08-11 09:32:39 +00:00
|
|
|
freeifaddrs (ifa_head);
|
|
|
|
return 0;
|
|
|
|
no_ifaddrs:
|
2012-02-05 05:28:23 +00:00
|
|
|
#endif
|
2011-08-11 09:32:39 +00:00
|
|
|
ifaces = &myAddr;
|
|
|
|
default_iface = &ifaces[0];
|
|
|
|
num_ifaces = 1;
|
|
|
|
return 0;
|
2005-04-27 03:34:38 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
|
|
|
UDP_Init (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2012-08-18 12:49:30 +00:00
|
|
|
struct hostent *local = 0;
|
2001-02-26 06:48:02 +00:00
|
|
|
char buff[MAXHOSTNAMELEN];
|
2011-09-04 00:00:42 +00:00
|
|
|
netadr_t addr;
|
2001-02-26 06:48:02 +00:00
|
|
|
char *colon;
|
2001-10-21 21:18:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
WSADATA winsockdata;
|
|
|
|
int r;
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-10-21 21:18:31 +00:00
|
|
|
r = WSAStartup (MAKEWORD (1, 1), &winsockdata);
|
|
|
|
if (r)
|
|
|
|
Sys_Error ("Winsock initialization failed.");
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
if (COM_CheckParm ("-noudp"))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// determine my name & address
|
2012-08-18 12:49:30 +00:00
|
|
|
#ifdef HAVE_GETHOSTNAME //FIXME
|
2001-02-26 06:48:02 +00:00
|
|
|
gethostname (buff, MAXHOSTNAMELEN);
|
|
|
|
local = gethostbyname (buff);
|
2012-08-18 12:49:30 +00:00
|
|
|
#endif
|
2001-07-27 23:17:40 +00:00
|
|
|
if (local)
|
2011-08-11 09:32:39 +00:00
|
|
|
myAddr = *(uint32_t *) local->h_addr_list[0];
|
2001-07-27 23:17:40 +00:00
|
|
|
else
|
|
|
|
myAddr = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// if the quake hostname isn't set, set it to the machine name
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (strcmp (hostname, "UNNAMED") == 0) {
|
2001-02-19 21:15:25 +00:00
|
|
|
buff[15] = 0;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Set ("hostname", buff);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((net_controlsocket = UDP_OpenSocket (0)) == -1)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("UDP_Init: Unable to open control socket");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-08-06 09:57:53 +00:00
|
|
|
get_iface_list (net_controlsocket);
|
2005-04-27 03:34:38 +00:00
|
|
|
|
2009-12-19 10:54:23 +00:00
|
|
|
{
|
2011-09-04 00:00:42 +00:00
|
|
|
AF_address_t t;
|
|
|
|
t.s4.sin_family = AF_INET;
|
|
|
|
t.s4.sin_addr.s_addr = INADDR_BROADCAST;
|
|
|
|
t.s4.sin_port = htons (net_hostport);
|
|
|
|
SockadrToNetadr (&t, &broadcastaddr);
|
2009-12-19 10:54:23 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
UDP_GetSocketAddr (net_controlsocket, &addr);
|
2001-02-26 06:48:02 +00:00
|
|
|
strcpy (my_tcpip_address, UDP_AddrToString (&addr));
|
2001-02-19 21:15:25 +00:00
|
|
|
colon = strrchr (my_tcpip_address, ':');
|
|
|
|
if (colon)
|
|
|
|
*colon = 0;
|
|
|
|
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("UDP (IPv4) Initialized\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
tcpipAvailable = true;
|
|
|
|
|
|
|
|
return net_controlsocket;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
|
|
|
UDP_Shutdown (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
UDP_Listen (false);
|
2001-10-21 21:18:31 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
UDP_CloseSocket (net_controlsocket);
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
void
|
2023-06-13 09:06:11 +00:00
|
|
|
UDP_Listen (bool state)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
// enable listening
|
2001-02-26 06:48:02 +00:00
|
|
|
if (state) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (net_acceptsocket != -1)
|
|
|
|
return;
|
|
|
|
if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("UDP_Listen: Unable to open accept socket");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// disable listening
|
|
|
|
if (net_acceptsocket == -1)
|
|
|
|
return;
|
|
|
|
UDP_CloseSocket (net_acceptsocket);
|
|
|
|
net_acceptsocket = -1;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
|
|
|
UDP_OpenSocket (int port)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int newsocket;
|
2001-02-19 21:15:25 +00:00
|
|
|
struct sockaddr_in address;
|
2001-04-10 23:17:47 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
#define ioctl ioctlsocket
|
2012-08-18 13:02:02 +00:00
|
|
|
unsigned long flags;
|
2001-04-10 23:17:47 +00:00
|
|
|
#else
|
2012-08-18 13:02:02 +00:00
|
|
|
int flags;
|
2011-08-06 11:30:56 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_IN_PKTINFO
|
|
|
|
int ip_pktinfo = 1;
|
2001-04-10 23:17:47 +00:00
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
|
|
|
return -1;
|
|
|
|
|
2012-08-18 13:02:02 +00:00
|
|
|
#if defined (HAVE_IOCTL) || defined (_WIN32)
|
|
|
|
flags = 1;
|
|
|
|
if (ioctl (newsocket, FIONBIO, &flags) == -1)
|
2001-02-19 21:15:25 +00:00
|
|
|
goto ErrorReturn;
|
2012-08-18 13:02:02 +00:00
|
|
|
#else
|
|
|
|
flags = fcntl (newsocket, F_GETFL, 0);
|
|
|
|
if (fcntl (newsocket, F_SETFL, flags | O_NONBLOCK) == -1)
|
|
|
|
goto ErrorReturn;
|
|
|
|
#endif
|
2011-08-06 11:30:56 +00:00
|
|
|
#ifdef HAVE_IN_PKTINFO
|
|
|
|
if (setsockopt (newsocket, SOL_IP, IP_PKTINFO, &ip_pktinfo,
|
|
|
|
sizeof (ip_pktinfo)) == -1) {
|
|
|
|
close (newsocket);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
address.sin_family = AF_INET;
|
|
|
|
address.sin_addr.s_addr = INADDR_ANY;
|
2001-02-26 06:48:02 +00:00
|
|
|
address.sin_port = htons (port);
|
|
|
|
if (bind (newsocket, (void *) &address, sizeof (address)) == -1)
|
2001-02-19 21:15:25 +00:00
|
|
|
goto ErrorReturn;
|
|
|
|
|
|
|
|
return newsocket;
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
ErrorReturn:
|
2002-08-20 19:16:11 +00:00
|
|
|
UDP_CloseSocket (newsocket);
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
|
|
|
UDP_CloseSocket (int socket)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
if (socket == net_broadcastsocket)
|
|
|
|
net_broadcastsocket = 0;
|
2001-10-21 21:18:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
closesocket (socket);
|
|
|
|
WSACleanup ();
|
|
|
|
return 0;
|
|
|
|
#else
|
2001-02-19 21:15:25 +00:00
|
|
|
return close (socket);
|
2001-10-21 21:18:31 +00:00
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2001-08-27 07:13:32 +00:00
|
|
|
PartialIPAddress
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-08-27 07:13:32 +00:00
|
|
|
this lets you type only as much of the net address as required, using
|
|
|
|
the local network components to fill in the rest
|
2001-02-19 21:15:25 +00:00
|
|
|
*/
|
2001-02-26 06:48:02 +00:00
|
|
|
static int
|
2011-09-04 00:00:42 +00:00
|
|
|
PartialIPAddress (const char *in, netadr_t *hostaddr)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2003-07-08 22:39:45 +00:00
|
|
|
char *buff;
|
2001-02-26 06:48:02 +00:00
|
|
|
char *b;
|
2018-09-09 00:54:16 +00:00
|
|
|
unsigned addr, mask, num, port, run;
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2003-07-08 22:39:45 +00:00
|
|
|
buff = nva (".%s", in);
|
2001-02-19 21:15:25 +00:00
|
|
|
b = buff;
|
|
|
|
if (buff[1] == '.')
|
|
|
|
b++;
|
|
|
|
|
|
|
|
addr = 0;
|
2001-02-26 06:48:02 +00:00
|
|
|
mask = -1;
|
|
|
|
while (*b == '.') {
|
2001-02-19 21:15:25 +00:00
|
|
|
b++;
|
|
|
|
num = 0;
|
|
|
|
run = 0;
|
2001-02-26 06:48:02 +00:00
|
|
|
while (!(*b < '0' || *b > '9')) {
|
|
|
|
num = num * 10 + *b++ - '0';
|
|
|
|
if (++run > 3)
|
2003-07-08 22:39:45 +00:00
|
|
|
goto error;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
|
2003-07-08 22:39:45 +00:00
|
|
|
goto error;
|
2018-09-09 00:54:16 +00:00
|
|
|
if (num > 255)
|
2003-07-08 22:39:45 +00:00
|
|
|
goto error;
|
2001-02-26 06:48:02 +00:00
|
|
|
mask <<= 8;
|
|
|
|
addr = (addr << 8) + num;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (*b++ == ':')
|
2001-02-26 06:48:02 +00:00
|
|
|
port = atoi (b);
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
|
|
|
port = net_hostport;
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
hostaddr->family = AF_INET;
|
|
|
|
hostaddr->port = htons ((short) port);
|
|
|
|
{
|
|
|
|
int32_t t = myAddr & htonl (mask);
|
|
|
|
t |= htonl (addr);
|
|
|
|
memcpy (hostaddr->ip, &t, ADDR_SIZE);
|
|
|
|
}
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2003-07-08 22:39:45 +00:00
|
|
|
free (buff);
|
2001-02-19 21:15:25 +00:00
|
|
|
return 0;
|
2003-07-08 22:39:45 +00:00
|
|
|
error:
|
|
|
|
free (buff);
|
|
|
|
return -1;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2018-10-09 03:35:01 +00:00
|
|
|
__attribute__((const)) int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_Connect (int socket, netadr_t *addr)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
|
|
|
UDP_CheckNewConnections (void)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2012-08-18 13:02:02 +00:00
|
|
|
#if defined (HAVE_IOCTL) || defined (_WIN32)
|
2013-01-22 04:27:39 +00:00
|
|
|
# ifdef _WIN64
|
|
|
|
u_long available;
|
|
|
|
# else
|
2011-12-08 12:50:55 +00:00
|
|
|
int available;
|
2013-01-22 04:27:39 +00:00
|
|
|
# endif
|
2011-08-24 00:14:02 +00:00
|
|
|
AF_address_t from;
|
|
|
|
socklen_t fromlen = sizeof (from);
|
2001-02-26 06:48:02 +00:00
|
|
|
char buff[1];
|
2012-08-18 13:02:02 +00:00
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (net_acceptsocket == -1)
|
|
|
|
return -1;
|
2012-08-18 13:02:02 +00:00
|
|
|
#if defined (HAVE_IOCTL) || defined (_WIN32)
|
2001-02-19 21:15:25 +00:00
|
|
|
if (ioctl (net_acceptsocket, FIONREAD, &available) == -1)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("UDP: ioctlsocket (FIONREAD) failed");
|
2001-02-19 21:15:25 +00:00
|
|
|
if (available)
|
|
|
|
return net_acceptsocket;
|
2003-07-08 20:11:10 +00:00
|
|
|
// quietly absorb empty packets
|
2011-08-06 09:57:53 +00:00
|
|
|
// there is no way to tell between an empty packet and no packets, but
|
|
|
|
// as non-blocking io is used, this is not a problem.
|
2011-08-06 11:30:56 +00:00
|
|
|
// we don't care about the interface on which the packet arrived
|
2011-09-04 00:00:42 +00:00
|
|
|
recvfrom (net_acceptsocket, buff, 0, 0, &from.sa, &fromlen);
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
2012-08-18 13:02:02 +00:00
|
|
|
#else
|
|
|
|
return net_acceptsocket;
|
|
|
|
#endif
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 05:03:58 +00:00
|
|
|
static void
|
|
|
|
hex_dump_buf (byte *buf, int len)
|
|
|
|
{
|
|
|
|
int pos = 0, llen, i;
|
|
|
|
|
|
|
|
while (pos < len) {
|
|
|
|
llen = (len - pos < 16 ? len - pos : 16);
|
|
|
|
printf ("%08x: ", pos);
|
|
|
|
for (i = 0; i < llen; i++)
|
|
|
|
printf ("%02x ", buf[pos + i]);
|
|
|
|
for (i = 0; i < 16 - llen; i++)
|
|
|
|
printf (" ");
|
|
|
|
printf (" | ");
|
|
|
|
|
|
|
|
for (i = 0; i < llen; i++)
|
|
|
|
printf ("%c", isprint (buf[pos + i]) ? buf[pos + i] : '.');
|
|
|
|
for (i = 0; i < 16 - llen; i++)
|
|
|
|
printf (" ");
|
|
|
|
printf ("\n");
|
|
|
|
pos += llen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_Read (int socket, byte *buf, int len, netadr_t *from)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int ret;
|
2011-09-04 00:00:42 +00:00
|
|
|
AF_address_t addr;
|
2011-08-06 11:30:56 +00:00
|
|
|
#ifdef HAVE_IN_PKTINFO
|
|
|
|
char ancillary[CMSG_SPACE (sizeof (struct in_pktinfo))];
|
|
|
|
struct msghdr msghdr = {
|
2011-09-04 00:00:42 +00:00
|
|
|
&addr,
|
|
|
|
sizeof (addr),
|
2011-08-06 11:30:56 +00:00
|
|
|
0, 0,
|
|
|
|
ancillary,
|
|
|
|
sizeof (ancillary),
|
|
|
|
0
|
|
|
|
};
|
|
|
|
struct iovec iovec = {buf, len};
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
struct in_pktinfo *info = 0;
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
memset (&addr, 0, sizeof (addr));
|
2011-08-06 11:30:56 +00:00
|
|
|
msghdr.msg_iov = &iovec;
|
|
|
|
msghdr.msg_iovlen = 1;
|
|
|
|
ret = recvmsg (socket, &msghdr, 0);
|
|
|
|
if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
|
|
|
|
return 0;
|
|
|
|
for (cmsg = CMSG_FIRSTHDR (&msghdr); cmsg;
|
|
|
|
cmsg = CMSG_NXTHDR (&msghdr, cmsg)) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "%d\n", cmsg->cmsg_type);
|
2011-08-06 11:30:56 +00:00
|
|
|
if (cmsg->cmsg_type == IP_PKTINFO) {
|
|
|
|
info = (struct in_pktinfo *) CMSG_DATA (cmsg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
last_iface = 0;
|
|
|
|
if (info) {
|
|
|
|
/* Our iterface list is 0 based, but the pktinfo interface index is 1
|
|
|
|
* based.
|
|
|
|
*/
|
|
|
|
last_iface = &ifaces[info->ipi_ifindex - 1];
|
|
|
|
}
|
2011-09-04 00:00:42 +00:00
|
|
|
SockadrToNetadr (&addr, from);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "got %d bytes from %s on iface %d (%s)\n", ret,
|
2022-09-19 15:31:08 +00:00
|
|
|
UDP_AddrToString (from), info ? (int) info->ipi_ifindex - 1 : -1,
|
2011-08-06 11:30:56 +00:00
|
|
|
last_iface ? inet_ntoa (info->ipi_addr) : "?");
|
|
|
|
#else
|
2011-08-24 00:14:02 +00:00
|
|
|
socklen_t addrlen = sizeof (AF_address_t);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
memset (&addr, 0, sizeof (addr));
|
2013-01-22 04:27:39 +00:00
|
|
|
ret = recvfrom (socket, (void *) buf, len, 0, (struct sockaddr *) &addr,
|
|
|
|
&addrlen);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED))
|
|
|
|
return 0;
|
2011-09-04 00:00:42 +00:00
|
|
|
SockadrToNetadr (&addr, from);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "got %d bytes from %s\n", ret,
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_AddrToString (from));
|
2011-08-06 11:30:56 +00:00
|
|
|
last_iface = default_iface;
|
|
|
|
#endif
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (developer & SYS_net) {
|
2021-04-04 05:03:58 +00:00
|
|
|
hex_dump_buf (buf, ret);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static int
|
2001-02-26 06:48:02 +00:00
|
|
|
UDP_MakeSocketBroadcastCapable (int socket)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int i = 1;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// make this socket broadcast capable
|
2001-08-27 07:13:32 +00:00
|
|
|
if (setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) &i,
|
|
|
|
sizeof (i)) < 0)
|
|
|
|
return -1;
|
2001-02-19 21:15:25 +00:00
|
|
|
net_broadcastsocket = socket;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-07-29 04:51:58 +00:00
|
|
|
UDP_Broadcast (int socket, byte *buf, int len)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int ret;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
if (socket != net_broadcastsocket) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (net_broadcastsocket != 0)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("Attempted to use multiple broadcasts sockets");
|
2001-02-19 21:15:25 +00:00
|
|
|
ret = UDP_MakeSocketBroadcastCapable (socket);
|
2001-02-26 06:48:02 +00:00
|
|
|
if (ret == -1) {
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("Unable to make socket broadcast capable\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return UDP_Write (socket, buf, len, &broadcastaddr);
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_Write (int socket, byte *buf, int len, netadr_t *to)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-02-26 06:48:02 +00:00
|
|
|
int ret;
|
2011-09-04 00:00:42 +00:00
|
|
|
AF_address_t addr;
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
NetadrToSockadr (to, &addr);
|
2013-01-22 04:27:39 +00:00
|
|
|
ret = sendto (socket, (const void *) buf, len, 0, &addr.sa,
|
|
|
|
SA_LEN (&addr.sa));
|
2001-02-19 21:15:25 +00:00
|
|
|
if (ret == -1 && errno == EWOULDBLOCK)
|
|
|
|
return 0;
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_net, "sent %d bytes to %s\n", ret,
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_AddrToString (to));
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (developer & SYS_net) {
|
2021-04-04 05:03:58 +00:00
|
|
|
hex_dump_buf (buf, len);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2003-07-08 22:39:45 +00:00
|
|
|
const char *
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_AddrToString (netadr_t *addr)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2003-07-08 22:39:45 +00:00
|
|
|
static dstring_t *buffer;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-07-08 22:39:45 +00:00
|
|
|
if (!buffer)
|
|
|
|
buffer = dstring_new ();
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
dsprintf (buffer, "%d.%d.%d.%d:%d", addr->ip[0],
|
|
|
|
addr->ip[1], addr->ip[2], addr->ip[3],
|
|
|
|
ntohs (addr->port));
|
2003-07-08 22:39:45 +00:00
|
|
|
return buffer->str;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_GetSocketAddr (int socket, netadr_t *na)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
unsigned int a;
|
2011-08-24 00:14:02 +00:00
|
|
|
socklen_t addrlen = sizeof (AF_address_t);
|
2011-09-04 00:00:42 +00:00
|
|
|
AF_address_t addr;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
memset (&addr, 0, sizeof (AF_address_t));
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
getsockname (socket, &addr.sa, &addrlen);
|
|
|
|
SockadrToNetadr (&addr, na);
|
|
|
|
memcpy (&a, na->ip, ADDR_SIZE);
|
2011-08-06 12:47:57 +00:00
|
|
|
if (a == 0 || a == inet_addr ("127.0.0.1")) {
|
2012-09-08 00:37:48 +00:00
|
|
|
if (default_iface)
|
|
|
|
memcpy (na->ip, default_iface, ADDR_SIZE);
|
2011-08-06 12:47:57 +00:00
|
|
|
if (last_iface)
|
2011-09-04 00:00:42 +00:00
|
|
|
memcpy (na->ip, last_iface, ADDR_SIZE);
|
2011-08-06 12:47:57 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_GetNameFromAddr (netadr_t *addr, char *name)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
struct hostent *hostentry;
|
|
|
|
|
2012-02-05 05:28:23 +00:00
|
|
|
//FIXME the cast is an evil hack for android
|
|
|
|
hostentry = gethostbyaddr ((char *) &addr->ip, ADDR_SIZE, AF_INET);
|
2001-02-26 06:48:02 +00:00
|
|
|
|
|
|
|
if (hostentry) {
|
|
|
|
strncpy (name, (char *) hostentry->h_name, NET_NAMELEN - 1);
|
2001-02-19 21:15:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy (name, UDP_AddrToString (addr));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_GetAddrFromName (const char *name, netadr_t *addr)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
struct hostent *hostentry;
|
|
|
|
|
|
|
|
if (name[0] >= '0' && name[0] <= '9')
|
|
|
|
return PartialIPAddress (name, addr);
|
2001-02-26 06:48:02 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
hostentry = gethostbyname (name);
|
|
|
|
if (!hostentry)
|
|
|
|
return -1;
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
addr->family = AF_INET;
|
|
|
|
addr->port = htons (net_hostport);
|
|
|
|
memcpy (addr->ip, hostentry->h_addr_list[0], ADDR_SIZE);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-09 03:35:01 +00:00
|
|
|
__attribute__((pure)) int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_AddrCompare (netadr_t *addr1, netadr_t *addr2)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2011-09-04 00:00:42 +00:00
|
|
|
if (addr1->family != addr2->family)
|
2011-08-22 01:30:35 +00:00
|
|
|
return -2;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
if (memcmp (addr1->ip, addr2->ip, ADDR_SIZE))
|
2001-02-19 21:15:25 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-09-04 00:00:42 +00:00
|
|
|
if (addr1->port != addr2->port)
|
2001-02-19 21:15:25 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-09 03:35:01 +00:00
|
|
|
__attribute__((pure)) int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_GetSocketPort (netadr_t *addr)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2011-09-04 00:00:42 +00:00
|
|
|
return ntohs (addr->port);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2001-02-26 06:48:02 +00:00
|
|
|
int
|
2011-09-04 00:00:42 +00:00
|
|
|
UDP_SetSocketPort (netadr_t *addr, int port)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2011-09-04 00:00:42 +00:00
|
|
|
addr->port = htons (port);
|
2001-02-19 21:15:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|