31 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
41 #include <sys/select.h>
47 #include "../../idlib/precompiled.h"
59 #define MAX_INTERFACES 32
68 static void NetadrToSockadr(
const netadr_t *
a,
struct sockaddr_in *
s ) {
69 memset(s, 0,
sizeof(*s));
72 s->sin_family = AF_INET;
74 s->sin_port = htons( (
short)a->
port );
75 *(
int *) &s->sin_addr = -1;
77 s->sin_family = AF_INET;
79 *(
int *) &s->sin_addr = *(
int *) &a->
ip;
80 s->sin_port = htons( (
short)a->
port );
89 static void SockadrToNetadr(
struct sockaddr_in *
s,
netadr_t *
a) {
90 unsigned int ip = *(
int *)&s->sin_addr;
92 a->
port = ntohs( s->sin_port );
95 if ( ip == INADDR_LOOPBACK ) {
107 static bool ExtractPort(
const char *
src,
char *buf,
int bufsize,
int *port ) {
109 strncpy( buf, src, bufsize );
110 p = buf; p +=
Min( bufsize - 1, (
int)strlen( src ) ); *p =
'\0';
111 p = strchr( buf,
':' );
116 *port = strtol( p+1,
NULL, 10 );
117 if ( ( *port == 0 && errno == EINVAL ) ||
129 static bool StringToSockaddr(
const char *s,
struct sockaddr_in *sadr,
bool doDNSResolve ) {
134 memset( sadr, 0,
sizeof( *sadr ) );
135 sadr->sin_family = AF_INET;
139 if (s[0] >=
'0' && s[0] <=
'9') {
140 if ( !inet_aton( s, &sadr->sin_addr ) ) {
142 if ( !ExtractPort( s, buf,
sizeof( buf ), &port ) ) {
145 if ( !inet_aton( buf, &sadr->sin_addr ) ) {
148 sadr->sin_port = htons( port );
150 }
else if ( doDNSResolve ) {
153 if ( ExtractPort( s, buf,
sizeof( buf ), &port ) ) {
154 sadr->sin_port = htons( port );
156 if ( !( h = gethostbyname( buf ) ) ) {
159 *(
int *) &sadr->sin_addr =
160 *(
int *) h->h_addr_list[0];
172 struct sockaddr_in sadr;
174 if ( !StringToSockaddr( s, &sadr, doDNSResolve ) ) {
178 SockadrToNetadr( &sadr, a );
214 common->
Printf(
"Sys_IsLANAddress: ID_NOLANADDRESS\n" );
231 p_ip = (
unsigned long *)&adr.
ip[0];
233 if( ( netint[i].ip & netint[i].
mask ) == ( ip & netint[
i].
mask ) ) {
258 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] ) {
264 common->
Printf(
"Sys_CompareNetAdrBase: bad address type\n" );
279 unsigned int ip,
mask;
280 struct ifaddrs *ifap, *ifp;
284 if( getifaddrs( &ifap ) < 0 ) {
285 common->
FatalError(
"InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) );
289 for( ifp = ifap; ifp; ifp = ifp->ifa_next ) {
290 if ( ifp->ifa_addr->sa_family != AF_INET )
293 if ( !( ifp->ifa_flags & IFF_UP ) )
296 if ( !ifp->ifa_addr )
299 if ( !ifp->ifa_netmask )
302 ip = ntohl( *(
unsigned long *)&ifp->ifa_addr->sa_data[2] );
303 mask = ntohl( *(
unsigned long *)&ifp->ifa_netmask->sa_data[2] );
305 if ( ip == INADDR_LOOPBACK ) {
309 (
unsigned char)ifp->ifa_addr->sa_data[2],
310 (
unsigned char)ifp->ifa_addr->sa_data[3],
311 (
unsigned char)ifp->ifa_addr->sa_data[4],
312 (
unsigned char)ifp->ifa_addr->sa_data[5] );
314 (
unsigned char)ifp->ifa_netmask->sa_data[2],
315 (
unsigned char)ifp->ifa_netmask->sa_data[3],
316 (
unsigned char)ifp->ifa_netmask->sa_data[4],
317 (
unsigned char)ifp->ifa_netmask->sa_data[5] );
329 unsigned int ip,
mask;
333 s = socket( AF_INET, SOCK_DGRAM, 0 );
336 if (
ioctl( s, SIOCGIFCONF, &ifc ) < 0 ) {
337 common->
FatalError(
"InitNetworking: SIOCGIFCONF error - %s\n", strerror( errno ) );
341 while ( ifindex < ifc.ifc_len ) {
342 common->
Printf(
"found interface %s - ", ifc.ifc_buf + ifindex );
344 ifr = (ifreq*)( ifc.ifc_buf + ifindex );
345 if (
ioctl( s, SIOCGIFADDR, ifr ) < 0 ) {
346 common->
Printf(
"SIOCGIFADDR failed: %s\n", strerror( errno ) );
348 if ( ifr->ifr_addr.sa_family != AF_INET ) {
351 ip = ntohl( *(
unsigned long *)&ifr->ifr_addr.sa_data[2] );
352 if ( ip == INADDR_LOOPBACK ) {
356 (
unsigned char)ifr->ifr_addr.sa_data[2],
357 (
unsigned char)ifr->ifr_addr.sa_data[3],
358 (
unsigned char)ifr->ifr_addr.sa_data[4],
359 (
unsigned char)ifr->ifr_addr.sa_data[5] );
361 if (
ioctl( s, SIOCGIFNETMASK, ifr ) < 0 ) {
362 common->
Printf(
" SIOCGIFNETMASK failed: %s\n", strerror( errno ) );
364 mask = ntohl( *(
unsigned long *)&ifr->ifr_addr.sa_data[2] );
365 if ( ip != INADDR_LOOPBACK ) {
367 (
unsigned char)ifr->ifr_addr.sa_data[2],
368 (
unsigned char)ifr->ifr_addr.sa_data[3],
369 (
unsigned char)ifr->ifr_addr.sa_data[4],
370 (
unsigned char)ifr->ifr_addr.sa_data[5] );
378 ifindex +=
sizeof( ifreq );
393 if ( net_interface ) {
394 common->
Printf(
"Opening IP socket: %s:%i\n", net_interface, port );
396 common->
Printf(
"Opening IP socket: localhost:%i\n", port );
399 if ( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == -1 ) {
400 common->
Printf(
"ERROR: IPSocket: socket: %s", strerror( errno ) );
405 if (
ioctl( newsocket, FIONBIO, &on ) == -1 ) {
411 if ( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (
char *) &i,
sizeof(i) ) == -1 ) {
412 common->
Printf(
"ERROR: IPSocket: setsockopt SO_BROADCAST:%s\n", strerror( errno ) );
416 if ( !net_interface || !net_interface[ 0 ]
418 address.sin_addr.s_addr = INADDR_ANY;
420 StringToSockaddr( net_interface, &
address,
true );
426 address.sin_port = htons((
short) port);
431 if ( bind( newsocket, (
const struct sockaddr *)&
address,
sizeof(
address ) ) == -1 ) {
432 common->
Printf(
"ERROR: IPSocket: bind: %s\n", strerror( errno ) );
439 if ( (
unsigned int)(getsockname( newsocket, (
struct sockaddr *)&
address, (
socklen_t*)&len )) == -1 ) {
440 common->
Printf(
"ERROR: IPSocket: getsockname: %s\n", strerror( errno ) );
444 SockadrToNetadr( &
address, bound_to );
489 struct sockaddr_in from;
496 fromlen =
sizeof( from );
497 ret = recvfrom(
netSocket, data, maxSize, 0, (
struct sockaddr *) &from, (
socklen_t *) &fromlen );
500 if (errno == EWOULDBLOCK || errno == ECONNREFUSED) {
504 common->
DPrintf(
"idPort::GetPacket recvfrom(): %s\n", strerror( errno ) );
510 SockadrToNetadr( &from, &net_from );
530 return GetPacket( net_from, data, size, maxSize );
536 tv.
tv_sec = timeout / 1000;
537 tv.
tv_usec = ( timeout % 1000 ) * 1000;
540 if ( errno == EINTR ) {
541 common->
DPrintf(
"idPort::GetPacketBlocking: select EINTR\n" );
544 common->
Error(
"idPort::GetPacketBlocking: select failed: %s\n", strerror( errno ) );
552 struct sockaddr_in from;
554 fromlen =
sizeof( from );
555 ret = recvfrom(
netSocket, data, maxSize, 0, (
struct sockaddr *)&from, (
socklen_t *)&fromlen );
558 common->
DPrintf(
"idPort::GetPacketBlocking: %s\n", strerror( errno ) );
562 SockadrToNetadr( &from, &net_from );
574 struct sockaddr_in addr;
577 common->
Warning(
"idPort::SendPacket: bad address type NA_BAD - ignored" );
585 NetadrToSockadr( &to, &addr );
587 ret = sendto(
netSocket, data, size, 0, (
struct sockaddr *) &addr,
sizeof(addr) );
635 struct sockaddr_in sadr;
637 common->
Printf(
"Couldn't resolve server name \"%s\"\n", host );
644 common->
Printf(
"\"%s\" resolved to %i.%i.%i.%i:%i\n", host,
646 NetadrToSockadr(&
address, &sadr);
652 if ((
fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
654 common->
Printf(
"ERROR: idTCP::Init: socket: %s\n", strerror(errno));
658 if ( connect(
fd, (
const sockaddr *)&sadr,
sizeof( sadr ) ) == -1 ) {
659 common->
Printf(
"ERROR: idTCP::Init: connect: %s\n", strerror( errno ) );
666 if ((status = fcntl(
fd, F_GETFL, 0)) != -1) {
667 status |= O_NONBLOCK;
668 status = fcntl(
fd, F_SETFL, status);
671 common->
Printf(
"ERROR: idTCP::Init: fcntl / O_NONBLOCK: %s\n", strerror(errno));
706 #if defined(_GNU_SOURCE)
708 if ( ( nbytes = TEMP_FAILURE_RETRY( read(
fd, data, size ) ) ) == -1 ) {
711 nbytes = read(
fd, data, size );
712 }
while ( nbytes == -1 && errno == EINTR );
713 if ( nbytes == -1 ) {
715 if (errno == EAGAIN) {
718 common->
Printf(
"ERROR: idTCP::Read: %s\n", strerror(errno));
725 common->
DPrintf(
"idTCP::Read: read 0 bytes - assume connection closed\n" );
738 static void got_SIGPIPE(
int signum ) {
750 struct sigaction bak_action;
751 struct sigaction action;
753 action.sa_handler = got_SIGPIPE;
754 sigemptyset( &action.sa_mask );
757 if ( sigaction( SIGPIPE, &action, &bak_action ) != 0 ) {
758 common->
Printf(
"ERROR: idTCP::Write: failed to set temporary SIGPIPE handler\n" );
763 #if defined(_GNU_SOURCE)
765 if ( ( nbytes = TEMP_FAILURE_RETRY ( write(
fd, data, size ) ) ) == -1 ) {
768 nbytes = write(
fd, data, size );
769 }
while ( nbytes == -1 && errno == EINTR );
770 if ( nbytes == -1 ) {
772 common->
Printf(
"ERROR: idTCP::Write: %s\n", strerror( errno ) );
777 if ( sigaction( SIGPIPE, &bak_action,
NULL ) != 0 ) {
778 common->
Printf(
"ERROR: idTCP::Write: failed to reset SIGPIPE handler\n" );
bool Init(const char *host, short port)
static int snPrintf(char *dest, int size, const char *fmt,...) id_attribute((format(printf
int Write(void *data, int size)
assert(prefInfo.fullscreenBtn)
void Sys_InitNetworking(void)
bool Sys_IsLANAddress(const netadr_t adr)
bool Sys_CompareNetAdrBase(const netadr_t a, const netadr_t b)
idCVar net_ip("net_ip","localhost", CVAR_SYSTEM,"local IP address")
idCVar net_port("net_port","", CVAR_SYSTEM|CVAR_INTEGER,"local IP port number")
bool Sys_StringToNetAdr(const char *s, netadr_t *a, bool doDNSResolve)
int Icmp(const char *text) const
#define ioctl(a, b, c, d)
bool GetPacket(netadr_t &from, void *data, int &size, int maxSize)
void SendPacket(const netadr_t to, const void *data, int size)
net_interface netint[MAX_INTERFACES]
GLsizei GLsizei GLenum GLenum const GLvoid * data
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
bool InitForPort(int portNumber)
int Read(void *data, int size)
GLubyte GLubyte GLubyte a
virtual void Printf(const char *fmt,...) id_attribute((format(printf
const char * Sys_NetAdrToString(const netadr_t a)
const char * GetString(void) const
bool GetPacketBlocking(netadr_t &from, void *data, int &size, int maxSize, int timeout)
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
virtual void Error(const char *fmt,...) id_attribute((format(printf
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
ID_INLINE T Min(T x, T y)