2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 //===========================================================================
26 // Programmer: MrElusive
27 // Last update: TTimo: cross-platform version, l_net library
30 //===========================================================================
32 //#include <windows.h>
37 #include "l_net_wins.h"
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <sys/ioctl.h>
42 #include <netinet/in.h>
43 #include <netinet/tcp.h>
44 #include <arpa/inet.h>
50 #define SOCKET_ERROR -1
51 #define INVALID_SOCKET -1
53 #define WinError WinPrint
58 #define ioctlsocket ioctl
59 #define closesocket close
61 int WSAGetLastError(){
66 typedef struct tag_error_struct
73 typedef struct tag_error_struct
79 #define NET_NAMELEN 64
81 static char my_tcpip_address[NET_NAMELEN];
83 #define DEFAULTnet_hostport 26000
85 #define MAXHOSTNAMELEN 256
87 static int net_acceptsocket = -1; // socket for fielding new connections
88 static int net_controlsocket;
89 static int net_hostport; // udp port number for acceptsocket
90 static int net_broadcastsocket = 0;
91 //static qboolean ifbcastinit = qfalse;
92 //static struct sockaddr_s broadcastaddr;
93 static struct sockaddr_s broadcastaddr;
95 static unsigned long myAddr;
97 ERROR_STRUCT errlist[] = {
98 {EACCES,"EACCES - The address is protected, user is not root"},
99 {EAGAIN,"EAGAIN - Operation on non-blocking socket that cannot return immediatly"},
100 {EBADF, "EBADF - sockfd is not a valid descriptor"},
101 {EFAULT, "EFAULT - The parameter is not in a writable part of the user address space"},
102 {EINVAL,"EINVAL - The socket is already bound to an address"},
103 {ENOBUFS,"ENOBUFS - not enough memory"},
104 {ENOMEM, "ENOMEM - not enough memory"},
105 {ENOTCONN, "ENOTCONN - not connected"},
106 {ENOTSOCK,"ENOTSOCK - Argument is file descriptor not a socket"},
107 {EOPNOTSUPP,"ENOTSUPP - The referenced socket is not of type SOCK_STREAM"},
108 {EPERM, "EPERM - Firewall rules forbid connection"},
112 //===========================================================================
116 // Changes Globals: -
117 //===========================================================================
118 const char *WINS_ErrorMessage( int error ){
122 return "No error occurred";
125 for ( search = 0; errlist[search].errstr; search++ )
127 if ( error == errlist[search].errnum ) {
128 return errlist[search].errstr;
132 return "Unknown error";
133 } //end of the function WINS_ErrorMessage
134 //===========================================================================
138 // Changes Globals: -
139 //===========================================================================
140 int WINS_Init( void ){
142 struct hostent *local;
143 char buff[MAXHOSTNAMELEN];
144 struct sockaddr_s addr;
147 linux doesn't have anything to initialize for the net
148 "Windows .. built for the internet .. the internet .. built with unix"
151 WORD wVersionRequested;
153 wVersionRequested = MAKEWORD( 2, 2 );
155 r = WSAStartup( wVersionRequested, &winsockdata );
158 WinPrint( "Winsock initialization failed.\n" );
163 i = COM_CheckParm ("-udpport");
165 net_hostport = DEFAULTnet_hostport;
167 else if (i < com_argc-1)
168 net_hostport = Q_atoi (com_argv[i+1]);
170 Sys_Error ("WINS_Init: you must specify a number after -udpport");
173 // determine my name & address
174 gethostname( buff, MAXHOSTNAMELEN );
175 local = gethostbyname( buff );
176 if(local && local->h_addr_list && local->h_addr_list[0])
177 myAddr = *(int *)local->h_addr_list[0];
179 myAddr = inet_ntoa("127.0.0.1");
181 // if the quake hostname isn't set, set it to the machine name
182 // if (Q_strcmp(hostname.string, "UNNAMED") == 0)
184 // see if it's a text IP address (well, close enough)
185 for ( p = buff; *p; p++ )
186 if ( ( *p < '0' || *p > '9' ) && *p != '.' ) {
190 // if it is a real name, strip off the domain; we only want the host
192 for ( i = 0; i < 15; i++ )
193 if ( buff[i] == '.' ) {
198 // Cvar_Set ("hostname", buff);
201 //++timo WTF is that net_controlsocket? it's sole purpose is to retrieve the local IP?
202 if ( ( net_controlsocket = WINS_OpenSocket( 0 ) ) == SOCKET_ERROR ) {
203 WinError( "WINS_Init: Unable to open control socket\n" );
206 ( (struct sockaddr_in *)&broadcastaddr )->sin_family = AF_INET;
207 ( (struct sockaddr_in *)&broadcastaddr )->sin_addr.s_addr = INADDR_BROADCAST;
208 ( (struct sockaddr_in *)&broadcastaddr )->sin_port = htons( (u_short)net_hostport );
210 WINS_GetSocketAddr( net_controlsocket, &addr );
211 strcpy( my_tcpip_address, WINS_AddrToString( &addr ) );
212 p = strrchr( my_tcpip_address, ':' );
216 WinPrint( "Winsock Initialized\n" );
218 return net_controlsocket;
219 } //end of the function WINS_Init
220 //===========================================================================
224 // Changes Globals: -
225 //===========================================================================
226 char *WINS_MyAddress( void ){
227 return my_tcpip_address;
228 } //end of the function WINS_MyAddress
229 //===========================================================================
233 // Changes Globals: -
234 //===========================================================================
235 void WINS_Shutdown( void ){
237 WINS_CloseSocket( net_controlsocket );
240 //WinPrint("Winsock Shutdown\n");
241 } //end of the function WINS_Shutdown
242 //===========================================================================
246 // Changes Globals: -
247 //===========================================================================
249 void WINS_Listen(int state)
254 if (net_acceptsocket != -1)
256 if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
257 WinError ("WINS_Listen: Unable to open accept socket\n");
262 if (net_acceptsocket == -1)
264 WINS_CloseSocket (net_acceptsocket);
265 net_acceptsocket = -1;
266 } //end of the function WINS_Listen*/
267 //===========================================================================
271 // Changes Globals: -
272 //===========================================================================
273 int WINS_OpenSocket( int port ){
275 struct sockaddr_in address;
278 if ( ( newsocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == SOCKET_ERROR ) {
279 WinPrint( "WINS_OpenSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
283 if ( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) {
284 WinPrint( "WINS_OpenSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
285 closesocket( newsocket );
289 memset( (char *) &address, 0, sizeof( address ) );
290 address.sin_family = AF_INET;
291 address.sin_addr.s_addr = INADDR_ANY;
292 address.sin_port = htons( (u_short)port );
293 if ( bind( newsocket, (void *)&address, sizeof( address ) ) == -1 ) {
294 WinPrint( "WINS_OpenSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
295 closesocket( newsocket );
300 } //end of the function WINS_OpenSocket
301 //===========================================================================
305 // Changes Globals: -
306 //===========================================================================
307 int WINS_OpenReliableSocket( int port ){
309 struct sockaddr_in address;
310 qboolean _true = 0xFFFFFFFF;
314 if ( ( newsocket = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) {
315 WinPrint( "WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
319 memset( (char *) &address, 0, sizeof( address ) );
320 address.sin_family = AF_INET;
321 address.sin_addr.s_addr = htonl( INADDR_ANY );
322 address.sin_port = htons( (u_short)port );
323 if ( bind( newsocket, (void *)&address, sizeof( address ) ) == -1 ) {
324 WinPrint( "WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
325 closesocket( newsocket );
330 if ( setsockopt( newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof( int ) ) == -1 ) {
331 WinPrint( "WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
332 WinPrint( "setsockopt error\n" );
336 } //end of the function WINS_OpenReliableSocket
337 //===========================================================================
341 // Changes Globals: -
342 //===========================================================================
343 int WINS_Listen( int socket ){
346 if ( ioctlsocket( socket, FIONBIO, &_true ) == -1 ) {
347 WinPrint( "WINS_Listen: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
350 if ( listen( socket, SOMAXCONN ) == SOCKET_ERROR ) {
351 WinPrint( "WINS_Listen: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
355 } //end of the function WINS_Listen
356 //===========================================================================
360 // Changes Globals: -
361 //===========================================================================
362 int WINS_Accept( int socket, struct sockaddr_s *addr ){
363 socklen_t addrlen = sizeof( struct sockaddr_s );
367 newsocket = accept( socket, (struct sockaddr *)addr, &addrlen );
368 if ( newsocket == INVALID_SOCKET ) {
369 if ( errno == EAGAIN ) {
372 WinPrint( "WINS_Accept: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
376 if ( setsockopt( newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof( int ) ) == SOCKET_ERROR ) {
377 WinPrint( "WINS_Accept: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
378 WinPrint( "setsockopt error\n" );
381 } //end of the function WINS_Accept
382 //===========================================================================
386 // Changes Globals: -
387 //===========================================================================
388 int WINS_CloseSocket( int socket ){
390 if (socket == net_broadcastsocket)
391 net_broadcastsocket = 0;
393 // shutdown(socket, SD_SEND);
395 if ( closesocket( socket ) == SOCKET_ERROR ) {
396 WinPrint( "WINS_CloseSocket: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
400 } //end of the function WINS_CloseSocket
401 //===========================================================================
402 // this lets you type only as much of the net address as required, using
403 // the local network components to fill in the rest
407 // Changes Globals: -
408 //===========================================================================
409 static int PartialIPAddress( char *in, struct sockaddr_s *hostaddr ){
418 strcpy( buff + 1, in );
419 if ( buff[1] == '.' ) {
428 if ( *++b < '0' || *b > '9' ) {
431 while ( !( *b < '0' || *b > '9' ) )
432 num = num * 10 + *( b++ ) - '0';
434 addr = ( addr << 8 ) + num;
437 hostaddr->sa_family = AF_INET;
438 ( (struct sockaddr_in *)hostaddr )->sin_port = htons( (u_short)net_hostport );
439 ( (struct sockaddr_in *)hostaddr )->sin_addr.s_addr = ( myAddr & htonl( mask ) ) | htonl( addr );
442 } //end of the function PartialIPAddress
443 //===========================================================================
447 // Changes Globals: -
448 //===========================================================================
449 int WINS_Connect( int socket, struct sockaddr_s *addr ){
451 u_long _true2 = 0xFFFFFFFF;
453 ret = connect( socket, (struct sockaddr *)addr, sizeof( struct sockaddr_s ) );
454 if ( ret == SOCKET_ERROR ) {
455 WinPrint( "WINS_Connect: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
458 if ( ioctlsocket( socket, FIONBIO, &_true2 ) == -1 ) {
459 WinPrint( "WINS_Connect: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
463 } //end of the function WINS_Connect
464 //===========================================================================
468 // Changes Globals: -
469 //===========================================================================
470 int WINS_CheckNewConnections( void ){
473 if ( net_acceptsocket == -1 ) {
477 if ( recvfrom( net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL ) > 0 ) {
478 return net_acceptsocket;
481 } //end of the function WINS_CheckNewConnections
482 //===========================================================================
483 // returns the number of bytes read
484 // 0 if no bytes available
489 // Changes Globals: -
490 //===========================================================================
491 int WINS_Read( int socket, byte *buf, int len, struct sockaddr_s *addr ){
492 socklen_t addrlen = sizeof( struct sockaddr_s );
496 ret = recvfrom( socket, buf, len, 0, (struct sockaddr *)addr, &addrlen );
498 // errno = WSAGetLastError();
500 if ( errno == EAGAIN || errno == ENOTCONN ) {
507 ret = recv( socket, buf, len, 0 );
508 // if there's no data on the socket ret == -1 and errno == EAGAIN
509 // MSDN states that if ret == 0 the socket has been closed
510 // man recv doesn't say anything
514 if ( ret == SOCKET_ERROR ) {
515 // errno = WSAGetLastError();
517 if ( errno == EAGAIN || errno == ENOTCONN ) {
522 if ( ret == SOCKET_ERROR ) {
523 WinPrint( "WINS_Read: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
526 } //end of the function WINS_Read
527 //===========================================================================
531 // Changes Globals: -
532 //===========================================================================
533 int WINS_MakeSocketBroadcastCapable( int socket ){
536 // make this socket broadcast capable
537 if ( setsockopt( socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof( i ) ) < 0 ) {
540 net_broadcastsocket = socket;
543 } //end of the function WINS_MakeSocketBroadcastCapable
544 //===========================================================================
548 // Changes Globals: -
549 //===========================================================================
550 int WINS_Broadcast( int socket, byte *buf, int len ){
553 if ( socket != net_broadcastsocket ) {
554 if ( net_broadcastsocket != 0 ) {
555 WinError( "Attempted to use multiple broadcasts sockets\n" );
557 ret = WINS_MakeSocketBroadcastCapable( socket );
559 WinPrint( "Unable to make socket broadcast capable\n" );
564 return WINS_Write( socket, buf, len, &broadcastaddr );
565 } //end of the function WINS_Broadcast
566 //===========================================================================
567 // returns qtrue on success or qfalse on failure
571 // Changes Globals: -
572 //===========================================================================
573 int WINS_Write( int socket, byte *buf, int len, struct sockaddr_s *addr ){
579 while ( written < len )
581 ret = sendto( socket, &buf[written], len - written, 0, (struct sockaddr *)addr, sizeof( struct sockaddr_s ) );
582 if ( ret == SOCKET_ERROR ) {
583 if ( WSAGetLastError() != EAGAIN ) {
586 //++timo FIXME: what is this used for?
598 while ( written < len )
600 ret = send( socket, buf, len, 0 );
601 if ( ret == SOCKET_ERROR ) {
602 if ( WSAGetLastError() != EAGAIN ) {
605 //++timo FIXME: what is this used for?
614 if ( ret == SOCKET_ERROR ) {
615 WinPrint( "WINS_Write: %s\n", WINS_ErrorMessage( WSAGetLastError() ) );
617 return ( ret == len );
618 } //end of the function WINS_Write
619 //===========================================================================
623 // Changes Globals: -
624 //===========================================================================
625 char *WINS_AddrToString( struct sockaddr_s *addr ){
626 static char buffer[22];
629 haddr = ntohl( ( (struct sockaddr_in *)addr )->sin_addr.s_addr );
630 sprintf( buffer, "%d.%d.%d.%d:%d", ( haddr >> 24 ) & 0xff, ( haddr >> 16 ) & 0xff, ( haddr >> 8 ) & 0xff, haddr & 0xff, ntohs( ( (struct sockaddr_in *)addr )->sin_port ) );
632 } //end of the function WINS_AddrToString
633 //===========================================================================
637 // Changes Globals: -
638 //===========================================================================
639 int WINS_StringToAddr( char *string, struct sockaddr_s *addr ){
640 int ha1, ha2, ha3, ha4, hp;
643 sscanf( string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp );
644 ipaddr = ( ha1 << 24 ) | ( ha2 << 16 ) | ( ha3 << 8 ) | ha4;
646 addr->sa_family = AF_INET;
647 ( (struct sockaddr_in *)addr )->sin_addr.s_addr = htonl( ipaddr );
648 ( (struct sockaddr_in *)addr )->sin_port = htons( (u_short)hp );
650 } //end of the function WINS_StringToAddr
651 //===========================================================================
655 // Changes Globals: -
656 //===========================================================================
657 int WINS_GetSocketAddr( int socket, struct sockaddr_s *addr ){
658 socklen_t addrlen = sizeof( struct sockaddr_s );
661 memset( addr, 0, sizeof( struct sockaddr_s ) );
662 getsockname( socket, (struct sockaddr *)addr, &addrlen );
663 a = ( (struct sockaddr_in *)addr )->sin_addr.s_addr;
664 if ( a == 0 || a == inet_addr( "127.0.0.1" ) ) {
665 ( (struct sockaddr_in *)addr )->sin_addr.s_addr = myAddr;
669 } //end of the function WINS_GetSocketAddr
670 //===========================================================================
674 // Changes Globals: -
675 //===========================================================================
676 int WINS_GetNameFromAddr( struct sockaddr_s *addr, char *name ){
677 struct hostent *hostentry;
679 hostentry = gethostbyaddr( (char *)&( (struct sockaddr_in *)addr )->sin_addr, sizeof( struct in_addr ), AF_INET );
681 strncpy( name, (char *)hostentry->h_name, NET_NAMELEN - 1 );
685 strcpy( name, WINS_AddrToString( addr ) );
687 } //end of the function WINS_GetNameFromAddr
688 //===========================================================================
692 // Changes Globals: -
693 //===========================================================================
694 int WINS_GetAddrFromName( char *name, struct sockaddr_s *addr ){
695 struct hostent *hostentry;
697 if ( name[0] >= '0' && name[0] <= '9' ) {
698 return PartialIPAddress( name, addr );
701 hostentry = gethostbyname( name );
706 addr->sa_family = AF_INET;
707 ( (struct sockaddr_in *)addr )->sin_port = htons( (u_short)net_hostport );
708 ( (struct sockaddr_in *)addr )->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
711 } //end of the function WINS_GetAddrFromName
712 //===========================================================================
716 // Changes Globals: -
717 //===========================================================================
718 int WINS_AddrCompare( struct sockaddr_s *addr1, struct sockaddr_s *addr2 ){
719 if ( addr1->sa_family != addr2->sa_family ) {
723 if ( ( (struct sockaddr_in *)addr1 )->sin_addr.s_addr != ( (struct sockaddr_in *)addr2 )->sin_addr.s_addr ) {
727 if ( ( (struct sockaddr_in *)addr1 )->sin_port != ( (struct sockaddr_in *)addr2 )->sin_port ) {
732 } //end of the function WINS_AddrCompare
733 //===========================================================================
737 // Changes Globals: -
738 //===========================================================================
739 int WINS_GetSocketPort( struct sockaddr_s *addr ){
740 return ntohs( ( (struct sockaddr_in *)addr )->sin_port );
741 } //end of the function WINS_GetSocketPort
742 //===========================================================================
746 // Changes Globals: -
747 //===========================================================================
748 int WINS_SetSocketPort( struct sockaddr_s *addr, int port ){
749 ( (struct sockaddr_in *)addr )->sin_port = htons( (u_short)port );
751 } //end of the function WINS_SetSocketPort