2021-02-06 09:39:32 +01:00
/*
2021-02-06 16:06:31 +01:00
* Copyright ( C ) 2002 - 2019 The DOSBox Team
2021-02-06 09:39:32 +01:00
*
* 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 .
*
2021-02-06 16:06:31 +01:00
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
2021-02-06 09:39:32 +01:00
*/
# include "dosbox.h"
# if C_IPX
# include "dosbox.h"
# include "ipxserver.h"
# include "timer.h"
# include <stdlib.h>
# include <string.h>
# include "ipx.h"
IPaddress ipxServerIp ; // IPAddress for server's listening port
UDPsocket ipxServerSocket ; // Listening server socket
packetBuffer connBuffer [ SOCKETTABLESIZE ] ;
Bit8u inBuffer [ IPXBUFFERSIZE ] ;
IPaddress ipconn [ SOCKETTABLESIZE ] ; // Active TCP/IP connection
UDPsocket tcpconn [ SOCKETTABLESIZE ] ; // Active TCP/IP connections
SDLNet_SocketSet serverSocketSet ;
TIMER_TickHandler * serverTimer ;
Bit8u packetCRC ( Bit8u * buffer , Bit16u bufSize ) {
Bit8u tmpCRC = 0 ;
Bit16u i ;
for ( i = 0 ; i < bufSize ; i + + ) {
tmpCRC ^ = * buffer ;
buffer + + ;
}
return tmpCRC ;
}
/*
static void closeSocket ( Bit16u sockidx ) {
Bit32u host ;
host = ipconn [ sockidx ] . host ;
LOG_MSG ( " IPXSERVER: %d.%d.%d.%d disconnected " , CONVIP ( host ) ) ;
SDLNet_TCP_DelSocket ( serverSocketSet , tcpconn [ sockidx ] ) ;
SDLNet_TCP_Close ( tcpconn [ sockidx ] ) ;
connBuffer [ sockidx ] . connected = false ;
connBuffer [ sockidx ] . waitsize = false ;
}
*/
static void sendIPXPacket ( Bit8u * buffer , Bit16s bufSize ) {
Bit16u srcport , destport ;
Bit32u srchost , desthost ;
Bit16u i ;
Bits result ;
UDPpacket outPacket ;
outPacket . channel = - 1 ;
outPacket . data = buffer ;
outPacket . len = bufSize ;
outPacket . maxlen = bufSize ;
IPXHeader * tmpHeader ;
tmpHeader = ( IPXHeader * ) buffer ;
srchost = tmpHeader - > src . addr . byIP . host ;
desthost = tmpHeader - > dest . addr . byIP . host ;
srcport = tmpHeader - > src . addr . byIP . port ;
destport = tmpHeader - > dest . addr . byIP . port ;
if ( desthost = = 0xffffffff ) {
// Broadcast
for ( i = 0 ; i < SOCKETTABLESIZE ; i + + ) {
if ( connBuffer [ i ] . connected & & ( ( ipconn [ i ] . host ! = srchost ) | | ( ipconn [ i ] . port ! = srcport ) ) ) {
outPacket . address = ipconn [ i ] ;
result = SDLNet_UDP_Send ( ipxServerSocket , - 1 , & outPacket ) ;
if ( result = = 0 ) {
LOG_MSG ( " IPXSERVER: %s " , SDLNet_GetError ( ) ) ;
continue ;
}
//LOG_MSG("IPXSERVER: Packet of %d bytes sent from %d.%d.%d.%d to %d.%d.%d.%d (BROADCAST) (%x CRC)", bufSize, CONVIP(srchost), CONVIP(ipconn[i].host), packetCRC(&buffer[30], bufSize-30));
}
}
} else {
// Specific address
for ( i = 0 ; i < SOCKETTABLESIZE ; i + + ) {
if ( ( connBuffer [ i ] . connected ) & & ( ipconn [ i ] . host = = desthost ) & & ( ipconn [ i ] . port = = destport ) ) {
outPacket . address = ipconn [ i ] ;
result = SDLNet_UDP_Send ( ipxServerSocket , - 1 , & outPacket ) ;
if ( result = = 0 ) {
LOG_MSG ( " IPXSERVER: %s " , SDLNet_GetError ( ) ) ;
continue ;
}
//LOG_MSG("IPXSERVER: Packet sent from %d.%d.%d.%d to %d.%d.%d.%d", CONVIP(srchost), CONVIP(desthost));
}
}
}
}
bool IPX_isConnectedToServer ( Bits tableNum , IPaddress * * ptrAddr ) {
if ( tableNum > = SOCKETTABLESIZE ) return false ;
* ptrAddr = & ipconn [ tableNum ] ;
return connBuffer [ tableNum ] . connected ;
}
static void ackClient ( IPaddress clientAddr ) {
IPXHeader regHeader ;
UDPpacket regPacket ;
Bits result ;
SDLNet_Write16 ( 0xffff , regHeader . checkSum ) ;
SDLNet_Write16 ( sizeof ( regHeader ) , regHeader . length ) ;
SDLNet_Write32 ( 0 , regHeader . dest . network ) ;
PackIP ( clientAddr , & regHeader . dest . addr . byIP ) ;
SDLNet_Write16 ( 0x2 , regHeader . dest . socket ) ;
SDLNet_Write32 ( 1 , regHeader . src . network ) ;
PackIP ( ipxServerIp , & regHeader . src . addr . byIP ) ;
SDLNet_Write16 ( 0x2 , regHeader . src . socket ) ;
regHeader . transControl = 0 ;
regPacket . data = ( Uint8 * ) & regHeader ;
regPacket . len = sizeof ( regHeader ) ;
regPacket . maxlen = sizeof ( regHeader ) ;
regPacket . address = clientAddr ;
// Send registration string to client. If client doesn't get this, client will not be registered
result = SDLNet_UDP_Send ( ipxServerSocket , - 1 , & regPacket ) ;
}
static void IPX_ServerLoop ( ) {
UDPpacket inPacket ;
IPaddress tmpAddr ;
//char regString[] = "IPX Register\0";
Bit16u i ;
Bit32u host ;
Bits result ;
inPacket . channel = - 1 ;
inPacket . data = & inBuffer [ 0 ] ;
inPacket . maxlen = IPXBUFFERSIZE ;
result = SDLNet_UDP_Recv ( ipxServerSocket , & inPacket ) ;
if ( result ! = 0 ) {
// Check to see if incoming packet is a registration packet
// For this, I just spoofed the echo protocol packet designation 0x02
IPXHeader * tmpHeader ;
tmpHeader = ( IPXHeader * ) & inBuffer [ 0 ] ;
// Check to see if echo packet
if ( SDLNet_Read16 ( tmpHeader - > dest . socket ) = = 0x2 ) {
// Null destination node means its a server registration packet
if ( tmpHeader - > dest . addr . byIP . host = = 0x0 ) {
UnpackIP ( tmpHeader - > src . addr . byIP , & tmpAddr ) ;
for ( i = 0 ; i < SOCKETTABLESIZE ; i + + ) {
if ( ! connBuffer [ i ] . connected ) {
// Use prefered host IP rather than the reported source IP
// It may be better to use the reported source
ipconn [ i ] = inPacket . address ;
connBuffer [ i ] . connected = true ;
host = ipconn [ i ] . host ;
LOG_MSG ( " IPXSERVER: Connect from %d.%d.%d.%d " , CONVIP ( host ) ) ;
ackClient ( inPacket . address ) ;
return ;
} else {
if ( ( ipconn [ i ] . host = = tmpAddr . host ) & & ( ipconn [ i ] . port = = tmpAddr . port ) ) {
LOG_MSG ( " IPXSERVER: Reconnect from %d.%d.%d.%d " , CONVIP ( tmpAddr . host ) ) ;
// Update anonymous port number if changed
ipconn [ i ] . port = inPacket . address . port ;
ackClient ( inPacket . address ) ;
return ;
}
}
}
}
}
// IPX packet is complete. Now interpret IPX header and send to respective IP address
sendIPXPacket ( ( Bit8u * ) inPacket . data , inPacket . len ) ;
}
}
void IPX_StopServer ( ) {
TIMER_DelTickHandler ( & IPX_ServerLoop ) ;
SDLNet_UDP_Close ( ipxServerSocket ) ;
}
bool IPX_StartServer ( Bit16u portnum ) {
Bit16u i ;
if ( ! SDLNet_ResolveHost ( & ipxServerIp , NULL , portnum ) ) {
//serverSocketSet = SDLNet_AllocSocketSet(SOCKETTABLESIZE);
ipxServerSocket = SDLNet_UDP_Open ( portnum ) ;
if ( ! ipxServerSocket ) return false ;
for ( i = 0 ; i < SOCKETTABLESIZE ; i + + ) connBuffer [ i ] . connected = false ;
TIMER_AddTickHandler ( & IPX_ServerLoop ) ;
return true ;
}
return false ;
}
# endif