fceux/attic/pc/sdl-netplay.c

225 lines
4.4 KiB
C

#include "sdl.h"
#include <SDL/SDL_net.h>
#include "sdl-netplay.h"
char *ServerHost;
static int LocalPortTCP=0xFCE;
static int LocalPortUDP=0xFCE;
static int RemotePortTCP=0xFCE;
static int RemotePortUDP; /* Not configurable, figured out during handshake. */
static TCPsocket Socket;
static UDPsocket UDPSocket;
static SDLNet_SocketSet set;
static void en32(uint8 *buf, uint32 morp)
{
buf[0]=morp;
buf[1]=morp>>8;
buf[2]=morp>>16;
buf[3]=morp>>24;
}
static uint32 de32(uint8 *morp)
{
return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24));
}
int FCEUD_NetworkConnect(void)
{
IPaddress rip;
SDLNet_Init();
if(netplay==1) /* Be a server. */
{
TCPsocket tmp;
Uint16 p=LocalPortUDP;
SDLNet_ResolveHost(&rip,NULL,LocalPortTCP);
UDPSocket=SDLNet_UDP_Open(&p);
tmp=SDLNet_TCP_Open(&rip);
Socket=SDLNet_TCP_Accept(&tmp);
memcpy(&rip,SDLNet_TCP_GetPeerAddress(Socket),sizeof(IPaddress));
{
uint8 buf[12];
uint32 player=1;
magic=SDL_GetTicks();
SDLNet_Write32(buf,uport);
SDLNet_Write32(buf+4,1);
SDLNet_Write32(buf+8,magic);
SDLNet_TCP_Send(Socket, buf, 12);
/* Get the UDP port the client is waiting for data on. */
SDLNet_TCP_Recv(Socket, buf, 2);
RemotePortUDP=de32(buf);
}
}
else /* Be a client */
{
SDLNet_ResolveHost(&rip,ServerHost,RemotePortTCP);
Socket=SDLNet_TCP_Open(&rip);
{
Uint16 p=LocalPortUDP;
uint8 buf[12];
UDPSocket=SDLNet_UDP_Open(&p);
/* Now, tell the server what local UDP port it should send to. */
en32(buf,p);
SDLNet_TCP_Send(Socket, buf, 4);
/* Get the UDP port from the server we should send data to. */
SDLNet_TCP_Recv(Socket, buf, 12);
RemotePortUDP=de32(buf);
magic=de32(buf+8);
}
set=SDLNet_AllocSocketSet(1);
SDLNet_TCP_AddSocket(set,TCPSocket);
SDLNet_UDP_AddSocket(set,UDPSocket);
} // End client connect code.
rip.port=RemotePortUDP;
SDLNet_UDP_Bind(UDPSocket, 0, &rip);
}
static int CheckUDP(uint8 *packet, int32 len, int32 alt)
{
uint32 crc;
uint32 repcrc;
crc=FCEUI_CRC32(0,packet+4,len+8);
repcrc=de32(packet);
if(crc!=repcrc) return(0); /* CRC32 mismatch, bad packet. */
packet+=4;
if(de32(packet)!=magic) /* Magic number mismatch, bad or spoofed packet. */
return(0);
packet+=4;
if(alt)
{
if(de32(packet)<incounter) /* Time warped packet. */
return(0);
}
else
if(de32(packet)!=incounter) /* Time warped packet. */
return(0);
return(1);
}
/* Be careful where these MakeXXX() functions are used. */
static uint8 *MakeUDP(uint8 *data, int32 len)
{
/* UDP packet data header is 12 bytes in length. */
static uint8 buf[12+32]; // arbitrary 32.
en32(buf+4,magic);
en32(buf+8,outcounter);
memcpy(buf+12,data,len);
en32(buf,FCEUI_CRC32(0,buf+4,8+len));
return(buf);
}
static uint8 *MakeTCP(uint8 *data, int32 len)
{
/* TCP packet data header is 4 bytes in length. */
static uint8 buf[4+32]; // arbitrary 32.
en32(buf,outcounter);
memcpy(buf+4,data,len);
return(buf);
}
#define UDPHEADSIZE 12
#define TCPHEADSIZE 4
void FCEUD_NetworkClose(void)
{
SDLNet_Quit();
}
/* 1 byte to server */
int FCEUD_SendDataToServer(uint8 v,uint8 cmd)
{
UDPpacket upack;
upack.channel=0;
upack.data=MakeUDP(data,1);
upack.len=upack.maxlen=UDPHEADSIZE+1;
upack.status=0;
SDLNet_UDP_Send(UDPSocket,0,&upack);
outcounter++;
return(1);
}
void FCEUD_SendDataToClients(uint8 *data)
{
UDPpacket upack;
SDLNet_TCP_Send(Socket,MakeTCP(data,5),TCPHEADSIZE+5);
upack.channel=0;
upack.data=MakeUDP(data,5);
upack.len=upack.maxlen=UDPHEADSIZE+5;
upack.status=0;
SDLNet_UDP_Send(UDPSocket,0,&upack);
outcounter++;
return(1);
}
int FCEUD_GetDataFromServer(uint8 *data)
{
uint8 buf[128];
NoWaiting&=~2;
while(SDLNet_CheckSockets(set,1)==0)
{
// do something here.
}
if(SDLNet_SocketReady(Socket))
{
SDLNet_TCP_Recv
if(de32(buf)==incounter) /* New packet, keep. */
{
unsigned long beefie;
memcpy(data,buf+TCPHEADSIZE,5);
incounter++;
if(!ioctl(Socket,FIONREAD,&beefie))
if(beefie)
NoWaiting|=2;
return(1);
}
}
if(SDLNet_SocketReady(UDPSocket)
{
}
}