📄 server.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <memory.h>#include <sys/types.h>#ifndef __WIN32__#include <unistd.h>#include <sys/time.h>#endif#ifdef __WIN32__#include <winsock.h>#include <process.h>#define ioctl ioctlsocket#define close closesocket#define read(a,b,c) recv(a, b, c, 0)#define write(a,b,c) send(a, b, c, 0)#define gettimeofday(a,b) S9xGetTimeOfDay (a)#define exit(a) _endthread()void S9xGetTimeOfDay (struct timeval *n);#else#include <netdb.h>#include <sys/socket.h>#include <sys/param.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#ifdef __SVR4#include <sys/stropts.h>#endif#endif // !__WIN32__#include "snes9x.h"#include "netplay.h"#include "memmap.h"#include "snapshot.h"#define NP_ONE_CLIENT 1struct SNPServer NPServer;extern unsigned long START;void S9xNPSendToAllClients (uint8 *data, int len);bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len);void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len);void S9xNPNoClientReady (int start_index = NP_ONE_CLIENT);void S9xNPRecomputePause ();void S9xNPWaitForEmulationToComplete ();void S9xNPSendROMImageToAllClients ();bool8 S9xNPSendROMImageToClient (int client);void S9xNPSendSRAMToClient (int c);void S9xNPSendSRAMToAllClients ();void S9xNPSyncClient (int);void S9xNPSendROMLoadRequest (const char *filename);void S9xNPSendFreezeFileToAllClients (const char *filename);void S9xNPStopServer ();void S9xNPShutdownClient (int c, bool8 report_error = FALSE){ if (NPServer.Clients [c].Connected) { NPServer.Clients [c].Connected = FALSE; NPServer.Clients [c].SaidHello = FALSE; close (NPServer.Clients [c].Socket);#ifdef NP_DEBUG printf ("SERVER: Player %d disconnecting @%ld\n", c + 1, S9xGetMilliTime () - START);#endif if (report_error) { sprintf (NetPlay.ErrorMsg, "Player %d on '%s' has disconnected.", c + 1, NPServer.Clients [c].HostName); S9xNPSetError (NetPlay.ErrorMsg); } if (NPServer.Clients [c].HostName) { free ((char *) NPServer.Clients [c].HostName); NPServer.Clients [c].HostName = NULL; } if (NPServer.Clients [c].ROMName) { free ((char *) NPServer.Clients [c].ROMName); NPServer.Clients [c].ROMName = NULL; } if (NPServer.Clients [c].Who) { free ((char *) NPServer.Clients [c].Who); NPServer.Clients [c].Who = NULL; } NPServer.Joypads [c] = 0; NPServer.NumClients--; S9xNPRecomputePause (); }}static bool8 S9xNPSGetData (int socket, uint8 *data, int length){ int len = length; uint8 *ptr = data; do { int num_bytes = len; // Read the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > 512) num_bytes = 512; int got = read (socket, (char *) ptr, num_bytes); if (got < 0) { if (errno == EINTR#ifdef EAGAIN || errno == EAGAIN#endif#ifdef EWOULDBLOCK || errno == EWOULDBLOCK#endif#ifdef WSAEWOULDBLOCK || errno == WSAEWOULDBLOCK#endif ) continue;#ifdef WSAEMSGSIZE if (errno != WSAEMSGSIZE) return (FALSE); else { got = num_bytes;#ifdef NP_DEBUG printf ("SERVER: WSAEMSGSIZE, actual bytes %d while receiving data @%d\n", got, S9xGetMilliTime () - START);#endif }#else return (FALSE);#endif } else if (got == 0) return (FALSE); len -= got; ptr += got; } while (len > 0); return (TRUE);}static bool8 S9xNPSSendData (int fd, const uint8 *data, int length){ int Percent = 0; int len = length; int chunk = length / 50; if (chunk < 1024) chunk = 1024; do { int num_bytes = len; // Write the data in small chunks, allowing this thread to spot an // abort request from another thread. if (num_bytes > chunk) num_bytes = chunk; int sent; sent = write (fd, (char *) data, len); if (sent < 0) { if (errno == EINTR #ifdef EAGAIN || errno == EAGAIN#endif#ifdef EWOULDBLOCK || errno == EWOULDBLOCK#endif ) {#ifdef NP_DEBUG printf ("SERVER: EINTR, EAGAIN or EWOULDBLOCK while sending data @%ld\n", S9xGetMilliTime () - START);#endif continue; } return (FALSE); } else if (sent == 0) return (FALSE); len -= sent; data += sent; if (length > 1024) { Percent = (uint8) (((length - len) * 100) / length);#ifdef __WIN32__ PostMessage (GUI.hWnd, WM_USER, Percent, Percent); Sleep (0);#endif } } while (len > 0); return (TRUE);}void S9xNPSendHeartBeat (){ int len = 3; uint8 data [3 + 4 * 5]; uint8 *ptr = data; int n; for (n = NP_MAX_CLIENTS - 1; n >= 0; n--) { if (NPServer.Clients [n].SaidHello) break; } if (n >= 0) { bool8 Paused = NPServer.Paused != 0; NPServer.FrameCount++; *ptr++ = NP_SERV_MAGIC; *ptr++ = 0; // Individual client sequence number will get placed here *ptr++ = NP_SERV_JOYPAD | (n << 6) | ((Paused != 0) << 5); WRITE_LONG (ptr, NPServer.FrameCount); len += 4; ptr += 4; int i; for (i = 0; i <= n; i++) { WRITE_LONG (ptr, NPServer.Joypads [i]); len += 4; ptr += 4; } S9xNPSendToAllClients (data, len); }}void S9xNPSendToAllClients (uint8 *data, int len){ int i; for (i = 0; i < NP_MAX_CLIENTS; i++) { if (NPServer.Clients [i].SaidHello) { data [1] = NPServer.Clients [i].SendSequenceNum++; if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) S9xNPShutdownClient (i, TRUE); } }}void S9xNPProcessClient (int c){ uint8 header [7]; uint8 *data; uint32 len; uint8 *ptr; if (!S9xNPSGetData (NPServer.Clients [c].Socket, header, 7)) { S9xNPSetWarning ("SERVER: Failed to get message header from client.\n"); S9xNPShutdownClient (c, TRUE); return; } if (header [0] != NP_CLNT_MAGIC) { S9xNPSetWarning ("SERVER: Bad header magic value received from client.\n"); S9xNPShutdownClient (c, TRUE); return; } if (header [1] != NPServer.Clients [c].ReceiveSequenceNum) {#ifdef NP_DEBUG printf ("SERVER: Messages lost from '%s', expected %d, got %d\n", NPServer.Clients [c].HostName ? NPServer.Clients [c].HostName : "Unknown", NPServer.Clients [c].ReceiveSequenceNum, header [1]);#endif sprintf (NetPlay.WarningMsg, "SERVER: Messages lost from '%s', expected %d, got %d\n", NPServer.Clients [c].HostName ? NPServer.Clients [c].HostName : "Unknown", NPServer.Clients [c].ReceiveSequenceNum, header [1]); NPServer.Clients [c].ReceiveSequenceNum = header [1] + 1; S9xNPSetWarning (NetPlay.WarningMsg); } else NPServer.Clients [c].ReceiveSequenceNum++; len = READ_LONG (&header [3]); switch (header [2] & 0x3f) { case NP_CLNT_HELLO:#ifdef NP_DEBUG printf ("SERVER: Got HELLO from client @%ld\n", S9xGetMilliTime () - START);#endif S9xNPSetAction ("Got HELLO from client...", TRUE); if (len > 0x10000) { S9xNPSetWarning ("SERVER: Client HELLO message length error."); S9xNPShutdownClient (c, TRUE); return; } data = new uint8 [len - 7]; if (!S9xNPSGetData (NPServer.Clients [c].Socket, data, len - 7)) { S9xNPSetWarning ("SERVER: Failed to get HELLO message content from client."); S9xNPShutdownClient (c, TRUE); return; } if (NPServer.NumClients <= NP_ONE_CLIENT) { NPServer.FrameTime = READ_LONG (data); strncpy (NPServer.ROMName, (char *) &data [4], 29); NPServer.ROMName [29] = 0; } NPServer.Clients [c].ROMName = strdup ((char *) &data [4]);#ifdef NP_DEBUG printf ("SERVER: Client is playing: %s, Frame Time: %d @%ld\n", data + 4, READ_LONG (data), S9xGetMilliTime () - START);#endif NPServer.Clients [c].SendSequenceNum = 0; len = 7 + 1 + 1 + 4 + strlen (NPServer.ROMName) + 1; delete data; ptr = data = new uint8 [len]; *ptr++ = NP_SERV_MAGIC; *ptr++ = NPServer.Clients [c].SendSequenceNum++; if (NPServer.SendROMImageOnConnect && NPServer.NumClients > NP_ONE_CLIENT) *ptr++ = NP_SERV_HELLO | 0x80; else *ptr++ = NP_SERV_HELLO; WRITE_LONG (ptr, len); ptr += 4; *ptr++ = NP_VERSION; *ptr++ = c + 1; WRITE_LONG (ptr, NPServer.FrameCount); ptr += 4; strcpy ((char *) ptr, NPServer.ROMName);#ifdef NP_DEBUG printf ("SERVER: Sending welcome information to client @%ld...\n", S9xGetMilliTime () - START);#endif S9xNPSetAction ("SERVER: Sending welcome information to new client...", TRUE); if (!S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) { S9xNPSetWarning ("SERVER: Failed to send welcome message to client."); S9xNPShutdownClient (c, TRUE); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -