diff options
Diffstat (limited to 'source/server.cpp')
-rw-r--r-- | source/server.cpp | 1303 |
1 files changed, 0 insertions, 1303 deletions
diff --git a/source/server.cpp b/source/server.cpp deleted file mode 100644 index 4eb384e..0000000 --- a/source/server.cpp +++ /dev/null @@ -1,1303 +0,0 @@ -/******************************************************************************* - Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. - - (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and - Jerremy Koot (jkoot@snes9x.com) - - (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net) - - (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net), - funkyass (funkyass@spam.shaw.ca), - Joel Yliluoma (http://iki.fi/bisqwit/) - Kris Bleakley (codeviolation@hotmail.com), - Matthew Kendora, - Nach (n-a-c-h@users.sourceforge.net), - Peter Bortas (peter@bortas.org) and - zones (kasumitokoduck@yahoo.com) - - C4 x86 assembler and some C emulation code - (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com), - _Demo_ (_demo_@zsnes.com), and Nach - - C4 C++ code - (c) Copyright 2003 Brad Jorsch - - DSP-1 emulator code - (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson, - John Weidman, neviksti (neviksti@hotmail.com), - Kris Bleakley, Andreas Naive - - DSP-2 emulator code - (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and - Lord Nightmare (lord_nightmare@users.sourceforge.net - - OBC1 emulator code - (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and - Kris Bleakley - Ported from x86 assembler to C by sanmaiwashi - - SPC7110 and RTC C++ emulator code - (c) Copyright 2002 Matthew Kendora with research by - zsKnight, John Weidman, and Dark Force - - S-DD1 C emulator code - (c) Copyright 2003 Brad Jorsch with research by - Andreas Naive and John Weidman - - S-RTC C emulator code - (c) Copyright 2001 John Weidman - - ST010 C++ emulator code - (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora - - Super FX x86 assembler emulator code - (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault - - Super FX C emulator code - (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman - - - SH assembler code partly based on x86 assembler code - (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) - - - Specific ports contains the works of other authors. See headers in - individual files. - - Snes9x homepage: http://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. -*******************************************************************************/ - -#ifdef NETPLAY_SUPPORT -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <memory.h> -#include <sys/types.h> -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -#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 1 - -struct 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; - } - delete data; -#ifdef NP_DEBUG - printf ("SERVER: Waiting for a response from the client @%ld...\n", S9xGetMilliTime () - START); -#endif - S9xNPSetAction ("SERVER: Waiting for a response from the client...", TRUE); - break; - - case NP_CLNT_LOADED_ROM: -#ifdef NP_DEBUG - printf ("SERVER: Client %d loaded requested ROM @%ld...\n", c, S9xGetMilliTime () - START); -#endif - NPServer.Clients [c].SaidHello = TRUE; - NPServer.Clients [c].Ready = FALSE; - NPServer.Clients [c].Paused = FALSE; - S9xNPRecomputePause (); - S9xNPWaitForEmulationToComplete (); - - if (NPServer.SyncByReset) - { - S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); - S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); - } - else - S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); - break; - - case NP_CLNT_RECEIVED_ROM_IMAGE: -#ifdef NP_DEBUG - printf ("SERVER: Client %d received ROM image @%ld...\n", c, S9xGetMilliTime () - START); -#endif - NPServer.Clients [c].SaidHello = TRUE; - NPServer.Clients [c].Ready = FALSE; - NPServer.Clients [c].Paused = FALSE; - S9xNPRecomputePause (); - S9xNPWaitForEmulationToComplete (); - - if (NPServer.SyncByReset) - { - S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); - S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); - } - else - S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); - - break; - - case NP_CLNT_WAITING_FOR_ROM_IMAGE: -#ifdef NP_DEBUG - printf ("SERVER: Client %d waiting for ROM image @%ld...\n", c, S9xGetMilliTime () - START); -#endif - NPServer.Clients [c].SaidHello = TRUE; - NPServer.Clients [c].Ready = FALSE; - NPServer.Clients [c].Paused = FALSE; - S9xNPRecomputePause (); - S9xNPSendROMImageToClient (c); - break; - - case NP_CLNT_READY: -#ifdef NP_DEBUG - printf ("SERVER: Client %d ready @%ld...\n", c, S9xGetMilliTime () - START); -#endif - if (NPServer.Clients [c].SaidHello) - { - NPServer.Clients [c].Paused = FALSE; - NPServer.Clients [c].Ready = TRUE; - - S9xNPRecomputePause (); - break; - } - NPServer.Clients [c].SaidHello = TRUE; - NPServer.Clients [c].Ready = TRUE; - NPServer.Clients [c].Paused = FALSE; - S9xNPRecomputePause (); - -//printf ("SERVER: SaidHello = TRUE, SeqNum = %d @%d\n", NPServer.Clients [c].SendSequenceNum, S9xGetMilliTime () - START); - if (NPServer.NumClients > NP_ONE_CLIENT) - { - if (!NPServer.SendROMImageOnConnect) - { - S9xNPWaitForEmulationToComplete (); - - if (NPServer.SyncByReset) - { - S9xNPServerAddTask (NP_SERVER_SEND_SRAM, (void *) c); - S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); - } - else - S9xNPServerAddTask (NP_SERVER_SYNC_CLIENT, (void *) c); - } - } - else - { - NPServer.Clients [c].Ready = TRUE; - S9xNPRecomputePause (); - } - break; - case NP_CLNT_JOYPAD: - NPServer.Joypads [c] = len; - break; - case NP_CLNT_PAUSE: -#ifdef NP_DEBUG - printf ("SERVER: Client %d Paused: %s @%ld\n", c, (header [2] & 0x80) ? "YES" : "NO", S9xGetMilliTime () - START); -#endif - NPServer.Clients [c].Paused = (header [2] & 0x80) != 0; - if (NPServer.Clients [c].Paused) - sprintf (NetPlay.WarningMsg, "SERVER: Client %d has paused.", c + 1); - else - sprintf (NetPlay.WarningMsg, "SERVER: Client %d has resumed.", c + 1); - S9xNPSetWarning (NetPlay.WarningMsg); - S9xNPRecomputePause (); - break; - } -} - -void S9xNPAcceptClient (int Listen, bool8 block) -{ - struct sockaddr_in remote_address; - struct linger val2; - struct hostent *host; - int new_fd; - int i; - -#ifdef NP_DEBUG - printf ("SERVER: attempting to accept new client connection @%ld\n", S9xGetMilliTime () - START); -#endif - S9xNPSetAction ("SERVER: Attempting to accept client connection...", TRUE); - memset (&remote_address, 0, sizeof (remote_address)); - ACCEPT_SIZE_T len = sizeof (remote_address); - - new_fd = accept (Listen, (struct sockaddr *)&remote_address, &len); - - S9xNPSetAction ("Setting socket options...", TRUE); - val2.l_onoff = 1; - val2.l_linger = 0; - if (setsockopt (new_fd, SOL_SOCKET, SO_LINGER, - (char *) &val2, sizeof (val2)) < 0) - { - S9xNPSetError ("Setting socket options failed."); - close (new_fd); - return; - } - - for (i = 0; i < NP_MAX_CLIENTS; i++) - { - if (!NPServer.Clients [i].Connected) - { - NPServer.NumClients++; - NPServer.Clients [i].Socket = new_fd; - NPServer.Clients [i].SendSequenceNum = 0; - NPServer.Clients [i].ReceiveSequenceNum = 0; - NPServer.Clients [i].Connected = TRUE; - NPServer.Clients [i].SaidHello = FALSE; - NPServer.Clients [i].Paused = FALSE; - NPServer.Clients [i].Ready = FALSE; - NPServer.Clients [i].ROMName = NULL; - NPServer.Clients [i].HostName = NULL; - NPServer.Clients [i].Who = NULL; - break; - } - } - - if (i >= NP_MAX_CLIENTS) - { - S9xNPSetError ("SERVER: Maximum number of NetPlay Clients have already connected."); - close (new_fd); - return; - } - - if (remote_address.sin_family == AF_INET) - { -#ifdef NP_DEBUG - printf ("SERVER: Looking up new client's hostname @%ld\n", S9xGetMilliTime () - START); -#endif - S9xNPSetAction ("SERVER: Looking up new client's hostname...", TRUE); - host = gethostbyaddr ((char *) &remote_address.sin_addr, - sizeof (remote_address.sin_addr), AF_INET); - - if (host) - { -#ifdef NP_DEBUG - printf ("SERVER: resolved new client's hostname (%s) @%ld\n", host->h_name, S9xGetMilliTime () - START); -#endif - sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, host->h_name); - NPServer.Clients [i].HostName = strdup (host->h_name); - } - else - { - char *ip = inet_ntoa (remote_address.sin_addr); - if (ip) - NPServer.Clients [i].HostName = strdup (ip); -#ifdef NP_DEBUG - printf ("SERVER: couldn't resolve new client's hostname (%s) @%ld\n", ip ? ip : "Unknown", S9xGetMilliTime () - START); -#endif - sprintf (NetPlay.WarningMsg, "SERVER: Player %d on %s has connected.", i + 1, ip ? ip : "Unknown"); - } - S9xNPSetWarning (NetPlay.WarningMsg); - } -#ifdef NP_DEBUG - printf ("SERVER: waiting for HELLO message from new client @%ld\n", S9xGetMilliTime () - START); -#endif - S9xNPSetAction ("SERVER: Waiting for HELLO message from new client..."); -} - -static bool8 server_continue = TRUE; - -static bool8 S9xNPServerInit (int port) -{ - struct sockaddr_in address; - int i; - int val; - - if (!S9xNPInitialise ()) - return (FALSE); - - for (i = 0; i < NP_MAX_CLIENTS; i++) - { - NPServer.Clients [i].SendSequenceNum = 0; - NPServer.Clients [i].ReceiveSequenceNum = 0; - NPServer.Clients [i].Connected = FALSE; - NPServer.Clients [i].SaidHello = FALSE; - NPServer.Clients [i].Paused = FALSE; - NPServer.Clients [i].Ready = FALSE; - NPServer.Clients [i].Socket = 0; - NPServer.Clients [i].ROMName = NULL; - NPServer.Clients [i].HostName = NULL; - NPServer.Clients [i].Who = NULL; - NPServer.Joypads [i] = 0; - } - - NPServer.NumClients = 0; - NPServer.FrameCount = 0; - -#ifdef NP_DEBUG - printf ("SERVER: Creating socket @%ld\n", S9xGetMilliTime () - START); -#endif - if ((NPServer.Socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) - { - S9xNPSetError ("NetPlay Server: Can't create listening socket."); - return (FALSE); - } - - val = 1; - setsockopt (NPServer.Socket, SOL_SOCKET, SO_REUSEADDR, - (char *)&val, sizeof (val)); - - memset (&address, 0, sizeof (address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl (INADDR_ANY); - address.sin_port = htons (port); - -#ifdef NP_DEBUG - printf ("SERVER: Binding socket to address and port @%ld\n", S9xGetMilliTime () - START); -#endif - if (bind (NPServer.Socket, (struct sockaddr *) &address, sizeof (address)) < 0) - { - S9xNPSetError ("NetPlay Server: Can't bind socket to port number.\nPort already in use?"); - return (FALSE); - } - -#ifdef NP_DEBUG - printf ("SERVER: Getting socket to listen @%ld\n", S9xGetMilliTime () - START); -#endif - if (listen (NPServer.Socket, NP_MAX_CLIENTS) < 0) - { - S9xNPSetError ("NetPlay Server: Can't get new socket to listen."); - return (FALSE); - } - -#ifdef NP_DEBUG - printf ("SERVER: Init complete @%ld\n", S9xGetMilliTime () - START); -#endif - return (TRUE); -} - -void S9xNPServerLoop (void *) -{ -#ifdef __WIN32__ - BOOL success = FALSE; -#else - bool8 success = FALSE; -#endif - - while (server_continue) - { - fd_set read_fds; - struct timeval timeout; - int res; - int i; - - int max_fd = NPServer.Socket; - -#ifdef __WIN32__ - Sleep (0); -#endif - - if (success && !Settings.Paused && !Settings.StopEmulation && - !Settings.ForcedPause && !NPServer.Paused) - { - S9xNPSendHeartBeat (); - } - - do - { - FD_ZERO (&read_fds); - FD_SET (NPServer.Socket, &read_fds); - for (i = 0; i < NP_MAX_CLIENTS; i++) - { - if (NPServer.Clients [i].Connected) - { - FD_SET (NPServer.Clients [i].Socket, &read_fds); - if (NPServer.Clients [i].Socket > max_fd) - max_fd = NPServer.Clients [i].Socket; - } - } - - timeout.tv_sec = 0; - timeout.tv_usec = 1000; - res = select (max_fd + 1, &read_fds, NULL, NULL, &timeout); - - if (res > 0) - { - if (FD_ISSET (NPServer.Socket, &read_fds)) - S9xNPAcceptClient (NPServer.Socket, FALSE); - - for (i = 0; i < NP_MAX_CLIENTS; i++) - { - if (NPServer.Clients [i].Connected && - FD_ISSET (NPServer.Clients [i].Socket, &read_fds)) - { - S9xNPProcessClient (i); - } - } - } - } while (res > 0); - -#ifdef __WIN32__ - success = WaitForSingleObject (GUI.ServerTimerSemaphore, 200) == WAIT_OBJECT_0; -#endif - - while (NPServer.TaskHead != NPServer.TaskTail) - { - void *task_data = NPServer.TaskQueue [NPServer.TaskHead].Data; - -#if defined(NP_DEBUG) && NP_DEBUG == 2 - printf ("SERVER: task %d @%ld\n", NPServer.TaskQueue [NPServer.TaskHead].Task, S9xGetMilliTime () - START); -#endif - - switch (NPServer.TaskQueue [NPServer.TaskHead].Task) - { - case NP_SERVER_SEND_ROM_IMAGE: - S9xNPSendROMImageToAllClients (); - break; - case NP_SERVER_SYNC_CLIENT: - NPServer.Clients [(int) task_data].Ready = FALSE; - S9xNPRecomputePause (); - S9xNPSyncClient ((int) task_data); - break; - case NP_SERVER_SYNC_ALL: - S9xNPSyncClients (); - break; - case NP_SERVER_SEND_FREEZE_FILE_ALL: - S9xNPSendFreezeFileToAllClients ((char *) task_data); - free ((char *) task_data); - break; - case NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL: - S9xNPSendROMLoadRequest ((char *) task_data); - free ((char *) task_data); - break; - case NP_SERVER_RESET_ALL: - S9xNPNoClientReady (0); - S9xNPWaitForEmulationToComplete (); - S9xNPSetAction ("SERVER: Sending RESET to all clients...", TRUE); -#ifdef NP_DEBUG - printf ("SERVER: Sending RESET to all clients @%ld\n", S9xGetMilliTime () - START); -#endif - { - uint8 reset [7]; - uint8 *ptr; - - ptr = reset; - *ptr++ = NP_SERV_MAGIC; - *ptr++ = 0; - *ptr++ = NP_SERV_RESET; - WRITE_LONG (ptr, NPServer.FrameCount); - S9xNPSendToAllClients (reset, 7); - } - break; - case NP_SERVER_SEND_SRAM: - NPServer.Clients [(int) task_data].Ready = FALSE; - S9xNPRecomputePause (); - S9xNPWaitForEmulationToComplete (); - S9xNPSendSRAMToClient ((int) task_data); - break; - - case NP_SERVER_SEND_SRAM_ALL: - S9xNPNoClientReady (); - S9xNPWaitForEmulationToComplete (); - S9xNPSendSRAMToAllClients (); - break; - - default: - S9xNPSetError ("SERVER: *** Unknown task ***\n"); - break; - } - NPServer.TaskHead = (NPServer.TaskHead + 1) % NP_MAX_TASKS; - } - } -#ifdef NP_DEBUG - printf ("SERVER: Server thread exiting @%ld\n", S9xGetMilliTime () - START); -#endif - S9xNPStopServer (); -} - -bool8 S9xNPStartServer (int port) -{ - static int p; - -#ifdef NP_DEBUG - printf ("SERVER: Starting server on port %d @%ld\n", port, S9xGetMilliTime () - START); -#endif - p = port; - server_continue = TRUE; - if (S9xNPServerInit (port)) -#ifdef __WIN32__ - return (_beginthread (S9xNPServerLoop, 0, &p) != ~0); -#else - return (TRUE); -#endif - - return (FALSE); -} - -void S9xNPStopServer () -{ -#ifdef NP_DEBUG - printf ("SERVER: Stopping server @%ld\n", S9xGetMilliTime () - START); -#endif - server_continue = FALSE; - close (NPServer.Socket); - - for (int i = 0; i < NP_MAX_CLIENTS; i++) - { - if (NPServer.Clients [i].Connected) - { - close (NPServer.Clients [i].Socket); - NPServer.Clients [i].Connected = FALSE; - NPServer.Clients [i].SaidHello = FALSE; - } - } -} - -#ifdef __WIN32__ -void S9xGetTimeOfDay (struct timeval *n) -{ - unsigned long t = S9xGetMilliTime (); - - n->tv_sec = t / 1000; - n->tv_usec = (t % 1000) * 1000; -} -#endif - -void S9xNPSendROMImageToAllClients () -{ - S9xNPNoClientReady (); - S9xNPWaitForEmulationToComplete (); - - int c; - - for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) - { - if (NPServer.Clients [c].SaidHello) - S9xNPSendROMImageToClient (c); - } - - if (NPServer.SyncByReset) - { - S9xNPServerAddTask (NP_SERVER_SEND_SRAM_ALL, 0); - S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); - } - else - S9xNPSyncClient (-1); -} - -bool8 S9xNPSendROMImageToClient (int c) -{ -#ifdef NP_DEBUG - printf ("SERVER: Sending ROM image to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); -#endif - sprintf (NetPlay.ActionMsg, "Sending ROM image to player %d...", c + 1); - S9xNPSetAction (NetPlay.ActionMsg, TRUE); - - uint8 header [7 + 1 + 4]; - uint8 *ptr = header; - int len = sizeof (header) + Memory.CalculatedSize + - strlen (Memory.ROMFilename) + 1; - *ptr++ = NP_SERV_MAGIC; - *ptr++ = NPServer.Clients [c].SendSequenceNum++; - *ptr++ = NP_SERV_ROM_IMAGE; - WRITE_LONG (ptr, len); - ptr += 4; - *ptr++ = Memory.HiROM; - WRITE_LONG (ptr, Memory.CalculatedSize); - - if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, sizeof (header)) || - !S9xNPSSendData (NPServer.Clients [c].Socket, Memory.ROM, - Memory.CalculatedSize) || - !S9xNPSSendData (NPServer.Clients [c].Socket, (uint8 *) Memory.ROMFilename, - strlen (Memory.ROMFilename) + 1)) - { - S9xNPShutdownClient (c, TRUE); - return (FALSE); - } - return (TRUE); -} - -void S9xNPSyncClients () -{ - S9xNPNoClientReady (); - S9xNPSyncClient (-1); -} - -void S9xNPSyncClient (int client) -{ -#ifdef HAVE_MKSTEMP - char fname[] = "/tmp/snes9x_fztmpXXXXXX"; -#else - char fname [L_tmpnam]; -#endif - - S9xNPWaitForEmulationToComplete (); - - S9xNPSetAction ("SERVER: Freezing game...", TRUE); -#ifdef HAVE_MKSTEMP - if ( (mkstemp(fname) < 0) && S9xFreezeGame(fname) ) -#else - if ( tmpnam(fname) && S9xFreezeGame(fname) ) -#endif - { - uint8 *data; - uint32 len; - - S9xNPSetAction ("SERVER: Loading freeze file...", TRUE); - if (S9xNPLoadFreezeFile (fname, data, len)) - { - int c; - - if (client < 0) - { - for (c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) - { - if (NPServer.Clients [c].SaidHello) - { - NPServer.Clients [client].Ready = FALSE; - S9xNPRecomputePause (); - S9xNPSendFreezeFile (c, data, len); - } - } - } - else - { - NPServer.Clients [client].Ready = FALSE; - S9xNPRecomputePause (); - S9xNPSendFreezeFile (client, data, len); - } - delete data; - } - remove (fname); - } -} - -bool8 S9xNPLoadFreezeFile (const char *fname, uint8 *&data, uint32 &len) -{ - FILE *ff; - - if ((ff = fopen (fname, "rb"))) - { - fseek (ff, 0, SEEK_END); - len = ftell (ff); - fseek (ff, 0, SEEK_SET); - - data = new uint8 [len]; - bool8 ok = (fread (data, 1, len, ff) == len); - fclose (ff); - - return (ok); - } - return (FALSE); -} - -void S9xNPSendFreezeFile (int c, uint8 *data, uint32 len) -{ -#ifdef NP_DEBUG - printf ("SERVER: Sending freeze file to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); -#endif - - sprintf (NetPlay.ActionMsg, "SERVER: Sending freeze-file to player %d...", c + 1); - S9xNPSetAction (NetPlay.ActionMsg, TRUE); - uint8 header [7 + 4]; - uint8 *ptr = header; - - *ptr++ = NP_SERV_MAGIC; - *ptr++ = NPServer.Clients [c].SendSequenceNum++; - *ptr++ = NP_SERV_FREEZE_FILE; - WRITE_LONG (ptr, len + 7 + 4); - ptr += 4; - WRITE_LONG (ptr, NPServer.FrameCount); - - if (!S9xNPSSendData (NPServer.Clients [c].Socket, header, 7 + 4) || - !S9xNPSSendData (NPServer.Clients [c].Socket, data, len)) - { - S9xNPShutdownClient (c, TRUE); - } -} - -void S9xNPRecomputePause () -{ - int c; - - for (c = 0; c < NP_MAX_CLIENTS; c++) - { - if (NPServer.Clients [c].SaidHello && - (!NPServer.Clients [c].Ready || NPServer.Clients [c].Paused)) - { -#if defined(NP_DEBUG) && NP_DEBUG == 2 - printf ("SERVER: Paused because of client %d (%d,%d) @%ld\n", c, NPServer.Clients [c].Ready, NPServer.Clients [c].Paused, S9xGetMilliTime () - START); -#endif - NPServer.Paused = TRUE; - return; - } - } -#if defined(NP_DEBUG) && NP_DEBUG == 2 - printf ("SERVER: not paused @%ld\n", S9xGetMilliTime () - START); -#endif - NPServer.Paused = FALSE; -} - -void S9xNPNoClientReady (int start_index) -{ - int c; - - for (c = start_index; c < NP_MAX_CLIENTS; c++) - NPServer.Clients [c].Ready = FALSE; - S9xNPRecomputePause (); -} - -void S9xNPSendROMLoadRequest (const char *filename) -{ - S9xNPNoClientReady (); - - int len = 7 + strlen (filename) + 1; - uint8 *data = new uint8 [len]; - uint8 *ptr = data; - *ptr++ = NP_SERV_MAGIC; - *ptr++ = 0; - *ptr++ = NP_SERV_LOAD_ROM; - WRITE_LONG (ptr, len); - ptr += 4; - strcpy ((char *) ptr, filename); - - for (int i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) - { - if (NPServer.Clients [i].SaidHello) - { -#ifdef NP_DEBUG - printf ("SERVER: Sending load ROM requesting to player %d @%ld\n", i + 1, S9xGetMilliTime () - START); -#endif - sprintf (NetPlay.WarningMsg, "SERVER: sending ROM load request to player %d...", i + 1); - S9xNPSetAction (NetPlay.WarningMsg, TRUE); - data [1] = NPServer.Clients [i].SendSequenceNum++; - if (!S9xNPSSendData (NPServer.Clients [i].Socket, data, len)) - { - S9xNPShutdownClient (i, TRUE); - } - } - } - delete data; -} - -void S9xNPSendSRAMToAllClients () -{ - int i; - - for (i = NP_ONE_CLIENT; i < NP_MAX_CLIENTS; i++) - { - if (NPServer.Clients [i].SaidHello) - S9xNPSendSRAMToClient (i); - } -} - -void S9xNPSendSRAMToClient (int c) -{ -#ifdef NP_DEBUG - printf ("SERVER: Sending S-RAM data to player %d @%ld\n", c + 1, S9xGetMilliTime () - START); -#endif - uint8 sram [7]; - int SRAMSize = Memory.SRAMSize ? - (1 << (Memory.SRAMSize + 3)) * 128 : 0; - if (SRAMSize > 0x10000) - SRAMSize = 0x10000; - int len = 7 + SRAMSize; - - sprintf (NetPlay.ActionMsg, "SERVER: Sending S-RAM to player %d...", c + 1); - S9xNPSetAction (NetPlay.ActionMsg, TRUE); - - uint8 *ptr = sram; - *ptr++ = NP_SERV_MAGIC; - *ptr++ = NPServer.Clients [c].SendSequenceNum++; - *ptr++ = NP_SERV_SRAM_DATA; - WRITE_LONG (ptr, len); - if (!S9xNPSSendData (NPServer.Clients [c].Socket, - sram, sizeof (sram)) || - (len > 7 && - !S9xNPSSendData (NPServer.Clients [c].Socket, - ::SRAM, len - 7))) - { - S9xNPShutdownClient (c, TRUE); - } -} - -void S9xNPSendFreezeFileToAllClients (const char *filename) -{ - uint8 *data; - uint32 len; - - if (NPServer.NumClients > NP_ONE_CLIENT && S9xNPLoadFreezeFile (filename, data, len)) - { - S9xNPNoClientReady (); - - for (int c = NP_ONE_CLIENT; c < NP_MAX_CLIENTS; c++) - { - if (NPServer.Clients [c].SaidHello) - S9xNPSendFreezeFile (c, data, len); - } - delete data; - } -} - -void S9xNPServerAddTask (uint32 task, void *data) -{ - NPServer.TaskQueue [NPServer.TaskTail].Task = task; - NPServer.TaskQueue [NPServer.TaskTail].Data = data; - - NPServer.TaskTail = (NPServer.TaskTail + 1) % NP_MAX_TASKS; -} - -void S9xNPReset () -{ - S9xNPNoClientReady (0); - S9xNPServerAddTask (NP_SERVER_RESET_ALL, 0); -} - -void S9xNPWaitForEmulationToComplete () -{ -#ifdef NP_DEBUG - printf ("SERVER: WaitForEmulationToComplete start @%ld\n", S9xGetMilliTime () - START); -#endif - - while (!NetPlay.PendingWait4Sync && NetPlay.Connected && - !Settings.ForcedPause && !Settings.StopEmulation && - !Settings.Paused) - { -#ifdef __WIN32__ - Sleep (40); -#endif - } -#ifdef NP_DEBUG - printf ("SERVER: WaitForEmulationToComplete end @%ld\n", S9xGetMilliTime () - START); -#endif -} - -void S9xNPServerQueueSyncAll () -{ - if (Settings.NetPlay && Settings.NetPlayServer && - NPServer.NumClients > NP_ONE_CLIENT) - { - S9xNPNoClientReady (); - S9xNPDiscardHeartbeats (); - S9xNPServerAddTask (NP_SERVER_SYNC_ALL, 0); - } -} - -void S9xNPServerQueueSendingROMImage () -{ - if (Settings.NetPlay && Settings.NetPlayServer && - NPServer.NumClients > NP_ONE_CLIENT) - { - S9xNPNoClientReady (); - S9xNPDiscardHeartbeats (); - S9xNPServerAddTask (NP_SERVER_SEND_ROM_IMAGE, 0); - } -} - -void S9xNPServerQueueSendingFreezeFile (const char *filename) -{ - if (Settings.NetPlay && Settings.NetPlayServer && - NPServer.NumClients > NP_ONE_CLIENT) - { - S9xNPNoClientReady (); - S9xNPDiscardHeartbeats (); - S9xNPServerAddTask (NP_SERVER_SEND_FREEZE_FILE_ALL, - (void *) strdup (filename)); - } -} - -void S9xNPServerQueueSendingLoadROMRequest (const char *filename) -{ - if (Settings.NetPlay && Settings.NetPlayServer && - NPServer.NumClients > NP_ONE_CLIENT) - { - S9xNPNoClientReady (); - S9xNPDiscardHeartbeats (); - S9xNPServerAddTask (NP_SERVER_SEND_ROM_LOAD_REQUEST_ALL, - (void *) strdup (filename)); - } -} - -#ifndef __WIN32__ -uint32 S9xGetMilliTime () -{ - static bool8 first = TRUE; - static long start_sec; - struct timeval tv; - - gettimeofday (&tv, NULL); - if (first) - { - start_sec = tv.tv_sec; - first = FALSE; - } - return ((uint32) ((tv.tv_sec - start_sec) * 1000 + tv.tv_usec / 1000)); -} -#endif -#endif - |