Initial commit - http://sourceforge.net/p/fceumm/code/160/
This commit is contained in:
434
src/drivers/win/netplay.c
Normal file
434
src/drivers/win/netplay.c
Normal file
@@ -0,0 +1,434 @@
|
||||
/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 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] = malloc(strlen(buf) + 1);
|
||||
strcpy(*strs[x], buf);
|
||||
}
|
||||
}
|
||||
remotetport = GetDlgItemInt(hwndDlg, 201, 0, 0);
|
||||
netlocalplayers = 1 + SendDlgItemMessage(hwndDlg, 204, CB_GETCURSEL, 0, (LPARAM)(LPSTR)0);
|
||||
}
|
||||
|
||||
int FCEUD_NetworkConnect();
|
||||
|
||||
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(buf);
|
||||
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;
|
||||
}
|
||||
|
||||
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] = malloc(strlen(text) + 1)))
|
||||
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 = malloc(totallen);
|
||||
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 = malloc(totallen);
|
||||
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(text);
|
||||
}
|
||||
|
||||
int FCEUD_NetworkConnect(void) {
|
||||
WSADATA WSAData;
|
||||
SOCKADDR_IN sockin; /* I want to play with fighting robots. */
|
||||
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 = malloc(sblen);
|
||||
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, netgamekey, strlen(netgamekey));
|
||||
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, netpassword, strlen(netpassword));
|
||||
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, sendbuf, sblen, 0);
|
||||
free(sendbuf);
|
||||
|
||||
recv_tcpwrap(buf, 1);
|
||||
netdivisor = buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FCEUI_NetplayStart(netlocalplayers, netdivisor);
|
||||
NetStatAdd("*** Connection established.");
|
||||
|
||||
FCEUDnetplay = 1;
|
||||
int tcpopt = 1;
|
||||
if (setsockopt(TSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&tcpopt, sizeof(int)))
|
||||
puts("Nodelay fail");
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int FCEUD_SendData(void *data, uint32 len) {
|
||||
send(Socket, data, len, 0);
|
||||
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, buf, len, 0);
|
||||
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(data, len) > 0) {
|
||||
unsigned long beefie;
|
||||
if (!ioctlsocket(Socket, FIONREAD, &beefie))
|
||||
if (beefie)
|
||||
NoWaiting |= 2;
|
||||
return(1);
|
||||
} else
|
||||
return(0);
|
||||
} else
|
||||
return(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ShowNetplayConsole(void) {
|
||||
if (!netwin)
|
||||
netwin = CreateDialog(fceu_hInstance, "NETMOO", 0, NetCon);
|
||||
}
|
||||
|
||||
CFGSTRUCT NetplayConfig[] = {
|
||||
AC(remotetport),
|
||||
AC(netlocalplayers),
|
||||
ACS(netgamekey),
|
||||
ACS(netplayhost),
|
||||
ACS(netplaynick),
|
||||
ACS(netpassword),
|
||||
ENDCFGSTRUCT
|
||||
};
|
||||
Reference in New Issue
Block a user