494 lines
12 KiB
C++
494 lines
12 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2002 Xodnizel
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "../../md5.h"
|
|
|
|
static int recv_tcpwrap(uint8 *buf, int len);
|
|
static void NetStatAdd(char *text);
|
|
|
|
static HWND netwin=0;
|
|
|
|
static char *netstatt[64];
|
|
static int netstattcount=0;
|
|
static int netlocalplayers = 1;
|
|
|
|
static char *netplayhost = 0;
|
|
static char *netplaynick = 0;
|
|
static char *netgamekey = 0;
|
|
static char *netpassword = 0;
|
|
static int remotetport=0xFCE;
|
|
|
|
static SOCKET Socket=INVALID_SOCKET;
|
|
|
|
static int wsainit=0;
|
|
|
|
int FCEUDnetplay = 0;
|
|
static void WSE(char *ahh)
|
|
{
|
|
char tmp[256];
|
|
sprintf(tmp,"*** Winsock: %s",ahh);
|
|
NetStatAdd(tmp);
|
|
}
|
|
|
|
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));
|
|
}
|
|
static void FixCDis(HWND hParent, int how);
|
|
void FCEUD_NetworkClose(void)
|
|
{
|
|
NetStatAdd("*** Connection lost.");
|
|
if(netwin)
|
|
{
|
|
SetDlgItemText(netwin,250,"Connect");
|
|
FixCDis(netwin,1);
|
|
}
|
|
if(Socket!=INVALID_SOCKET)
|
|
{
|
|
closesocket(Socket);
|
|
Socket=INVALID_SOCKET;
|
|
}
|
|
|
|
if(wsainit)
|
|
{
|
|
WSACleanup();
|
|
wsainit=0;
|
|
}
|
|
/* Make sure blocking is returned to normal once network play is stopped. */
|
|
NoWaiting&=~2;
|
|
FCEUDnetplay = 0;
|
|
FCEUI_NetplayStop();
|
|
}
|
|
static void FixCDis(HWND hParent, int how)
|
|
{
|
|
int x;
|
|
|
|
for(x=200;x<=206;x++)
|
|
EnableWindow( GetDlgItem(hParent,x),how);
|
|
}
|
|
static void GetSettings(HWND hwndDlg)
|
|
{
|
|
char buf[256];
|
|
char **strs[4]={&netplayhost,&netplaynick,&netgamekey,&netpassword};
|
|
int ids[4]={200,203,205,206};
|
|
int x;
|
|
|
|
for(x=0;x<4;x++)
|
|
{
|
|
GetDlgItemText(hwndDlg,ids[x],buf,256);
|
|
if(*strs[x])
|
|
{
|
|
free(*strs[x]);
|
|
*strs[x] = 0;
|
|
}
|
|
if(buf[0])
|
|
{
|
|
*strs[x] = (char*)malloc(strlen(buf) + 1); //mbg merge 7/17/06 added cast
|
|
strcpy(*strs[x], buf);
|
|
}
|
|
}
|
|
remotetport = GetDlgItemInt(hwndDlg,201,0,0);
|
|
netlocalplayers=1 + SendDlgItemMessage(hwndDlg,204,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
|
|
}
|
|
|
|
static void NetStatAdd(char *text)
|
|
{
|
|
int x;
|
|
uint32 totallen = 0;
|
|
char *textbuf;
|
|
|
|
if(!netwin) return;
|
|
if(netstattcount>=64) free(netstatt[netstattcount&63]);
|
|
|
|
if(!(netstatt[netstattcount&63]=(char*)malloc(strlen(text)+1))) //mbg merge 7/17/06 added cast
|
|
return;
|
|
strcpy(netstatt[netstattcount&63],text);
|
|
netstattcount++;
|
|
|
|
if(netstattcount>=64)
|
|
{
|
|
for(x=netstattcount&63;;)
|
|
{
|
|
totallen += strlen(netstatt[x]);
|
|
x=(x+1)&63;
|
|
if(x==(netstattcount&63)) break;
|
|
totallen += 2;
|
|
}
|
|
|
|
totallen++; // NULL
|
|
textbuf = (char *)malloc(totallen); //mbg merge 7/17/06 added cast
|
|
textbuf[0] = 0;
|
|
|
|
for(x=netstattcount&63;;)
|
|
{
|
|
strcat(textbuf,netstatt[x]);
|
|
x=(x+1)&63;
|
|
if(x==(netstattcount&63)) break;
|
|
strcat(textbuf,"\r\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(x=0;x<netstattcount;x++)
|
|
{
|
|
totallen += strlen(netstatt[x]);
|
|
if(x<(netstattcount-1))
|
|
totallen += 2;
|
|
}
|
|
totallen++;
|
|
textbuf = (char*)malloc(totallen); //mbg merge 7/17/06 added cast
|
|
textbuf[0] = 0;
|
|
for(x=0;x<netstattcount;x++)
|
|
{
|
|
strcat(textbuf,netstatt[x]);
|
|
if(x<(netstattcount-1))
|
|
strcat(textbuf,"\r\n");
|
|
}
|
|
}
|
|
SetDlgItemText(netwin,101,textbuf);
|
|
free(textbuf);
|
|
SendDlgItemMessage(netwin,101,EM_LINESCROLL,0,32767);
|
|
}
|
|
|
|
void FCEUD_NetplayText(uint8 *text)
|
|
{
|
|
NetStatAdd((char*)text); //mbg merge 7/17/06 added cast
|
|
}
|
|
|
|
int FCEUD_NetworkConnect(void)
|
|
{
|
|
WSADATA WSAData;
|
|
SOCKADDR_IN sockin; /* I want to play with fighting robots. */ /* clack clack clack razzzzzzzzzz */
|
|
SOCKET TSocket;
|
|
int netdivisor;
|
|
|
|
if(WSAStartup(MAKEWORD(1,1),&WSAData))
|
|
{
|
|
NetStatAdd("*** Error initializing WIndows Sockets.");
|
|
return(0);
|
|
}
|
|
wsainit=1;
|
|
|
|
if( (TSocket=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
|
|
{
|
|
WSE("Error creating stream socket.");
|
|
FCEUD_NetworkClose();
|
|
return(0);
|
|
}
|
|
|
|
memset(&sockin,0,sizeof(sockin));
|
|
sockin.sin_family=AF_INET;
|
|
|
|
{
|
|
struct hostent *phostentb;
|
|
unsigned long hadr;
|
|
int sockin_len;
|
|
|
|
sockin.sin_port=0;
|
|
sockin.sin_addr.s_addr=INADDR_ANY;
|
|
sockin_len=sizeof(sockin);
|
|
|
|
hadr=inet_addr(netplayhost);
|
|
|
|
if(hadr!=INADDR_NONE)
|
|
sockin.sin_addr.s_addr=hadr;
|
|
else
|
|
{
|
|
NetStatAdd("*** Looking up host name...");
|
|
if(!(phostentb=gethostbyname((const char *)netplayhost)))
|
|
{
|
|
WSE("Error getting host network information.");
|
|
closesocket(TSocket);
|
|
FCEUD_NetworkClose();
|
|
return(0);
|
|
}
|
|
memcpy((char *)&sockin.sin_addr,((PHOSTENT)phostentb)->h_addr,((PHOSTENT)phostentb)->h_length);
|
|
}
|
|
|
|
sockin.sin_port=htons(remotetport);
|
|
NetStatAdd("*** Connecting to remote host...");
|
|
if(connect(TSocket,(PSOCKADDR)&sockin,sizeof(sockin))==SOCKET_ERROR)
|
|
{
|
|
WSE("Error connecting to remote host.");
|
|
closesocket(TSocket);
|
|
FCEUD_NetworkClose();
|
|
return(0);
|
|
}
|
|
Socket=TSocket;
|
|
NetStatAdd("*** Sending initialization data to server...");
|
|
|
|
{
|
|
uint8 *sendbuf;
|
|
uint8 buf[1];
|
|
uint32 sblen;
|
|
|
|
sblen = 4 + 16 + 16 + 64 + 1 + (netplaynick?strlen(netplaynick):0);
|
|
sendbuf = (uint8*)malloc(sblen); //mbg merge 7/17/06 added cast
|
|
memset(sendbuf, 0, sblen);
|
|
|
|
en32(sendbuf, sblen - 4);
|
|
|
|
if(netgamekey)
|
|
{
|
|
struct md5_context md5;
|
|
uint8 md5out[16];
|
|
|
|
md5_starts(&md5);
|
|
md5_update(&md5, GI->MD5, 16);
|
|
md5_update(&md5, (uint8*)netgamekey, strlen(netgamekey)); //mbg merge 7/17/06 added cast
|
|
md5_finish(&md5, md5out);
|
|
memcpy(sendbuf + 4, md5out, 16);
|
|
}
|
|
else
|
|
memcpy(sendbuf + 4, GI->MD5, 16);
|
|
|
|
if(netpassword)
|
|
{
|
|
struct md5_context md5;
|
|
uint8 md5out[16];
|
|
|
|
md5_starts(&md5);
|
|
md5_update(&md5, (uint8*)netpassword, strlen(netpassword)); //mbg merge 7/17/06 added cast
|
|
md5_finish(&md5, md5out);
|
|
memcpy(sendbuf + 4 + 16, md5out, 16);
|
|
}
|
|
|
|
memset(sendbuf + 4 + 16 + 16, 0, 64);
|
|
sendbuf[4 + 16 + 16 + 64] = netlocalplayers;
|
|
|
|
if(netplaynick)
|
|
memcpy(sendbuf + 4 + 16 + 16 + 64 + 1,netplaynick,strlen(netplaynick));
|
|
|
|
send(Socket, (char*)sendbuf, sblen, 0); //mbg merge 7/17/06 added cast
|
|
free(sendbuf);
|
|
|
|
recv_tcpwrap(buf, 1);
|
|
netdivisor = buf[0];
|
|
}
|
|
}
|
|
|
|
|
|
FCEUI_NetplayStart(netlocalplayers,netdivisor);
|
|
NetStatAdd("*** Connection established.");
|
|
|
|
FCEUDnetplay = 1;
|
|
char tcpopt = 1; //mbg merge 7/17/06 changed to char
|
|
if(setsockopt(TSocket, IPPROTO_TCP, TCP_NODELAY, &tcpopt, sizeof(int)))
|
|
puts("Nodelay fail");
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
int FCEUD_SendData(void *data, uint32 len)
|
|
{
|
|
send(Socket, (char*)data, len ,0); //mbg merge 7/17/06 added cast
|
|
return(1);
|
|
}
|
|
|
|
static int recv_tcpwrap(uint8 *buf, int len)
|
|
{
|
|
fd_set fdoo;
|
|
int t;
|
|
struct timeval popeye;
|
|
|
|
popeye.tv_sec=0;
|
|
popeye.tv_usec=100000;
|
|
|
|
while(len)
|
|
{
|
|
FD_ZERO(&fdoo);
|
|
FD_SET(Socket,&fdoo);
|
|
|
|
switch(select(0,&fdoo,0,0,&popeye))
|
|
{
|
|
case 0: //BlockingCheck();
|
|
continue;
|
|
case SOCKET_ERROR:return(0);
|
|
}
|
|
|
|
t=recv(Socket,(char*)buf,len,0); //mbg merge 7/17/06 added csat
|
|
if(t<=0) return(0);
|
|
len -= t;
|
|
buf += t;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
int FCEUD_RecvData(void *data, uint32 len)
|
|
{
|
|
NoWaiting&=~2;
|
|
|
|
for(;;)
|
|
{
|
|
fd_set funfun;
|
|
struct timeval popeye;
|
|
|
|
popeye.tv_sec=0;
|
|
popeye.tv_usec=100000;
|
|
|
|
FD_ZERO(&funfun);
|
|
FD_SET(Socket,&funfun);
|
|
|
|
switch(select(0,&funfun,0,0,&popeye))
|
|
{
|
|
case 0:continue;
|
|
case SOCKET_ERROR:return(0);
|
|
}
|
|
|
|
if(FD_ISSET(Socket,&funfun))
|
|
{
|
|
if(recv_tcpwrap((uint8*)data,len)>0) //mbg merge 7/17/06 added cast
|
|
{
|
|
unsigned long beefie;
|
|
if(!ioctlsocket(Socket,FIONREAD,&beefie))
|
|
if(beefie)
|
|
NoWaiting|=2;
|
|
return(1);
|
|
}
|
|
else
|
|
return(0);
|
|
}
|
|
else
|
|
return(0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CFGSTRUCT NetplayConfig[]={
|
|
AC(remotetport),
|
|
AC(netlocalplayers),
|
|
ACS(netgamekey),
|
|
ACS(netplayhost),
|
|
ACS(netplaynick),
|
|
ACS(netpassword),
|
|
ENDCFGSTRUCT
|
|
};
|
|
|
|
|
|
static BOOL CALLBACK NetCon(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_CLOSE:
|
|
GetSettings(hwndDlg);
|
|
DestroyWindow(hwndDlg);
|
|
netwin=0;
|
|
FCEUD_NetworkClose();
|
|
break;
|
|
case WM_COMMAND:
|
|
if(HIWORD(wParam)==BN_CLICKED)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case 250:
|
|
if(FCEUDnetplay)
|
|
{
|
|
FCEUD_NetworkClose();
|
|
SetDlgItemText(hwndDlg,250,"Connect");
|
|
FixCDis(hwndDlg,1);
|
|
}
|
|
else if(GI)
|
|
{
|
|
GetSettings(hwndDlg);
|
|
if(FCEUD_NetworkConnect())
|
|
{
|
|
SetDlgItemText(hwndDlg,250,"Disconnect");
|
|
FixCDis(hwndDlg,0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if(HIWORD(wParam)==EN_CHANGE && Socket!=INVALID_SOCKET)
|
|
{
|
|
char buf[1024];
|
|
int t;
|
|
|
|
|
|
t=GetDlgItemText(hwndDlg,102,buf,1024);
|
|
buf[1023]=0;
|
|
|
|
if(strchr(buf,'\r'))
|
|
{
|
|
char *src,*dest;
|
|
|
|
src=dest=buf;
|
|
|
|
while(*src)
|
|
{
|
|
if(*src != '\n' && *src != '\r')
|
|
{
|
|
*dest = *src;
|
|
dest++;
|
|
}
|
|
src++;
|
|
}
|
|
*dest = 0;
|
|
FCEUI_NetplayText((uint8*)buf); //mbg merge 7/17/06 added cast
|
|
SetDlgItemText(hwndDlg,102,"");
|
|
}
|
|
}
|
|
break;
|
|
case WM_INITDIALOG:
|
|
if(netplayhost)
|
|
SetDlgItemText(hwndDlg,200,netplayhost);
|
|
SetDlgItemInt(hwndDlg,201,remotetport,0);
|
|
if(netplaynick)
|
|
SetDlgItemText(hwndDlg,203,netplaynick);
|
|
if(netgamekey)
|
|
SetDlgItemText(hwndDlg,205,netgamekey);
|
|
if(netpassword)
|
|
SetDlgItemText(hwndDlg,206,netpassword);
|
|
|
|
{
|
|
int x;
|
|
char buf[8];
|
|
for(x=0;x<4;x++)
|
|
{
|
|
sprintf(buf,"%d",x+1);
|
|
SendDlgItemMessage(hwndDlg,204,CB_ADDSTRING,0,(LPARAM)(LPSTR)buf);
|
|
}
|
|
SendDlgItemMessage(hwndDlg,204,CB_SETCURSEL,netlocalplayers-1,(LPARAM)(LPSTR)0);
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void ShowNetplayConsole(void)
|
|
{
|
|
if(!netwin)
|
|
netwin=CreateDialog(fceu_hInstance,"NETMOO",0,NetCon);
|
|
}
|