diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a91a9c495..cd5727bcf 100755 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,5 +1,9 @@ D2X-Rebirth Changelog +20070530 +-------- +d2x.ini, SConstruct, arch/linux/arch_ip.cpp, arch/linux/linuxnet.c arch/linux/ukali.c, arch/linux/include/ipx_drv.h, arch/win32/arch_ip.cpp, arch/win32/winnet.c, arch/win32/ipx_drv.h, arch/win32/include/ipx_drv.h, main/ip_base.cpp, main/ip_basec.h, main/inferno.c, main/ipbase.h, main/ipclient.cpp, main/ipclienc.c, main/ipclient.h, main/menu.c, main/network.c, main/playsave.c, main/vers_id.h: Removed old UDP/IP and MCAST4 code; Implemented online-capable UDP/IP interface + 20070527 -------- include/cfile.h, main/inferno.c, main/mission.c, main/movie.c: add add_to_end parameter to cfile_init, allowing custom MIDI music to be found in an add-on hog diff --git a/SConstruct b/SConstruct index 1d5e86c38..faa247d5e 100644 --- a/SConstruct +++ b/SConstruct @@ -17,12 +17,11 @@ D2XMINOR = 52 D2XMICRO = 0 #D2XMICRO = int(SVN_REVISION) -VERSION = str(D2XMAJOR) + '.' + str(D2XMINOR) - +VERSION_STRING = ' v' + str(D2XMAJOR) + '.' + str(D2XMINOR) if (D2XMICRO): - VERSION += '.' + str(D2XMICRO) + VERSION_STRING += '.' + str(D2XMICRO) -print '\n===== ' + PROGRAM_NAME + ' v' + VERSION + ' =====\n' +print '\n===== ' + PROGRAM_NAME + VERSION_STRING + ' =====\n' # installation path PREFIX = '/usr/local/' @@ -168,7 +167,10 @@ common_sources = [ 'misc/strio.c', 'misc/strutil.c', 'texmap/ntmap.c', -'texmap/scanline.c' +'texmap/scanline.c', +'main/ip_base.cpp', +'main/ipclienc.c', +'main/ipclient.cpp', ] # for editor @@ -235,9 +237,8 @@ editor_sources = [ # for *nix arch_unix_sources = [ 'arch/linux/init.c', -'arch/linux/ipx_mcast4.c', -'arch/linux/ipx_udp.c', 'arch/linux/linuxnet.c', +'arch/linux/arch_ip.cpp' ] # for linux @@ -266,12 +267,11 @@ arch_win32_sources = [ 'arch/win32/hmpfile.c', 'arch/win32/init.c', 'arch/win32/ipx_win.c', -'arch/win32/ipx_mcast4.c', -'arch/win32/ipx_udp.c', 'arch/win32/midi.c', 'arch/win32/mono.c', 'arch/win32/winnet.c', 'arch/sdl/digi.c', +'arch/win32/arch_ip.cpp' ] # for Mac OS X @@ -319,7 +319,8 @@ env = Environment(ENV = os.environ) env.ParseConfig('sdl-config --cflags') env.ParseConfig('sdl-config --libs') env.Append(CPPFLAGS = ['-Wall', '-funsigned-char']) -env.Append(CPPDEFINES = [('VERSION', '\\"' + str(VERSION) + '\\"')]) +env.Append(CPPDEFINES = [('D2XMAJOR', '\\"' + str(D2XMAJOR) + '\\"'), ('D2XMINOR', '\\"' + str(D2XMINOR) + '\\"')]) +#env.Append(CPPDEFINES = [('VERSION', '\\"' + str(VERSION) + '\\"')]) env.Append(CPPDEFINES = [('USE_SDLMIXER', sdlmixer)]) env.Append(CPPDEFINES = ['NMONO', 'PIGGY_USE_PAGING', 'NETWORK', 'HAVE_NETIPX_IPX_H', 'NEWDEMO', '_REENTRANT']) env.Append(CPPPATH = ['include', 'main', 'arch/include']) @@ -509,12 +510,12 @@ Help(PROGRAM_NAME + ', SConstruct file help:' + """ + ' sharepath = ' + DATA_DIR + """ Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory - CXX C++ compiler command - CXXFLAGS C++ compiler flags + CXX C++ compiler command + CXXFLAGS C++ compiler flags """) #EOF diff --git a/arch/linux/arch_ip.cpp b/arch/linux/arch_ip.cpp new file mode 100755 index 000000000..49b50fc69 --- /dev/null +++ b/arch/linux/arch_ip.cpp @@ -0,0 +1,220 @@ +/* + * arch_ip.cpp - arch specific udp/ip code. (linux ver) + * added 2000/02/07 Matt Mueller (some code borrowed from ipx_udp.c) + */ + +#include +#include /* for htons & co. */ +#include +#include +#include +#include +#include +#include +extern "C" { +#include "ipx_drv.h" +#include "pstypes.h" +#include "mono.h" +} + +#include "ip_base.h" +#include "ipclient.h" + +static int mysock=-1; +extern int nm_messagebox(char *title, int nchoices, ...); + +/* Do hostname resolve on name "buf" and return the address in buffer "qhbuf". + */ +int arch_ip_queryhost(ip_addr *addr,char *buf,u_short baseport) +{ + struct hostent *he; + char *s; + char c=0; + u_short p; + + if ((s=strrchr(buf,':'))) { + c=*s; + *s='\0'; + p=ip_portshift(baseport,s+1); + } + else p=ip_portshift(baseport,NULL); + he=gethostbyname((char *)buf); + if (s) *s=c; + if (!he) { + msg("Error resolving my hostname \"%s\"",buf); + return -1; //(NULL); + } + if (he->h_addrtype!=AF_INET || he->h_length!=4) { + msg("Error parsing resolved my hostname \"%s\"",buf); + return -1;//(NULL); + } + if (!*he->h_addr_list) { + msg("My resolved hostname \"%s\" address list empty",buf); + return -1;//(NULL); + } + addr->set(4,(u_char*)*he->h_addr_list,p); + + return 0; +} + +#ifdef UDPDEBUG +/* Like dumpraddr() but for structure "sockaddr_in" + */ + +static void dumpaddr(struct sockaddr_in *sin) +{ + unsigned short ports; + u_char qhbuf[6]; + + memcpy(qhbuf+0,&sin->sin_addr,4); + ports=sin->sin_port; + memcpy(qhbuf+4,&ports,2); + dumpraddr(qhbuf); +} +#endif + + +int ip_sendtoca(ip_addr addr,const void *buf,int len){ + struct sockaddr_in toaddr; + if (addr.addrlen()!=4) return 0;//not handled yet + toaddr.sin_family=AF_INET; + memcpy(&toaddr.sin_addr,addr.addr,4); + toaddr.sin_port=*(unsigned short *)(addr.addr+4); +#ifdef UDPDEBUG + printf(MSGHDR "sendtoca((%d) ",len); + addr.dump(); + puts(")."); +#endif + return sendto(mysock,buf,len,0,(struct sockaddr *)&toaddr,sizeof(toaddr)); +} + +/* Find as much as MAX_BRDINTERFACES during local iface autoconfiguration. + * Note that more interfaces can be added during manual configuration + * or host-received-packet autoconfiguration + */ + +#define MAX_BRDINTERFACES 16 + +/* We require the interface to be UP and RUNNING to accept it. + */ + +#define IF_REQFLAGS (IFF_UP|IFF_RUNNING) + +/* We reject any interfaces declared as LOOPBACK type. + */ +#define IF_NOTFLAGS (IFF_LOOPBACK) + +int arch_ip_get_my_addr(u_short myport){ + unsigned cnt=MAX_BRDINTERFACES,i,j; + struct ifconf ifconf; + int sock; + struct sockaddr_in *sinp; + ip_addr addr; + + if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0) + FAIL("Creating socket() failure during broadcast detection:\n%m"); + +#ifdef SIOCGIFCOUNT + if (ioctl(sock,SIOCGIFCOUNT,&cnt)) + { /* msg("Getting iterface count error: %m"); */ } + else + cnt=cnt*2+2; +#endif + + chk(ifconf.ifc_req=(struct ifreq *)alloca((ifconf.ifc_len=cnt*sizeof(struct ifreq)))); + if (ioctl(sock,SIOCGIFCONF,&ifconf)||ifconf.ifc_len%sizeof(struct ifreq)) { + close(sock); + FAIL("ioctl(SIOCGIFCONF) failure during broadcast detection:\n%m"); + } + cnt=ifconf.ifc_len/sizeof(struct ifreq); + + for (i=j=0;isin_family!=AF_INET) continue; + addr.set(4,(ubyte*)&sinp->sin_addr,htons(myport)); +#ifdef UDPDEBUG + printf(MSGHDR"added if "); + addr.dump(); + printf("\n"); +#endif + ip_my_addrs.add(addr); + } + return(0); +} + +int arch_ip_open_socket(int port){ + struct sockaddr_in sin; + int val_one=1; + if ((mysock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) { + mysock = -1; + FAIL("socket() creation failed on port %d:\n%m",port); + } + if (setsockopt(mysock,SOL_SOCKET,SO_BROADCAST,&val_one,sizeof(val_one))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("setsockopt(SO_BROADCAST) failed:\n%m"); + } + sin.sin_family=AF_INET; + sin.sin_addr.s_addr=htonl(INADDR_ANY); + sin.sin_port=htons(port); + + if (bind(mysock,(struct sockaddr *)&sin,sizeof(sin))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("bind() to UDP port %d failed:\n%m",port); + } + + return 0; +} + +void arch_ip_close_socket(void) { + if (mysock<0) { + msg("close w/o open"); + return; + } + if (close(mysock)) + msg("close() failed on CloseSocket D1X ip socket %m"); + mysock=-1; +} + +int arch_ip_recvfrom(char*outbuf,int outbufsize,struct ipx_recv_data *rd){ + struct sockaddr_in fromaddr; + socklen_t fromaddrsize=sizeof(fromaddr); + int size; + static ip_addr ip_fromaddr; + ip_addr *vptr=&ip_fromaddr; + + if ((size=recvfrom(mysock,outbuf,outbufsize,0,(struct sockaddr *)&fromaddr,&fromaddrsize))<0) + return -1; + + if (fromaddr.sin_family!=AF_INET) return -1; + +#ifdef UDPDEBUG + printf(MSGHDR "recvfrom((%d-2=%d),",size,size-2); + dumpaddr(&fromaddr); + puts(")."); +#endif + + ip_fromaddr.set(4,(u_char*)&fromaddr.sin_addr,fromaddr.sin_port); + + memcpy(rd->src_node,&vptr,sizeof(ip_addr*)); + return size; +} + +int arch_ip_PacketReady(void) { + static ipx_socket_t temp; + temp.fd=mysock; + return ipx_general_PacketReady(&temp); +} diff --git a/arch/linux/include/ipx_drv.h b/arch/linux/include/ipx_drv.h index d3d784ac7..478019261 100755 --- a/arch/linux/include/ipx_drv.h +++ b/arch/linux/include/ipx_drv.h @@ -12,24 +12,25 @@ #ifndef _IPX_DRV_H #define _IPX_DRV_H #include +#include "pstypes.h" #define IPX_MANUAL_ADDRESS #define MAX_PACKET_DATA 1500 typedef struct IPXAddressStruct { - u_char Network[4] __attribute__((packed)); - u_char Node[6] __attribute__((packed)); - u_char Socket[2] __attribute__((packed)); + u_char Network[4]; + u_char Node[6]; + u_char Socket[2]; } IPXAddress_t; typedef struct IPXPacketStructure { - u_short Checksum __attribute__((packed)); - u_short Length __attribute__((packed)); - u_char TransportControl __attribute__((packed)); - u_char PacketType __attribute__((packed)); - IPXAddress_t Destination __attribute__((packed)); - IPXAddress_t Source __attribute__((packed)); + u_short Checksum; + u_short Length; + u_char TransportControl; + u_char PacketType; + IPXAddress_t Destination; + IPXAddress_t Source; } IPXPacket_t; typedef struct ipx_socket_struct { @@ -67,6 +68,8 @@ struct ipx_driver { int (*HandleNetgameAuxData)(ipx_socket_t *s, const u_char buf[]); void (*HandleLeaveGame)(ipx_socket_t *s); int (*SendGamePacket)(ipx_socket_t *s, u_char *data, int dataLen); + int (*CheckReadyToJoin)(unsigned char *server, unsigned char *node); + int usepacketnum;//we can save 4 bytes }; int ipx_general_PacketReady(ipx_socket_t *s); diff --git a/arch/linux/linuxnet.c b/arch/linux/linuxnet.c index 0cc472104..d40a9600b 100755 --- a/arch/linux/linuxnet.c +++ b/arch/linux/linuxnet.c @@ -44,8 +44,6 @@ COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #ifdef KALINIX #include "ipx_kali.h" #endif -#include "ipx_udp.h" -#include "ipx_mcast4.h" #include "error.h" #include "../../main/player.h" /* for Players */ #include "../../main/multi.h" /* for NetPlayers */ @@ -92,7 +90,8 @@ int ipx_general_PacketReady(ipx_socket_t *s) { return 0; } -struct ipx_driver *driver = &ipx_udp; +struct ipx_driver *driver; +extern struct ipx_driver ipx_ip; ubyte * ipx_get_my_server_address() { @@ -113,8 +112,7 @@ void arch_ipx_set_driver(int ipx_driver) #ifdef KALINIX case IPX_DRIVER_KALI: driver = &ipx_kali; break; #endif - case IPX_DRIVER_UDP: driver = &ipx_udp; break; - case IPX_DRIVER_MCAST4: driver = &ipx_mcast4; break; + case IPX_DRIVER_UDP: driver = &ipx_ip; break; default: Int3(); } } @@ -188,6 +186,7 @@ void ipx_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *ad Assert(datasize <= MAX_IPX_DATA+4); memcpy(ipx_header.Destination.Network, network, 4); + memcpy(ipx_header.Destination.Node, immediate_address, 6); *(u_short *)ipx_header.Destination.Socket = htons(ipx_socket_data.socket); ipx_header.PacketType = 4; /* Packet Exchange */ diff --git a/arch/linux/ukali.c b/arch/linux/ukali.c index fce010824..9d9fa8c29 100755 --- a/arch/linux/ukali.c +++ b/arch/linux/ukali.c @@ -24,6 +24,8 @@ //added 05/17/99 Matt Mueller - needed to redefine FD_* so that no asm is used #include "checker.h" //end addition -MM +#include "vers_id.h" + int g_sockfd = -1; struct sockaddr_in kalinix_addr; char g_mynodenum[6]; diff --git a/arch/win32/arch_ip.cpp b/arch/win32/arch_ip.cpp new file mode 100755 index 000000000..1a17dba50 --- /dev/null +++ b/arch/win32/arch_ip.cpp @@ -0,0 +1,169 @@ +/* + * arch_ip.cpp - arch specific udp/ip code. (win32 ver) + * added 2000/02/07 Matt Mueller (some code borrowed from ipx_udp.c) + */ + +#include +#include +#include +#include +extern "C" { +#include "ipx_drv.h" +#include "pstypes.h" +#include "mono.h" +//#include "multi.h" +} + +#include "ip_base.h" +#include "ipclient.h" + +static int mysock=-1; +extern int nm_messagebox(char *title, int nchoices, ...); + +/* Do hostname resolve on name "buf" and return the address in buffer "qhbuf". + */ +int arch_ip_queryhost(ip_addr *addr,char *buf,u_short baseport) +{ + struct hostent *he; + char *s; + char c=0; + u_short p; + + if ((s=strrchr(buf,':'))) { + c=*s; + *s='\0'; + p=ip_portshift(baseport,s+1); + } + else p=ip_portshift(baseport,NULL); + he=gethostbyname((char *)buf); + if (s) *s=c; + if (!he) { + msg("Error resolving my hostname \"%s\"",buf); + return -1; + } + if (he->h_addrtype!=AF_INET || he->h_length!=4) { + msg("Error parsing resolved my hostname \"%s\"",buf); + return -1; + } + if (!*he->h_addr_list) { + msg("My resolved hostname \"%s\" address list empty",buf); + return -1; + } + addr->set(4,(u_char*)*he->h_addr_list,p); + + return 0; +} + +#ifdef UDPDEBUG +/* Like dumpraddr() but for structure "sockaddr_in" + */ +static void dumpaddr(struct sockaddr_in *sin) +{ + unsigned short ports; + u_char qhbuf[6]; + + memcpy(qhbuf+0,&sin->sin_addr,4); + ports=sin->sin_port; + memcpy(qhbuf+4,&ports,2); + dumpraddr(qhbuf); +} +#endif + + +int ip_sendtoca(ip_addr addr,const void *buf,int len){ + struct sockaddr_in toaddr; + if (addr.addrlen()!=4) return 0;//not handled yet + toaddr.sin_family=AF_INET; + memcpy(&toaddr.sin_addr,addr.addr,4); + toaddr.sin_port=*(unsigned short *)(addr.addr+4); +#ifdef UDPDEBUG + printf(MSGHDR "sendtoca((%d) ",len); + addr.dump(); + puts(")."); +#endif + return sendto(mysock,(char*)buf,len,0,(struct sockaddr *)&toaddr,sizeof(toaddr)); +} + + +int arch_ip_get_my_addr(u_short myport){ + char buf[256]; + if (gethostname(buf,sizeof(buf))) FAIL("Error getting my hostname"); + + ip_addr ip; + if (ip.dns(buf,myport)) FAIL("Error querying my own hostname \"%s\"",buf); + ip_my_addrs.add(ip); + return 0; +} +int arch_ip_open_socket(int port){ + struct sockaddr_in sin; + int val_one=1; + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + if (WSAStartup( wVersionRequested, &wsaData)) + { + return -1; + } + + if ((mysock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) { + mysock = -1; + FAIL("socket() creation failed on port %d:\n%m",port); + } + if (setsockopt(mysock,SOL_SOCKET,SO_BROADCAST,(char*)&val_one,sizeof(val_one))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("setsockopt(SO_BROADCAST) failed:\n%m"); + } + sin.sin_family=AF_INET; + sin.sin_addr.s_addr=htonl(INADDR_ANY); + sin.sin_port=htons(port); + + if (bind(mysock,(struct sockaddr *)&sin,sizeof(sin))) { + if (close(mysock)) msg("close() failed during error recovery: %m"); + mysock=-1; + FAIL("bind() to UDP port %d failed:\n%m",port); + } + + return 0; +} + +void arch_ip_close_socket(void) { + if (mysock<0) { + msg("close w/o open"); + return; + } + if (closesocket(mysock)) + msg("close() failed on CloseSocket D1X ip socket %m"); + mysock=-1; + WSACleanup(); +} + +int arch_ip_recvfrom(char*outbuf,int outbufsize,struct ipx_recv_data *rd){ + struct sockaddr_in fromaddr; + int fromaddrsize=sizeof(fromaddr); + int size; + static ip_addr ip_fromaddr; + ip_addr *vptr=&ip_fromaddr; + + if ((size=recvfrom(mysock,outbuf,outbufsize,0,(struct sockaddr *)&fromaddr,&fromaddrsize))<0) + return -1; + + if (fromaddr.sin_family!=AF_INET) return -1; + +#ifdef UDPDEBUG + printf(MSGHDR "recvfrom((%d-2=%d),",size,size-2); + dumpaddr(&fromaddr); + puts(")."); +#endif + + ip_fromaddr.set(4,(u_char*)&fromaddr.sin_addr,fromaddr.sin_port); + + memcpy(rd->src_node,&vptr,sizeof(ip_addr*)); + return size; +} +int arch_ip_PacketReady(void) { + ipx_socket_t temp; + temp.fd=mysock; + return ipx_general_PacketReady(&temp); +} diff --git a/arch/win32/include/ipx_drv.h b/arch/win32/include/ipx_drv.h index 0026faf42..3a7e80b4c 100755 --- a/arch/win32/include/ipx_drv.h +++ b/arch/win32/include/ipx_drv.h @@ -26,9 +26,9 @@ #endif typedef struct IPXAddressStruct { - u_char Network[4] __pack__; - u_char Node[6] __pack__; - u_char Socket[2] __pack__; + u_char Network[4]; + u_char Node[6]; + u_char Socket[2]; } IPXAddress_t; typedef struct IPXPacketStructure { @@ -71,6 +71,8 @@ struct ipx_driver { int (*HandleNetgameAuxData)(ipx_socket_t *s, const u_char buf[]); void (*HandleLeaveGame)(ipx_socket_t *s); int (*SendGamePacket)(ipx_socket_t *s, u_char *data, int dataLen); + int (*CheckReadyToJoin)(unsigned char *server, unsigned char *node); + int usepacketnum;//we can save 4 bytes }; int ipx_general_PacketReady(ipx_socket_t *s); diff --git a/arch/win32/ipx_drv.h b/arch/win32/ipx_drv.h index cd26caffd..720952e78 100755 --- a/arch/win32/ipx_drv.h +++ b/arch/win32/ipx_drv.h @@ -26,18 +26,18 @@ #endif typedef struct IPXAddressStruct { - u_char Network[4] __pack__; - u_char Node[6] __pack__; - u_char Socket[2] __pack__; + u_char Network[4]; + u_char Node[6]; + u_char Socket[2]; } IPXAddress_t; typedef struct IPXPacketStructure { - u_short Checksum __pack__; - u_short Length __pack__; - u_char TransportControl __pack__; - u_char PacketType __pack__; - IPXAddress_t Destination __pack__; - IPXAddress_t Source __pack__; + u_short Checksum; + u_short Length; + u_char TransportControl; + u_char PacketType; + IPXAddress_t Destination; + IPXAddress_t Source; } IPXPacket_t; #ifdef _MSC_VER @@ -71,6 +71,8 @@ struct ipx_driver { int (*HandleNetgameAuxData)(ipx_socket_t *s, const u_char buf[]); void (*HandleLeaveGame)(ipx_socket_t *s); int (*SendGamePacket)(ipx_socket_t *s, u_char *data, int dataLen); + int (*CheckReadyToJoin)(unsigned char *server, unsigned char *node); + int usepacketnum;//we can save 4 bytes }; int ipx_general_PacketReady(ipx_socket_t *s); diff --git a/arch/win32/winnet.c b/arch/win32/winnet.c index 8f8ffb903..aac9c29f2 100755 --- a/arch/win32/winnet.c +++ b/arch/win32/winnet.c @@ -32,8 +32,6 @@ COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "error.h" #include "ipx.h" #include "ipx_drv.h" -#include "ipx_udp.h" -#include "ipx_mcast4.h" #include "../../main/player.h" /* for Players */ #include "../../main/multi.h" /* for NetPlayers */ @@ -77,6 +75,7 @@ int ipx_general_PacketReady(ipx_socket_t *s) { } struct ipx_driver *driver = &ipx_win; +extern struct ipx_driver ipx_ip; ubyte * ipx_get_my_server_address() { @@ -92,8 +91,7 @@ void arch_ipx_set_driver(int ipx_driver) { switch(ipx_driver) { case IPX_DRIVER_IPX: driver = &ipx_win; break; - case IPX_DRIVER_UDP: driver = &ipx_udp; break; - case IPX_DRIVER_MCAST4: driver = &ipx_mcast4; break; + case IPX_DRIVER_UDP: driver = &ipx_ip; break; default: Int3(); } } diff --git a/d2x.ini b/d2x.ini index 9b6709c13..f8916fd0b 100755 --- a/d2x.ini +++ b/d2x.ini @@ -5,7 +5,7 @@ ;-nonicefps Disable CPU cycle freeing. Higher CPU load, but game may be smoother ;-hogdir set shared data directory to ;-nohogdir don't try to use shared data directory -;-userdir set user dir to instead of $HOME/.d2x-rebirth +;-userdir set user dir to instead of $HOME/.d2x-rebirth ;-use_players_dir put player files and saved games in Players subdirectory ;-macdata Read (and, for editor, write) mac data files (swap colors) ;-lowmem Lowers animation detail for better performance with low memory @@ -64,10 +64,7 @@ ;-ipxnetwork Use IPX network number ;-kali Use Kali for networking -;-udp Specify options for udp/ip: -; @ Shift udp port base offset -; = Broadcast both local and to HOST_LIST -; + Broadcast only to HOST_LIST -; HOSTS can be any IP or hostname -; HOSTS can also be in the form of
: -; Separate multiple HOSTS with a , +;-ip_nogetmyaddr Prevent autodetection of local ip address +;-ip_myaddr Use as local ip address +;-ip_bind_addr Bind to instead of INADDR_ANY +;-ip_baseport

