/* 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;xh_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); }