diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-08-24 11:16:07 +0200 |
| commit | c068f22329d5cc722622a2183bbb22eef2093df7 (patch) | |
| tree | 12d56c1aede67988a55e241364606bfbb4dba933 /src/parsec/nw_udp.cpp | |
| download | openparsec-c068f22329d5cc722622a2183bbb22eef2093df7.tar.xz openparsec-c068f22329d5cc722622a2183bbb22eef2093df7.zip | |
Diffstat (limited to 'src/parsec/nw_udp.cpp')
| -rw-r--r-- | src/parsec/nw_udp.cpp | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/parsec/nw_udp.cpp b/src/parsec/nw_udp.cpp new file mode 100644 index 0000000..4313a9b --- /dev/null +++ b/src/parsec/nw_udp.cpp @@ -0,0 +1,272 @@ +/* + * PARSEC - Platform dependent UDP Functions + * + * $Author: uberlinuxguy $ - $Date: 2004/09/15 12:25:31 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * Copyright (c) Andreas Varga <sid@parsec.org> 1998-2000 + * + * 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 + */ +// compilation flags/debug support +#include "config.h" + +#ifdef SYSTEM_TARGET_WINDOWS + +// C library +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "net_defs.h" +#include "sys_defs.h" + +// network code config +#include "net_conf.h" +#define NEED_WINSOCK2 + +// local module header +#include "net_udpdf.h" +#include "nw_udp.h" + +// proprietary module headers +#include "con_aux.h" +#include "net_game.h" +#include "net_wrap.h" + + +// flags +#define USE_DIRECTED_BROADCASTS + +// required winsock version --------------------------------------------------- +// +#ifdef NEED_WINSOCK2 + #define WINSOCK_MAJOR 2 + #define WINSOCK_MINOR 0 +#else + #define WINSOCK_MAJOR 1 + #define WINSOCK_MINOR 1 +#endif + + +// string constants ----------------------------------------------------------- +// +static char net_game_unavail[] = "Network game not available.\n"; +static char no_api_detected[] = "TCP/IP networking support not found."; +static char winsock_init_ok[] = "WinSock version %d.%d initialized."; +static char winsock_init_error[]= "WinSock %d.%d could not be initialized.\n"; + +// server (destination) ports ------------------------------------------------- +// +extern int server_udp_port; // defined in NET_UDP + +// local ip address strings (host and broadcast in presentation format) ------- +// +extern char local_ip[ MAX_IPADDR_LEN + 1 ]; +extern char local_broadcast[ MAX_IPADDR_LEN + 1 ]; + +// determine local ip address ------------------------------------------------- +// +int UDPs_GetLocalIP() +{ + // get dns name of local host + char hostname[ MAXHOSTNAMELEN ]; + if ( gethostname( hostname, MAXHOSTNAMELEN ) == -1 ) { + MSGOUT( "cannot get local host name." ); + return FALSE; + } + + // resolve host name to hostent info + hostent *hptr = gethostbyname( hostname ); + if ( hptr == NULL ) { + MSGOUT( "DNS error: %s %s.", hostname, hstrerror( h_errno ) ); + return FALSE; + } + if ( hptr->h_addrtype != AF_INET ) { + MSGOUT( "cannot resolve local hostname: illegal address type in DNS entry." ); + return FALSE; + } + + // fetch list of ip addresses for local host + char **addrlist = hptr->h_addr_list; + if ( addrlist[ 0 ] == NULL ) { + return FALSE; + } + + // take either first interface or user-selected interface if valid + int addrid = 0; + for ( int aid = 1; addrlist[ aid ] != NULL; aid++ ) { + if ( aid == NetInterfaceSelect ) { + addrid = aid; + break; + } + } + + // store globally: numeric + memcpy( &LocalNode, addrlist[ addrid ], IP_ADR_LENGTH ); + + // store globally: presentation + inet_ntop( AF_INET, &LocalNode, local_ip, MAX_IPADDR_LEN + 1 ); + + //NOTE: + // the port number appended to the local ip address is only valid + // in the peer-to-peer protocol, since it is the only protocol + // using a well-known port number. the game server and slot server + // protocols use an ephemeral port. for other protocols than + // peer-to-peer this doesn't matter, however, since it need only + // be valid for node address comparisons in order to filter + // broadcast loop-backs. still, for those protocols, it MUST not + // be the server port, or else we would filter all packets from a + // server running on the same machine as the client. therefore, we + // simply use a port number of zero in this case. + + if ( NET_ProtocolPEER() ) { + + // append port number to ip address + UDP_StoreNodePort( &LocalNode, server_udp_port ); + + } else { + + // append zero port number to ip address + UDP_StoreNodePort( &LocalNode, 0 ); + } + + return TRUE; +} + + +// determine broadcast address for local subnet ------------------------------- +// +void UDPs_GetLocalBroadcast() +{ + // use global broadcast + memset( &LocalBroadcast, 0xff, IP_ADR_LENGTH ); + inet_ntop( AF_INET, &LocalBroadcast, local_broadcast, MAX_IPADDR_LEN + 1 ); + + // append port number to ip address + UDP_StoreNodePort( &LocalBroadcast, server_udp_port ); + +#ifdef USE_DIRECTED_BROADCASTS + + //NOTE: + // in case of error we take the global broadcast address as a + // fallback. this might not work everywhere, though. + + // determine real subnet-directed broadcast address + SOCKET sockfd = WSASocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0 ); + if ( sockfd == INVALID_SOCKET ) { + MSGOUT( "GetLocalBroadcast(): can't open socket." ); + return; + } + + DWORD infolen; + INTERFACE_INFO infobuff[ 10 ]; + int wsaerr = WSAIoctl( sockfd, SIO_GET_INTERFACE_LIST, NULL, 0, &infobuff, + sizeof( infobuff ), &infolen, NULL, NULL ); + if ( wsaerr == SOCKET_ERROR ) { + MSGOUT( "GetLocalBroadcast(): ioctl error." ); + return; + } + + CLOSESOCKET( sockfd ); + + // scan all interfaces + int numinfos = infolen / sizeof( INTERFACE_INFO ); + for ( int infoid = 0; infoid < numinfos; infoid++ ) { + + char ifaddr[ MAX_IPADDR_LEN + 1 ]; + SOCKADDR_IN *sa = (SOCKADDR_IN *) &infobuff[ infoid ].iiAddress; + inet_ntop( AF_INET, &sa->sin_addr, ifaddr, MAX_IPADDR_LEN + 1 ); + + DBGTXT( MSGOUT( "found interface %s", ifaddr ); ); + + // fetch broadcast address for interface we are using + if ( strcmp( local_ip, ifaddr ) == 0 ) { + +// sa = (SOCKADDR_IN *) &infobuff[ infoid ].iiBroadcastAddress; + sa = (SOCKADDR_IN *) &infobuff[ infoid ].iiNetmask; + + // store globally: numeric + memcpy( &LocalBroadcast, &sa->sin_addr, IP_ADR_LENGTH ); + + byte *localcast = (byte *) &LocalBroadcast; + byte *localnode = (byte *) &LocalNode; + for ( int pos = 0; pos < IP_ADR_LENGTH; pos++ ) { + if ( localcast[ pos ] == 255 ) { + localcast[ pos ] = localnode[ pos ]; + } else { + localcast[ pos ] = 255; + } + } + + // store globally: presentation + inet_ntop( AF_INET, &LocalBroadcast, local_broadcast, MAX_IPADDR_LEN + 1 ); + DBGTXT( MSGOUT( "taking broadcast addr %s", local_broadcast ); ); + } + } + +#endif // USE_DIRECTED_BROADCASTS + +} + +// init tcp/ip stack (winsock) ------------------------------------------------ +// +int UDPs_InitOSNetAPI() +{ + MSGOUT( "Initializing TCP/IP stack..." ); + + WSADATA wsaData; + word wVersionRequested = MAKE_WORD( WINSOCK_MAJOR, WINSOCK_MINOR ); + + // initialize winsock + if ( WSAStartup( wVersionRequested, &wsaData ) == SOCKET_ERROR ) { + fprintf( stderr, winsock_init_error, WINSOCK_MAJOR, WINSOCK_MINOR ); + MSGOUT( no_api_detected ); + MSGOUT( net_game_unavail ); + return FALSE; + } + + // print information on the version of WinSock found + MSGOUT( winsock_init_ok, + LO_BYTE( wsaData.wHighVersion ), HI_BYTE( wsaData.wHighVersion ) ); + MSGOUT( wsaData.szDescription ); + + return TRUE; +} + + +// close tcp/ip stack (winsock) ----------------------------------------------- +// +void UDPs_KillOSNetAPI() +{ + // winsock cleanup + WSACleanup(); +} + + +#endif // SYSTEM_TARGET_WINDOWS |