Use

as offset from normal port (allows multiple instances of d1x to be run on a single computer) diff --git a/main/inferno.c b/main/inferno.c index d28f20648..191577fd8 100755 --- a/main/inferno.c +++ b/main/inferno.c @@ -253,13 +253,10 @@ void print_commandline_help() printf( " -packets %s\n", "Specifies the number of packets per second\n"); printf( " -ipxnetwork %s\n", "Use IPX network number "); printf( " -kali %s\n", "Use Kali for networking"); - printf( " -udp %s\n", "Specify options for udp/ip:"); - printf( " @ %s\n", " Shift udp port base offset"); - printf( " = %s\n", " Broadcast both local and to HOST_LIST"); - printf( " + %s\n", " Broadcast only to HOST_LIST"); - printf( " %s\n", " HOSTS can be any IP or hostname"); - printf( " %s\n", " HOSTS can also be in the form of

:"); - printf( " %s\n", " Separate multiple HOSTS with a ,"); + printf( " -ip_nogetmyaddr %s\n", "Prevent autodetection of local ip address"); + printf( " -ip_myaddr %s\n", "Use as local ip address"); + printf( " -ip_bind_addr %s\n", "Bind to instead of INADDR_ANY"); + printf( " -ip_baseport

%s\n", "Use

as offset from normal port (allows multiple instances of d1x to be run on a single computer)"); #endif // NETWORK #ifndef NDEBUG diff --git a/main/ip_base.cpp b/main/ip_base.cpp new file mode 100755 index 000000000..9f8d472b1 --- /dev/null +++ b/main/ip_base.cpp @@ -0,0 +1,449 @@ +/* + * ip_base.cpp - base for NAT-compatible udp/ip code. + * added 2000/02/07 Matt Mueller + */ +extern "C" { +#include "timer.h" +#include "mono.h" +#include "args.h" +} +#include +#include "ip_base.h" +#include +#ifndef _WIN32 +#include +#endif + +int myport=-1; + +int baseport=UDP_BASEPORT; + +ip_addr_list ip_my_addrs; +ip_peer_list peer_list; + +int ip_handshake_base::fillbuf(ubyte *buf){ + u_int32_t tmp32; + u_int16_t tmp16; + int pos=0; + buf[pos++]=type; + buf[pos++]=state; + pos+=id.fillbuf(buf+pos); + tmp16=htons(iver); + memcpy(buf+pos,&tmp16,2);pos+=2; + tmp32=htonl(tryid); + memcpy(buf+pos,&tmp32,4);pos+=4; + return pos; +} + +int ip_handshake_base::readbuf(ubyte *buf){ + int pos=0; + nopend=1; + type=buf[pos++]; + state=buf[pos++]; + pos+=id.readbuf(buf+pos); + memcpy(&iver,buf+pos,2);pos+=2; + iver=htons(iver); + memcpy(&tryid,buf+pos,4);pos+=4; + tryid=htonl(tryid); + return pos; +} + +void ip_handshake_base::setstate(int newstate){ + if (!nopend){ + if (state&STATE_NEED_RESEND){ + if (!(newstate&STATE_NEED_RESEND)) + peer_list.pendinghandshakes--; + }else{ + if (newstate&STATE_NEED_RESEND) + peer_list.pendinghandshakes++; + } + mprintf((0,"peer_list.pendinghandshakes=%i\n",peer_list.pendinghandshakes)); + } + state=newstate;attempts=0;nextsend=0; +} + +int ip_handshake_base::addstate(int newstate){ + if (state & STATE_ERR){ + setstate((state | newstate) & ~STATE_ERR); + return 2; + } + if ((state | newstate) != state){ + setstate(state | newstate); + return 1; + } + return 0; +} + +int ip_handshake_info::fillbuf(ubyte *buf){ + int pos=ip_handshake_base::fillbuf(buf); + pos+=addr.fillbuf(buf+pos); + return pos; +} + +int ip_handshake_info::readbuf(ubyte *buf){ + int pos=ip_handshake_base::readbuf(buf); + pos+=addr.readbuf(buf+pos); + return pos; +} + +int ip_handshake_relay::fillbuf(ubyte *buf){ + u_int16_t tmp16; + int pos=ip_handshake_base::fillbuf(buf); + pos+=r_id.fillbuf(buf+pos); + tmp16=htons(r_iver); + memcpy(buf+pos,&tmp16,2);pos+=2; + pos+=r_addr.fillbuf(buf+pos); + return pos; +} + +int ip_handshake_relay::readbuf(ubyte *buf){ + int pos=ip_handshake_base::readbuf(buf); + pos+=r_id.readbuf(buf+pos); + memcpy(&r_iver,buf+pos,2);pos+=2; + r_iver=htons(r_iver); + pos+=r_addr.readbuf(buf+pos); + return pos; + +} +ip_handshake_relay::ip_handshake_relay(ip_peer *torelay):ip_handshake_base(1){ + type=IP_CFG_RELAY; + r_id=torelay->id; + r_iver=torelay->iver; + r_addr=torelay->addr; + setstate(STATE_INEEDINFO); +} + +void ip_peer::send_handshake(ip_handshake_base*hsb){ + ubyte buf[256]; + int s=0; + memcpy(buf+s,D1Xcfgid,4);s+=4; + s+=hsb->fillbuf(buf+s); + assert(s<256); + if (addr.goodaddr==NULL){ + ip_addr_list::iterator i; + for (i=addr.begin();i!=addr.end();i++) + ip_sendtoca(*i,buf,s); + }else + ip_sendtoca(*addr.goodaddr,buf,s); + hsb->nextsend=timer_get_approx_seconds()+IP_HS_RETRYTIME; + hsb->attempts++; +} + +bool ip_peer::verify_addr(ip_addr_list &fraddrs){ + int a1=addr.add(fraddrs); + if (a1) + addr.goodaddr=NULL; + + return a1>0; +} + +ip_peer * ip_peer_list::add_1(ip_addr addr){ + ip_peer*n=add_unk(); + n->addr.add(addr); + + return n; +} + +ip_peer * ip_peer_list::add_full(ip_id id, u_int16_t iver,ip_addr_list &addrs){ + ip_peer*n=add_id(id); + n->addr.add(addrs); + n->iver=iver; + mprintf((0,"addfull %i addrs\n",n->addr.naddr)); + return n; +} + +void ip_peer_list::make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs){ + list::iterator unki=find(unknown_peers.begin(),unknown_peers.end(),p); + if (unki!=unknown_peers.end()) + unknown_peers.erase(unki); + p->id=id; + p->iver=iver; + p->addr.add(addrs); + peers.insert(peer_map::value_type(p->id,p)); +} + +ip_peer * ip_peer_list::find_byid(ip_id id){ + peer_map::iterator i=peers.find(id); + if (i!=peers.end()) + return (*i).second; + return NULL; +} + +struct do_find_by_addr : public unary_function { + int j; + ip_addr addr; + bool operator()(ip_peer * p) { + if (p->addr.hasaddr(addr)) + return 1; + return 0; + } +}; + +template +struct pairkiller { + fo *o; + ret operator()(pair &aoeuaoeu) { + return (*o)(aoeuaoeu.second); + } + pairkiller(fo *no):o(no){} +}; + +template +pairkiller pairkill(fo * no){ + return pairkiller(no); +} + +ip_peer * ip_peer_list::find_by_addr(ip_addr addr){ + do_find_by_addr fba; + fba.addr=addr; + peer_map::iterator i=find_if(peers.begin(),peers.end(),pairkill(&fba)); + if (i!=peers.end()) + return (*i).second; + list::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba); + if (j!=unknown_peers.end()) + return (*j); + return NULL; +} + +ip_peer * ip_peer_list::find_unk_by_addr(ip_addr addr){ + do_find_by_addr fba; + fba.addr=addr; + list::iterator j=find_if(unknown_peers.begin(),unknown_peers.end(),fba); + if (j!=unknown_peers.end()) + return (*j); + return NULL; +} + +struct do_peer_handshake : public unary_function{ + fix mintime; + list::iterator i; + ip_handshake_base *hsb; + void operator() (ip_peer* peer) { + for(i=peer->handshakes.begin();i!=peer->handshakes.end();++i){ + hsb=(*i); + //if (hsb->statenextsendstate & STATE_NEED_RESEND) && hsb->nextsendattempts>IP_MAX_HS_ATTEMPTS){ + hsb->setstate(STATE_ERR); + }else{ + peer->send_handshake(hsb); + } + } + } + } +}; + +void ip_peer_list::handshake_frame(void){ + if(pendinghandshakes){ + fix mintime=timer_get_approx_seconds();//try every X seconds + if (pendinghandshake_lasttime(&doph)); + for_each(unknown_peers.begin(),unknown_peers.end(),doph); + } + } +} + +struct do_peer_delete : public unary_function{ + void operator() (ip_peer* peer) { + delete peer; + } +}; + +void ip_peer_list::clear(void){ + do_peer_delete dopd; + for_each(peers.begin(),peers.end(),pairkill(&dopd)); + peers.erase(peers.begin(),peers.end()); + for_each(unknown_peers.begin(),unknown_peers.end(),dopd); + unknown_peers.erase(unknown_peers.begin(),unknown_peers.end()); +} + +ip_peer_list::~ip_peer_list(){ + clear(); +} + + +#ifdef UDPDEBUG +//000a0oeuaoeu + +static void dumpid(unsigned char *a) +{ + printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]); +} +#endif + +int ip_sendtoid(ubyte *id,const void *buf,int len){ + ip_peer *p=peer_list.find_byid(id); + if (!p || p->addr.goodaddr==NULL){ +#ifdef UDPDEBUG + printf(MSGHDR"send to invalid id("); + dumpid(id); + printf(") %p.",p); +#endif + return -1; + } + return ip_sendtoca(*p->addr.goodaddr,buf,len); +} + +void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr){ + ip_peer *p; + switch(buf[0]){ + case IP_CFG_SORRY: + { +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10))); +#endif + + }break; + case IP_CFG_HANDSHAKE: +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i tryid%u\n",ntohs(*(unsigned short*)(buf+8)),(unsigned int)ntohl(*(u_int32_t*)(buf+10))); +#endif + { + ip_handshake_info *hsi=new ip_handshake_info(buf); + hsi->addr.add(fromaddr); + ip_handshake_info *lhsi=NULL; + p=peer_list.find_byid(hsi->id); + if (!p){ + p=peer_list.find_unk_by_addr(fromaddr); + if (p){ + peer_list.make_full(p,hsi->id,hsi->iver,hsi->addr); + } + } + else + p->verify_addr(hsi->addr); + if (!p){ + p=peer_list.add_hsi(hsi); + } + lhsi=p->find_handshake(); + lhsi->tryid=hsi->tryid; + if (p->addr.goodaddr==NULL){ + p->addr.setgoodaddr(fromaddr); + } + if (hsi->state&STATE_INEEDINFO) + lhsi->setstate(STATE_SENDINGINFO); + else + lhsi->setstate(0); + + if (lhsi->state) + p->send_handshake(lhsi); + + delete hsi; + }break; + case IP_CFG_RELAY: + { + ip_peer *rp; + ip_handshake_relay hsr(buf); +#ifdef UDPDEBUG + printf("ip_receive_cfg: %i %i ",buf[0],buf[1]); + dumprid(buf+2); + printf(" v%i r_id ",ntohs(*(unsigned short*)(buf+8))); + hsr.r_id.dump(); + printf(" r_iv%i\n",hsr.r_iver); +#endif + p=peer_list.find_byid(hsr.id); + if (!p) { + mprintf((0,"relay from unknown peer\n")); + break;//hrm. + } + rp=peer_list.find_byid(hsr.r_id); + if (hsr.state&STATE_RELAYREPLY){ + if (!rp) { + mprintf((0,"relay reply for unknown peer\n")); + break;//hrm. + } + ip_handshake_relay *rhsr=p->find_relay(rp->id); + if (!rhsr) + break; + rhsr->setstate(0); +#ifdef UDPDEBUG + printf("**** "); + p->id.dump(); + printf(" is ok with "); + rp->id.dump(); + printf("\n"); +#endif + }else{ + if (!rp) + rp=peer_list.add_full(hsr.r_id,hsr.r_iver,hsr.r_addr); + else + rp->verify_addr(hsr.r_addr); + + if (rp->addr.goodaddr==NULL){ + mprintf((0,"sending relayed handshake\n")); + //handshake with relayed peer + ip_handshake_info *lhsi=rp->find_handshake(); + if (lhsi->addstate(STATE_INEEDINFO)); + rp->send_handshake(lhsi); + }else{ + mprintf((0,"sending relayed reply\n")); + //reply to relayer + ip_handshake_relay rhsr(rp); + rhsr.setstate(STATE_RELAYREPLY); + p->send_handshake(&rhsr); + } + } + }break; + } +} + + + +int ipx_ip_GetMyAddress(void) { + + int i; + u_int32_t myhandshakeid; + + d_srand( timer_get_approx_seconds() ); + + ip_my_addrs.clear(); + + if (!FindArg("-ip_nogetmyaddr")) + arch_ip_get_my_addr(myport);//if we can't get an addr, then we can still probably play, just some NAT configs might not work. + + if ((i=FindArg("-ip_myaddr"))){ + ip_addr ip; + if (!ip.dns(Args[i+1],myport)){ + ip_my_addrs.add(ip); + } + } + + myhandshakeid=htonl(d_rand32()); + if (ip_my_addrs.naddr){ + ip_addr ip=*ip_my_addrs.begin(); + ipx_MyAddress[4]=ip.addr[2]; + ipx_MyAddress[5]=ip.addr[3]; + }else{ + ipx_MyAddress[4]=d_rand()%255; + ipx_MyAddress[5]=d_rand()%255; + } + memcpy(ipx_MyAddress+6,&myhandshakeid,4); + +#ifdef UDPDEBUG + printf(MSGHDR "Using TCP/IP id "); + dumprid(ipx_MyAddress+4); + putchar('\n'); +#endif + return 0; +} +/* Parse PORTSHIFT numeric parameter + */ + +unsigned short ip_portshift(unsigned short baseport, const char *cs) +{ + long port; + unsigned short ports=htons(baseport); + if (cs){ + port=atol(cs); + if (cs[0]=='-' || cs[0]=='+')//relative port + ports=htons(port+baseport); + else + ports=htons(port);//absolute port + } + return ports; +} diff --git a/main/ip_base.h b/main/ip_base.h new file mode 100755 index 000000000..03c55d3f2 --- /dev/null +++ b/main/ip_base.h @@ -0,0 +1,379 @@ +/* + * ip_base.h - base for NAT-compatible udp/ip code. + * added 2000/02/07 Matt Mueller + */ + +#ifndef ___IP_BASE_H +#define ___IP_BASE_H + +#include +#include +#include +extern "C" { +#include "ip_basec.h" +#include "fix.h" +#include "mono.h" +#include "vers_id.h" +#include "timer.h" +} + +using namespace std; + +class ip_addr;//prototype for arch_ip_queryhost + +#include "ipclient.h" +#include + +inline u_int32_t d_rand32(void) { return d_rand() + (d_rand()<<15) + (d_rand()<<30);}//d_rand() only returns 15 bits +void ip_receive_cfg(ubyte *buf,int buflen,ip_addr fromaddr); +extern unsigned char ipx_MyAddress[10]; +unsigned short ip_portshift(unsigned short baseport, const char *cs); + +#define UDP_BASEPORT 31017 +#define UDP_SERV_BASEPORT 30817 +#define PORTSHIFT_TOLERANCE 0x100 +#define MAX_PACKETSIZE 8192 + +// Length HAS TO BE 2! +#define D1Xid "\xd1x" +// Length HAS TO BE 4! +#define D1Xcfgid "\xcfg\xd1x" + + +//cfg packet types +#define IP_CFG_BASE 0 +#define IP_CFG_HANDSHAKE 1 +#define IP_CFG_RELAY 2 +//someone giving us an error (ie, outdated version, etc.) ... not handled yet. +#define IP_CFG_SORRY 3 + + +#define STATE_INEEDINFO 1<<0 +#define STATE_SENDINGINFO 1<<1 +#define STATE_NEED_RESEND (STATE_INEEDINFO) +#define STATE_VALID_STATES (STATE_INEEDINFO | STATE_SENDINGINFO) +#define STATE_RELAYREPLY 1<<6 +#define STATE_ERR 1<<7 + +/* Dump raw form of IP address/port by fancy output to user + */ +#ifdef UDPDEBUG +#include +inline char *ip_hs_statetoa(int state){ + if (!state) + return "NOSTATE"; + if (state&STATE_ERR) + return "ERR"; + if ((state&(STATE_INEEDINFO|STATE_SENDINGINFO))==(STATE_INEEDINFO|STATE_SENDINGINFO)) + return "NEED+SEND"; + if (state&STATE_INEEDINFO) + return "NEED"; + if (state&STATE_SENDINGINFO) + return "SEND"; + return "huh?"; +} + +inline void dumprid(const unsigned char *a) +{ + printf("<%u.%u.%u.%u.%u.%u>",a[0],a[1],a[2],a[3],a[4],a[5]); +} + +inline void dumpraddr(const unsigned char *addr) +{ + ushort port; + printf("[%u.%u.%u.%u]",addr[0],addr[1],addr[2],addr[3]); + port=(unsigned short)ntohs(*(unsigned short *)(addr+4)); + printf(":%d",port); +} +#endif + +class ip_id { + public: + ubyte id[6]; + + int fillbuf(ubyte *buf)const {memcpy(buf,id,6);return 6;}; + int readbuf(const ubyte *buf){memcpy(id,buf,6);return 6;}; + bool operator < (const ip_id &a_id)const {return memcmp(id,a_id.id,6)<0;} + bool operator == (const ip_id &a_id)const {return memcmp(id,a_id.id,6)==0;} + bool operator > (const ip_id &a_id)const {return memcmp(id,a_id.id,6)>0;} + ip_id& operator = (const ip_id &a_id){readbuf(a_id.id);return *this;} +#ifdef UDPDEBUG + void dump(void){dumprid(id);} +#endif + ip_id(ubyte*nid){readbuf(nid);} + ip_id(void){}; +}; + +class ip_addr { + protected: + ubyte alen;//alen stuff is to maybe make ipv6 support easier (if the transition ever actually happens) + public: + ubyte addr[6]; + + int fillbuf(ubyte *buf)const {buf[0]=alen;memcpy(buf+1,addr,alen);return alen+1;}; + int readbuf(const ubyte *buf){ + int l=buf[0]; + if (l==6){ + memcpy(addr,buf+1,6);alen=l; + }else{ + mprintf((0,"ip_addr readbuf bad len %i\n",l)); + memset(addr,0,6);alen=0; + } + return l+1; + }; + bool operator < (const ip_addr &a_addr)const { + if (alen!=a_addr.alen) return alen (const ip_addr &a_addr)const { + if (alen!=a_addr.alen) return alen>a_addr.alen; + return memcmp(addr,a_addr.addr,alen)>0; + } + ip_addr& operator = (const ip_addr &a_addr){alen=a_addr.alen;memcpy(addr,a_addr.addr,6);return *this;} +#ifdef UDPDEBUG + void dump(void)const{dumpraddr(addr);} +#endif + void set(int addrsize,ubyte *naddr,ushort port){ + if (addrsize!=4)return;//not handled yet. + alen=addrsize+2; + memcpy(addr,naddr,addrsize); + memcpy(addr+addrsize,&port,2); + } + int dns(char *address,ushort baseport){ + return arch_ip_queryhost(this,address,baseport); + } + bool ok(void)const{return alen>0;} + int addrlen(void)const{return alen-2;} + ip_addr(void){alen=0;}; +}; + +class ip_addr_list { + protected: + list addrs; + public: + typedef list::iterator iterator; + typedef list::const_iterator const_iterator; + int naddr; + ip_addr *goodaddr; + + iterator begin(void){return addrs.begin();} + iterator end(void){return addrs.end();} + const_iterator begin(void)const{return addrs.begin();} + const_iterator end(void)const{return addrs.end();} + bool hasaddr(ip_addr addr){ + iterator i=find(begin(),end(),addr); + return (i!=addrs.end()); + } + int add(ip_addr addr){ + if (hasaddr(addr)) + return 0; + addrs.push_back(addr); + naddr++; + return 1; + } + int add(const ip_addr_list &na){ + int j=0; + const_iterator i=na.begin(); + for (;i!=na.end();++i) + j+=add(*i); + return j; + } + void setgoodaddr(ip_addr addr){ + iterator i=find(begin(),end(),addr); + if (i!=end()){ + goodaddr=&(*i); + return; + } + addrs.push_back(addr); + goodaddr=&(*addrs.end()); + } + int fillbuf(ubyte *buf)const { + int s=0; + const_iterator i; + buf[s++]=naddr; + for (i=begin();i!=end();++i) + s+=(*i).fillbuf(buf+s); + return s; + } + int readbuf(const ubyte *buf){ + int s=1,n; + ip_addr a; + for (n=buf[0];n;--n){ + s+=a.readbuf(buf+s); + if (a.ok()) + add(a); + } + return s; + } + void clear(void){ + naddr=0; + goodaddr=NULL; + addrs.erase(begin(),end()); + } + + ip_addr_list(const ip_addr_list &nl):addrs(nl.addrs),naddr(nl.naddr){setgoodaddr(*nl.goodaddr);} + ip_addr_list(void):naddr(0),goodaddr(NULL){} +}; + +extern ip_addr_list ip_my_addrs; +extern int ip_sendtoca(ip_addr addr,const void *buf,int len); + +class ip_handshake_base { + public: + ubyte type; + ubyte state; + ip_id id; + u_int16_t iver; + u_int32_t tryid; + + fix nextsend; + int attempts; + int nopend; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + void setrandid(void){tryid=d_rand32() ^ timer_get_approx_seconds();} + void setstate(int newstate); + int addstate(int newstate); + + ip_handshake_base(bool initme=0):type(IP_CFG_BASE){ + nopend=0; + state=0; + setstate(0); + if(initme){ + id=ipx_MyAddress+4; + iver=D2X_IVER; + setrandid(); + } + } + virtual ~ip_handshake_base(){setstate(0);}//decrement pendinghandshakes if needed. +}; + +class ip_handshake_info : public ip_handshake_base { + public: + ip_addr_list addr; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + + ip_handshake_info(ubyte *buf){ + readbuf(buf); + } + ip_handshake_info(void):ip_handshake_base(1){ + type=IP_CFG_HANDSHAKE; + addr=ip_my_addrs; + } +}; + +class ip_peer; +class ip_handshake_relay : public ip_handshake_base { + public: + ip_id r_id; + u_int16_t r_iver; + ip_addr_list r_addr; + + virtual int fillbuf(ubyte *buf); + virtual int readbuf(ubyte *buf); + + ip_handshake_relay(ubyte *buf){ + readbuf(buf); + } + ip_handshake_relay(ip_peer *torelay); +}; + +//max number of times to try to handshake a host +#define IP_MAX_HS_ATTEMPTS 10 +//how often to resend a hand-shake (3 seconds) +#define IP_HS_RETRYTIME (F1_0*3) +//how often (max) to search through the resend loop (1 second) +#define IP_HS_FRAME_RETRYTIME (F1_0) + +class ip_peer { + public: + ip_addr_list addr; + ip_id id; + int iver; + list handshakes; + + void add_hs(ip_handshake_base* hs){ + handshakes.push_back(hs); + } + + ip_handshake_relay* find_relay(ip_id r_id){ + list::iterator i; + ip_handshake_base* hsb; + ip_handshake_relay* hsr; + for (i=handshakes.begin();i!=handshakes.end();++i){ + hsb=(*i); + if (hsb->type==IP_CFG_RELAY){ + hsr=(ip_handshake_relay*)hsb; + if (hsr->r_id==r_id) + return hsr; + } + } + return NULL; + } + ip_handshake_info* find_handshake(void){ + list::iterator i; + ip_handshake_base* hsb; + for (i=handshakes.begin();i!=handshakes.end();++i){ + hsb=(*i); + if (hsb->type==IP_CFG_HANDSHAKE) + return (ip_handshake_info*) hsb; + } + ip_handshake_info *ni=new ip_handshake_info(); + add_hs(ni); + return ni; + } + + void send_handshake(ip_handshake_base*hsb); + bool verify_addr(ip_addr_list &fraddrs); + ip_peer(void){iver=0;} + ~ip_peer(){ + list::iterator i; + for (i=handshakes.begin();i!=handshakes.end();++i){ + delete (*i); + } + } +}; + + +class ip_peer_list { + public: + typedef map > peer_map; + peer_map peers; + list unknown_peers; + int pendinghandshakes; + fix pendinghandshake_lasttime; + + ip_peer * add_id(ip_id id){ + ip_peer*n=new ip_peer(); + n->id=id; + peers.insert(peer_map::value_type(n->id,n)); + return n; + } + ip_peer * add_unk(void){ + ip_peer*n=new ip_peer(); + unknown_peers.push_back(n); + return n; + } + ip_peer * add_1(ip_addr addr); + ip_peer * add_full(ip_id id, u_int16_t iver, ip_addr_list &addrs); + void make_full(ip_peer*p,ip_id id, u_int16_t iver, ip_addr_list &addrs); + ip_peer * add_hsi(ip_handshake_info *hsi){return add_full(hsi->id,hsi->iver,hsi->addr);} + ip_peer * find_byid(ip_id id); + ip_peer * find_by_addr(ip_addr addr); + ip_peer * find_unk_by_addr(ip_addr addr); + void handshake_frame(void); + void clear(void); + ip_peer_list(){ + pendinghandshakes=0; + pendinghandshake_lasttime=0; + } + ~ip_peer_list(); +}; + +extern ip_peer_list peer_list; + +#endif diff --git a/main/ip_basec.h b/main/ip_basec.h new file mode 100755 index 000000000..12a8a4826 --- /dev/null +++ b/main/ip_basec.h @@ -0,0 +1,23 @@ +/* + * ip_basec.h - interface from cpp to c funcs + * added 2000/02/07 Matt Mueller + */ +#ifndef ___IP_BASEC_H +#define ___IP_BASEC_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "pstypes.h" +int ip_sendtoid(ubyte *id,const void *buf,int len); + +int get_MAX_PLAYERS(void); +int get_Netgame_player_connected(int pn); +ubyte * get_Netgame_player_node(int pn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/main/ipclienc.c b/main/ipclienc.c new file mode 100755 index 000000000..3dd60070d --- /dev/null +++ b/main/ipclienc.c @@ -0,0 +1,20 @@ +/* + * ipclienc.h - interface from cpp to c funcs + * added 2000/02/07 Matt Mueller + */ +#include "ip_basec.h" +#include "ipx.h" +#include "network.h" + +void ip_sendtoall(char *buf,int len){ + int j; + for (j=0;j +#ifdef __WINDOWS__ +#include "alloca.h" +#endif +#include "mono.h" +#include "key.h" +#include "text.h" +#include "newmenu.h" +#include "args.h" +void network_init(void); +int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address); +} + +#include "ip_base.h" +#include "ipclient.h" +#ifndef _WIN32 +#include +#endif + +ubyte broadcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +ubyte null_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +extern int Player_num; +extern int Network_send_objects; +extern int N_players; + +int ip_connect_manual(char *textaddr) { + int r; + ubyte buf[1500]; + ip_peer *p; + ip_addr addr; + + if (addr.dns(textaddr,UDP_BASEPORT)) { + nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address"); + return -1; + } +#ifdef UDPDEBUG + printf("connecting to "); + addr.dump(); + printf("\n"); +#endif + + network_init(); + N_players = 0; + + if (!(p=peer_list.find_by_addr(addr))){ + p=peer_list.add_1(addr); + } + + ip_handshake_info *hsi=p->find_handshake(); + hsi->setstate(STATE_INEEDINFO); + + while(hsi->state&STATE_VALID_STATES){ + r=ipx_get_packet_data(buf); + if (r>0) + mprintf((0,MSGHDR "ip_connect_manual: weird, someone sent us normal data\n")); + if (key_inkey()==KEY_ESC) + return 0; + } + + if (hsi->state&STATE_ERR) { + nm_messagebox(TXT_ERROR,1,TXT_OK,"handshake timeout"); + return -1; + } + +// join the Netgame. + + return get_and_show_netgame_info(null_addr,p->id.id,NULL); +} + + +static int ipx_ip_OpenSocket(ipx_socket_t * socket, int oport) { + int i; + if ((i=FindArg("-ip_baseport"))){ + baseport=UDP_BASEPORT+atoi(Args[i+1]); + } + + myport=baseport+(oport - IPX_DEFAULT_SOCKET); + if (arch_ip_open_socket(myport)) return -1; + + if (ipx_ip_GetMyAddress() < 0) FAIL("Error getting my address"); + +#ifdef UDPDEBUG + msg("OpenSocket on D1X socket port %d (%d : %+d) : %+d",myport,oport,oport-IPX_DEFAULT_SOCKET,baseport-UDP_BASEPORT); +#endif + return 0; +} +static void ipx_ip_CloseSocket(ipx_socket_t * socket) { +#ifdef UDPDEBUG + msg("CloseSocket on D1X socket port %d",myport); +#endif + arch_ip_close_socket(); + peer_list.clear(); +} + + + +/* Here we'll send the packet to our host. If it is unicast packet, send + * it to IP address/port as retrieved from IPX address. Otherwise (broadcast) + * we'll repeat the same data to each host in our broadcasting list. + */ + +static int ipx_ip_SendPacket(ipx_socket_t * socket, IPXPacket_t *IPXHeader, + ubyte *data, int dataLen) { + int i=dataLen; + char *buf; + + if (dataLen<0 || dataLen>MAX_PACKETSIZE) { +#ifdef UDPDEBUG + msg("SendPacket enter, dataLen=%d out of range",dataLen); +#endif + return -1; + } + chk(buf=(char*)alloca(2+dataLen)); + memcpy(buf+0,D1Xid ,2); + memcpy(buf+2,data,dataLen); + +#ifdef UDPDEBUG + printf(MSGHDR "sendto((%d),Node=[4] %02X %02X,Socket=%02X %02X,s_port=%u,", + dataLen, + IPXHeader->Destination.Node [4],IPXHeader->Destination.Node [5], + IPXHeader->Destination.Socket[0],IPXHeader->Destination.Socket[1], + ntohs(*(unsigned short *)(IPXHeader->Destination.Socket))); + dumprid(IPXHeader->Destination.Node); + puts(")."); +#endif + + if (memcmp(broadcast_addr,IPXHeader->Destination.Node,6)==0){ + ip_addr brbuf; + brbuf.set(4,IPXHeader->Destination.Node,htons(myport)); + i=ip_sendtoca(brbuf,buf,2+dataLen); + ip_sendtoall(buf,2+dataLen); + }else { + i=ip_sendtoid(IPXHeader->Destination.Node,buf,2+dataLen); + } + + return(i<1?-1:i-1); +} + +/* Here we will receive new packet to the given buffer. Both formats of packets + * are supported, we fallback to old format when first obsolete packet is seen. + * If the (valid) packet is received from unknown host, we will add it to our + * broadcasting list. FIXME: For now such autoconfigured hosts are NEVER removed. + */ + +static int ipx_ip_ReceivePacket(ipx_socket_t * socket, char *outbuf, int outbufsize, + struct ipx_recv_data *rd) { + int size; + size_t offs; + ip_addr *fromaddr; + + if ((size=arch_ip_recvfrom(outbuf,outbufsize,rd))<0) + return -1; + + if (size<2) return -1; + + memcpy(&fromaddr,rd->src_node,sizeof(ip_addr*)); + + if (memcmp(outbuf+0,D1Xid,2)) { + if (memcmp(outbuf+0,D1Xcfgid,4)) { + mprintf((0,MSGHDR"no valid header\n")); + return -1; + } + { + ip_receive_cfg((ubyte*)outbuf+4,size-4,*fromaddr); + } + return 0; + } + else + offs=2; + + memmove(outbuf,outbuf+offs,size-(offs)); + size-=offs; + + rd->src_socket = myport; + rd->dst_socket = myport; + + rd->pkt_type = 0; +#ifdef UDPDEBUG + printf(MSGHDR "ReceivePacket: size=%d,from=",size); + fromaddr->dump(); + putchar('\n'); +#endif + if (ip_my_addrs.hasaddr(*fromaddr)) + memcpy(rd->src_node,ipx_MyAddress+4,6); + else + memset(rd->src_node,0,6); + + return size; +} + +static int ipx_ip_general_PacketReady(ipx_socket_t * socket) { + peer_list.handshake_frame(); + return arch_ip_PacketReady(); +} + +static int ipx_ip_CheckReadyToJoin(ubyte *server, ubyte *node){ + if (Network_send_objects) return 0;//if we are currently letting someone else join, we don't know if this person can join ok. + + ip_peer *p=peer_list.find_byid(node); + if (!p || p->addr.goodaddr==NULL) + return 0; + ip_peer *np; + ip_handshake_relay *hsr; + int j; + int ok,nope=0; + + for (j=0;jid==node)continue;//don't tell them to talk to themselves. + + ok=0; + + hsr=p->find_relay(np->id); + if (!hsr){ + hsr=new ip_handshake_relay(np); + p->add_hs(hsr); + } + if (hsr->state==0) + ok++; + + hsr=np->find_relay(p->id); + if (!hsr){ + hsr=new ip_handshake_relay(p); + np->add_hs(hsr); + } + if (hsr->state==0) + ok++; + if (ok!=2) + nope++; + } + } + if (nope) + return 0; + + return 1; +} + +struct ipx_driver ipx_ip = { + ipx_ip_GetMyAddress, + ipx_ip_OpenSocket, + ipx_ip_CloseSocket, + ipx_ip_SendPacket, + ipx_ip_ReceivePacket, + ipx_ip_general_PacketReady, + NULL, + NULL, + NULL, + NULL, + ipx_ip_CheckReadyToJoin, + 0, //save 4 bytes. udp/ip is completely inaccessable by the other methods, so we don't need to worry about compatibility. +}; diff --git a/main/ipclient.h b/main/ipclient.h new file mode 100755 index 000000000..3c9789472 --- /dev/null +++ b/main/ipclient.h @@ -0,0 +1,59 @@ +/* + * ipclient.h - udp/ip client code + * added 2000/02/07 Matt Mueller + */ +#ifndef __IPCLIENT_H_ +#define __IPCLIENT_H_ + +#include +#include +#ifdef __cplusplus +extern "C"{ +#endif +#include "pstypes.h" +#include "ipx.h" +#include "ipx_drv.h" +#include "newmenu.h" +void ip_sendtoall(char *buf,int len); +int ip_connect_manual(char *textaddr);//make it extern C so that it can be called from .c files. +int arch_ip_get_my_addr(ushort myport); +int arch_ip_open_socket(int port); +void arch_ip_close_socket(void); +int arch_ip_recvfrom(char *outbuf,int outbufsize,struct ipx_recv_data *rd); +int arch_ip_PacketReady(void); +int arch_ip_queryhost(ip_addr *addr,char *buf,ushort baseport); + +int ipx_ip_GetMyAddress(void); + +extern int myport; + +extern int baseport; + + +#ifdef __cplusplus +} +#endif + + +#define MSGHDR "IPX_ip: " + +static inline void msg(const char *fmt,...) +{ + va_list ap; + fputs(MSGHDR,stdout); + va_start(ap,fmt); + vprintf(fmt,ap); + va_end(ap); + putchar('\n'); +} + +#define FAIL(m...) do{ nm_messagebox("Error", 1, "Ok", ##m); return -1; } while (0) + +static inline void chk(void *p){ + if (p) return; + msg("FATAL: Virtual memory exhausted!"); + exit(EXIT_FAILURE); +} + + +#endif diff --git a/main/ipserver.cpp b/main/ipserver.cpp new file mode 100755 index 000000000..af01fe005 --- /dev/null +++ b/main/ipserver.cpp @@ -0,0 +1,74 @@ +/* + * ipserver.cpp - udp/ip dedicated gamelist server + * added 2000/02/07 Matt Mueller + */ + +#include +#include +#include +#include + +#include "ip_base.h" + +extern "C"{ +#include "error.h" +#include "args.h" +#include "u_mem.h" +} + +unsigned char ipx_MyAddress[10]; + +int ipx_general_PacketReady(int fd) { + fd_set set; + struct timeval tv; + + FD_ZERO(&set); + FD_SET(fd, &set); + tv.tv_usec = 50000;//50 ms + tv.tv_sec = 0; + if (select(fd + 1, &set, NULL, NULL, &tv) > 0) + return 1; + else + return 0; +} + +void ip_server_mainloop(void){ + struct ipx_recv_data rd; + int size; + char buf[1500]; + ip_addr *fromaddr; +// fix curtime; + while (1){ + while (arch_ip_PacketReady()) { + if ((size = arch_ip_recvfrom(buf, 1500, &rd)) > 4) { + memcpy(&fromaddr,rd.src_node,sizeof(ip_addr*)); + if (memcmp(buf,D1Xcfgid,4)==0){ + ip_receive_cfg((ubyte*)buf+4,size-4,*fromaddr); + } + } + } + peer_list.handshake_frame(); +// curtime=timer_get_approx_seconds(); + } +} + +void int_handler(int s){ + exit(1); +} + +int main(int argc,char **argv){ + error_init(NULL); + signal(SIGINT,int_handler);//make ctrl-c do cleanup stuff. + InitArgs(argc,argv); +#ifndef NDEBUG + if ( FindArg( "-showmeminfo" ) ) + show_mem_info = 1; // Make memory statistics show +#endif + myport=UDP_SERV_BASEPORT; + if(arch_ip_open_socket(myport)) + return 1; + atexit(arch_ip_close_socket); + if (ipx_ip_GetMyAddress()) + return 2; + ip_server_mainloop(); +} diff --git a/main/ipserver.h b/main/ipserver.h new file mode 100755 index 000000000..b41048bb8 --- /dev/null +++ b/main/ipserver.h @@ -0,0 +1,28 @@ +/* + * ipserver.h - udp/ip standalone server + * added 2000/02/07 Matt Mueller + */ +#ifndef __IPSERVER_H_ +#define __IPSERVER_H_ + +#include "ip_base.h" + +class game_info { + public: + ip_id id; + char *name; + int players; + int maxplayers; + char *mission; + int level; + int gamemode; + int status; +}; + +class serv_generic_info { + public: + ip_id id; + char +}; + +#endif diff --git a/main/menu.c b/main/menu.c index 0f33ea145..812174b6c 100755 --- a/main/menu.c +++ b/main/menu.c @@ -121,8 +121,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #define MENU_JOIN_UDP_NETGAME 31 #define MENU_START_KALI_NETGAME 32 // Kali support copied from d1x #define MENU_JOIN_KALI_NETGAME 33 -#define MENU_START_MCAST4_NETGAME 34 // UDP/IP over multicast networks -#define MENU_JOIN_MCAST4_NETGAME 35 //ADD_ITEM("Start netgame...", MENU_START_NETGAME, -1 ); //ADD_ITEM("Send net message...", MENU_SEND_NET_MESSAGE, -1 ); @@ -151,6 +149,8 @@ void do_detail_level_menu_custom(void); void do_new_game_menu(void); #ifdef NETWORK void do_multi_player_menu(void); +void do_ip_manual_join_menu(); +void ip_connect_manual(); void ipx_set_driver(int ipx_driver); #endif //NETWORK void do_cpu_menu(); @@ -392,27 +392,17 @@ void do_option ( int select) #ifdef NETWORK - //case MENU_START_TCP_NETGAME: - //case MENU_JOIN_TCP_NETGAME: case MENU_START_IPX_NETGAME: case MENU_JOIN_IPX_NETGAME: - case MENU_START_UDP_NETGAME: - case MENU_JOIN_UDP_NETGAME: case MENU_START_KALI_NETGAME: case MENU_JOIN_KALI_NETGAME: - case MENU_START_MCAST4_NETGAME: - case MENU_JOIN_MCAST4_NETGAME: -// load_mission(Builtin_mission_num); #ifdef MACINTOSH Network_game_type = IPX_GAME; #endif -// WIN(ipx_create_read_thread()); switch (select & ~0x1) { - case MENU_START_IPX_NETGAME: ipx_set_driver(IPX_DRIVER_IPX); break; - case MENU_START_UDP_NETGAME: ipx_set_driver(IPX_DRIVER_UDP); break; - case MENU_START_KALI_NETGAME: ipx_set_driver(IPX_DRIVER_KALI); break; - case MENU_START_MCAST4_NETGAME: ipx_set_driver(IPX_DRIVER_MCAST4); break; - default: Int3(); + case MENU_START_IPX_NETGAME: ipx_set_driver(IPX_DRIVER_IPX); break; + case MENU_START_KALI_NETGAME: ipx_set_driver(IPX_DRIVER_KALI); break; + default: Int3(); } if ((select & 0x1) == 0) // MENU_START_*_NETGAME @@ -421,30 +411,15 @@ void do_option ( int select) network_join_game(); break; -#ifdef MACINTOSH - case MENU_START_APPLETALK_NETGAME: -// load_mission(Builtin_mission_num); - #ifdef MACINTOSH - Network_game_type = APPLETALK_GAME; - #endif + case MENU_START_UDP_NETGAME: + ipx_set_driver(IPX_DRIVER_UDP); network_start_game(); break; + case MENU_JOIN_UDP_NETGAME: + ipx_set_driver(IPX_DRIVER_UDP); + do_ip_manual_join_menu(); + break; - case MENU_JOIN_APPLETALK_NETGAME: -// load_mission(Builtin_mission_num); - #ifdef MACINTOSH - Network_game_type = APPLETALK_GAME; - #endif - network_join_game(); - break; -#endif -#if 0 - case MENU_START_TCP_NETGAME: - case MENU_JOIN_TCP_NETGAME: - nm_messagebox (TXT_SORRY,1,TXT_OK,"Not available in shareware version!"); - // DoNewIPAddress(); - break; -#endif case MENU_START_SERIAL: com_main_menu(); break; @@ -1365,8 +1340,6 @@ void do_multi_player_menu() int old_game_mode; do { -// WIN(ipx_destroy_read_thread()); - old_game_mode = Game_mode; num_options = 0; @@ -1374,27 +1347,16 @@ void do_multi_player_menu() ADD_ITEM(TXT_START_IPX_NET_GAME, MENU_START_IPX_NETGAME, -1); ADD_ITEM(TXT_JOIN_IPX_NET_GAME, MENU_JOIN_IPX_NETGAME, -1); #endif //NATIVE_IPX - //ADD_ITEM(TXT_START_TCP_NET_GAME, MENU_START_TCP_NETGAME, -1); - //ADD_ITEM(TXT_JOIN_TCP_NET_GAME, MENU_JOIN_TCP_NETGAME, -1); ADD_ITEM("Start UDP/IP Netgame", MENU_START_UDP_NETGAME, -1); ADD_ITEM("Join UDP/IP Netgame\n", MENU_JOIN_UDP_NETGAME, -1); - ADD_ITEM("Start Multicast UDP/IP Netgame", MENU_START_MCAST4_NETGAME, -1); - ADD_ITEM("Join Multicast UDP/IP Netgame\n", MENU_JOIN_MCAST4_NETGAME, -1); #ifdef KALINIX ADD_ITEM("Start Kali Netgame", MENU_START_KALI_NETGAME, -1); ADD_ITEM("Join Kali Netgame\n", MENU_JOIN_KALI_NETGAME, -1); #endif // KALINIX -#ifdef MACINTOSH - ADD_ITEM("Start Appletalk Netgame", MENU_START_APPLETALK_NETGAME, -1 ); - ADD_ITEM("Join Appletalk Netgame\n", MENU_JOIN_APPLETALK_NETGAME, -1 ); -#endif - -// ADD_ITEM(TXT_MODEM_GAME, MENU_START_SERIAL, -1); - choice = newmenu_do1( NULL, TXT_MULTIPLAYER, num_options, m, NULL, choice ); - if ( choice > -1 ) + if ( choice > -1 ) do_option(menu_choice[choice]); if (old_game_mode != Game_mode) @@ -1429,44 +1391,45 @@ void ipx_set_driver(int ipx_driver) Network_active = 1; } else { switch(ipx_error) { - case IPX_NOT_INSTALLED: con_printf(CON_VERBOSE, "%s\n", TXT_NO_NETWORK); break; - case IPX_SOCKET_TABLE_FULL: con_printf(CON_VERBOSE, "%s 0x%x.\n", TXT_SOCKET_ERROR, IPX_DEFAULT_SOCKET+socket); break; - case IPX_NO_LOW_DOS_MEM: con_printf(CON_VERBOSE, "%s\n", TXT_MEMORY_IPX ); break; - default: con_printf(CON_VERBOSE, "%s %d", TXT_ERROR_IPX, ipx_error ); + case IPX_NOT_INSTALLED: con_printf(CON_VERBOSE, "%s\n", TXT_NO_NETWORK); break; + case IPX_SOCKET_TABLE_FULL: con_printf(CON_VERBOSE, "%s 0x%x.\n", TXT_SOCKET_ERROR, IPX_DEFAULT_SOCKET+socket); break; + case IPX_NO_LOW_DOS_MEM: con_printf(CON_VERBOSE, "%s\n", TXT_MEMORY_IPX ); break; + default: con_printf(CON_VERBOSE, "%s %d", TXT_ERROR_IPX, ipx_error ); } con_printf(CON_VERBOSE, "%s\n",TXT_NETWORK_DISABLED); - Network_active = 0; // Assume no network + Network_active = 0; // Assume no network } ipx_read_user_file("descent.usr"); ipx_read_network_file("descent.net"); - //@@if (FindArg("-dynamicsockets")) - //@@ Network_allow_socket_changes = 1; - //@@else - //@@ Network_allow_socket_changes = 0; } else { con_printf(CON_VERBOSE, "%s\n", TXT_NETWORK_DISABLED); - Network_active = 0; // Assume no network + Network_active = 0; // Assume no network } } -void DoNewIPAddress () - { - newmenu_item m[4]; - char IPText[30]; - int choice; +void do_ip_manual_join_menu() +{ + int menu_choice[3]; + newmenu_item m[3]; + int choice = 0, num_options = 0; + int old_game_mode; + char buf[128]=""; - m[0].type=NM_TYPE_TEXT; m[0].text = "Enter an address or hostname:"; - m[1].type=NM_TYPE_INPUT; m[1].text_len = 50; m[1].text = IPText; - IPText[0]=0; + do { + old_game_mode = Game_mode; + num_options = 0; - choice = newmenu_do( NULL, "Join a TCPIP game", 2, m, NULL ); + m[num_options].type = NM_TYPE_INPUT; m[num_options].text=buf; m[num_options].text_len=128;menu_choice[num_options]=-1; num_options++; - if (choice==-1 || m[1].text[0]==0) - return; + choice = newmenu_do1( NULL, "ENTER IP OR HOSTNAME", num_options, m, NULL, choice ); - nm_messagebox (TXT_SORRY,1,TXT_OK,"That address is not valid!"); - } + if ( choice > -1 ) + ip_connect_manual(buf); + if (old_game_mode != Game_mode) + break; // leave menu + } while( choice > -1 ); +} #endif // NETWORK #ifdef GP2X diff --git a/main/network.c b/main/network.c index 472f0f6d0..434bdefe0 100755 --- a/main/network.c +++ b/main/network.c @@ -363,6 +363,10 @@ void network_release_registered_game(void); #endif +// ugly global fellows for the big wait in directIP connection +ubyte *Ext_server=NULL; +ubyte *Ext_node=NULL; + void network_init(void) { @@ -1695,8 +1699,12 @@ void network_send_all_info_request(char type,int which_security) if (Network_game_type == IPX_GAME) { memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 ); memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 ); - - send_broadcast_sequence_packet(me); + if (Ext_server==NULL || Ext_node==NULL){ + send_broadcast_sequence_packet(me); + } + else { + send_internetwork_sequence_packet( me, Ext_server,Ext_node); + } #ifdef MACINTOSH } else { me.player.network.appletalk.node = appletalk_get_my_node(); @@ -1765,7 +1773,10 @@ void network_send_endlevel_sub(int player_num) { endlevel_info end; - int i, j; + int i; +#ifdef WORDS_BIGENDIAN + int j; +#endif // Send an endlevel packet for a player end.type = PID_ENDLEVEL; @@ -1778,8 +1789,6 @@ network_send_endlevel_sub(int player_num) for (i = 0; i < MAX_PLAYERS; i++) for (j = 0; j < MAX_PLAYERS; j++) end.kill_matrix[i][j] = INTEL_SHORT(end.kill_matrix[i][j]); -#else - j = j; // to satisfy compiler #endif if (Players[player_num].connected == 1) // Still playing @@ -2329,9 +2338,7 @@ void network_process_packet(ubyte *data, int length ) network_send_lite_info(their); break; - case PID_SEND_ALL_GAMEINFO: - if (length != SEQUENCE_PACKET_SIZE) { mprintf ((0,"WARNING! Recieved invalid size for PID_SEND_ALL_GAMEINFO\n")); @@ -4638,11 +4645,10 @@ void network_do_big_wait(int choice) else #endif data = packet; - + switch (data[0]) { case PID_GAME_INFO: - if (Network_game_type == IPX_GAME) { receive_full_netgame_packet(data, &TempNetInfo); } else { @@ -4687,7 +4693,6 @@ void network_do_big_wait(int choice) break; case PID_PLAYERSINFO: mprintf ((0,"Got a PID_PLAYERSINFO!\n")); - if (Network_game_type == IPX_GAME) { #ifndef WORDS_BIGENDIAN temp_info=(AllNetPlayers_info *)data; @@ -4804,7 +4809,7 @@ void network_listen() NetSecurityFlag=NETSECURITY_OFF; i=1; - if (Network_game_type == IPX_GAME) { +// if (Network_game_type == IPX_GAME) { size = ipx_get_packet_data( packet ); while ( size > 0) { network_process_packet( packet, size ); @@ -4812,17 +4817,17 @@ void network_listen() break; size = ipx_get_packet_data( packet ); } - #ifdef MACINTOSH - } else { - size = appletalk_get_packet_data( apacket ); - while ( size > 0) { - network_process_packet( apacket, size ); - if (++i>loopmax) - break; - size = appletalk_get_packet_data( apacket ); - } - #endif - } +// #ifdef MACINTOSH +// } else { +// size = appletalk_get_packet_data( apacket ); +// while ( size > 0) { +// network_process_packet( apacket, size ); +// if (++i>loopmax) +// break; +// size = appletalk_get_packet_data( apacket ); +// } +// #endif +// } } int network_wait_for_playerinfo() @@ -6489,3 +6494,141 @@ int HoardEquipped() } return (checked); } + +int network_do_join_game() +{ + if (Active_games[0].game_status == NETSTAT_ENDLEVEL) + { + nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_NET_GAME_BETWEEN2); + return 0; + } + + // Check for valid mission name + if (!load_mission_by_name(Active_games[0].mission_name)) + { + nm_messagebox(NULL, 1, TXT_OK, TXT_MISSION_NOT_FOUND); + return 0; + } + + if (!network_wait_for_all_info (0)) + { + nm_messagebox (TXT_SORRY,1,TXT_OK,"There was a join error!"); + Network_status = NETSTAT_BROWSING; // We are looking at a game menu + Ext_server=NULL; + Ext_node=NULL; + return 0; + } + + Network_status = NETSTAT_BROWSING; // We are looking at a game menu + Ext_server=NULL; + Ext_node=NULL; + + if (!can_join_netgame(&Active_games[0], &ActiveNetPlayers[0])) + { + if (Active_games[0].numplayers == Active_games[0].max_numplayers) + nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_GAME_FULL); + else + nm_messagebox(TXT_SORRY, 1, TXT_OK, TXT_IN_PROGRESS); + return 0; + } + + // Choice is valid, prepare to join in + + memcpy (&Netgame, &Active_games[0], sizeof(netgame_info)); + memcpy (&NetPlayers,TempPlayersInfo,sizeof(AllNetPlayers_info)); + + Difficulty_level = Netgame.difficulty; + MaxNumNetPlayers = Netgame.max_numplayers; + change_playernum_to(1); + + network_set_game_mode(Netgame.gamemode); + + StartNewLevel(Netgame.levelnum, 0); + + return 1; // look ma, we're in a game!!! +} + +int show_game_stats(netgame_info game) +{ + char rinfo[512],*info=rinfo; + char *NetworkModeNames[]={"Anarchy","Team Anarchy","Robo Anarchy","Cooperative","Capture the Flag","Hoard","Team Hoard","Unknown"}; + int c; + + memset(info,0,sizeof(char)*256); + + info+=sprintf(info,"\nConnected to\n\"%s\"\n",game.game_name); + + if(!game.mission_title) + info+=sprintf(info,"Level: Descent2: CounterStrike"); + else + info+=sprintf(info,game.mission_title); + + info+=sprintf (info," - Lvl %i",game.levelnum); + info+=sprintf (info,"\n\nDifficulty: %s",MENU_DIFFICULTY_TEXT(game.difficulty)); + info+=sprintf (info,"\nGame Mode: %s",NetworkModeNames[game.gamemode]); + info+=sprintf (info,"\nPlayers: %i/%i",game.numconnected,game.max_numplayers); + + while (1){ + c=nm_messagebox("WELCOME", 1, "JOIN GAME", rinfo); + if (c==0) + return 1; + else + return 0; + } +} + +int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address){ + sequence_packet me; + fix nextsend; + int numsent; + fix curtime; + + if (setjmp(LeaveGame)) + return 0; + + num_active_games = 0; + Network_games_changed = 0; + Network_status = NETSTAT_BROWSING; + memset(Active_games, 0, sizeof(netgame_info)*MAX_ACTIVE_NETGAMES); + + nextsend=0;numsent=0; + + while (1){ + curtime=timer_get_fixed_seconds(); + if (nextsend=5) + return 0;//timeout + nextsend=curtime+F1_0*3; + numsent++; + mprintf((0, "Sending game_list request.\n")); + memcpy( me.player.callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 ); + memcpy( me.player.network.ipx.node, ipx_get_my_local_address(), 6 ); + memcpy( me.player.network.ipx.server, ipx_get_my_server_address(), 4 ); + me.type = PID_GAME_LIST; //get GAME_LIST - more infos follow later while big wait! + if (net_address != NULL) + send_sequence_packet( me, server,node,net_address); + else + send_internetwork_sequence_packet(me, server, node); + } + + network_listen(); + + if (Network_games_changed){ + if (num_active_games<1){ + Network_games_changed=0; + continue; + } + if (show_game_stats(Active_games[0])) { + Ext_server=server; + Ext_node=node; + return (network_do_join_game()); + } + else + return 0; + } + if (key_inkey()==KEY_ESC) + return 0; + + } + return 0; +} diff --git a/main/playsave.c b/main/playsave.c index 42aeb8a98..af7a6f5d9 100755 --- a/main/playsave.c +++ b/main/playsave.c @@ -65,6 +65,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "u_mem.h" #include "strio.h" #include "physfsx.h" +#include "vers_id.h" #define SAVE_FILE_ID MAKE_SIG('D','P','L','R') diff --git a/main/vers_id.h b/main/vers_id.h index 96d828dd5..180276b3e 100755 --- a/main/vers_id.h +++ b/main/vers_id.h @@ -8,12 +8,16 @@ #ifndef _VERS_ID #define _VERS_ID -#ifndef VERSION -# define VERSION +#define VERSION_TYPE "Full Version" + +#ifdef D2XMICRO +#define VERSION D2XMAJOR "." D2XMINOR "." D2XMICRO +#else +#define VERSION D2XMAJOR "." D2XMINOR #endif -#define VERSION_TYPE "Full Version" #define DESCENT_VERSION "D2X-Rebirth v" VERSION -#define D2X_IVER (D2XMAJOR*10000+D2XMINOR*100+D2XMICRO) +// #define D2X_IVER (D2XMAJOR*10000+D2XMINOR*100+D2XMICRO) +#define D2X_IVER (atoi(D2XMAJOR)*1000+atoi(D2XMINOR)*10) #endif /* _VERS_ID */