Various networking stuff

This commit is contained in:
simon.kagstrom 2009-01-24 15:48:43 +00:00
parent a6c5b3c6f9
commit f31320b774
7 changed files with 340 additions and 74 deletions

View File

@ -1,3 +1,8 @@
version 7:
TODO: Multiple frodo versions, switch between
-- Simon Kagstrom <simon.kagstrom@gmail.com>,
version 6: version 6:
TODO: Multiple frodo versions, switch between TODO: Multiple frodo versions, switch between
* Handle reset button (back to menu) * Handle reset button (back to menu)
@ -14,7 +19,8 @@ version 6:
is not a PRG to load correctly). Thanks to Dominik Reichardt for pointing is not a PRG to load correctly). Thanks to Dominik Reichardt for pointing
this out this out
-- Simon Kagstrom <simon.kagstrom@gmail.com>, -- Simon Kagstrom <simon.kagstrom@gmail.com>, Sat Jan 24 11:48:01 CET 2009
version 5: version 5:
* Some wiimote sanity checks * Some wiimote sanity checks

View File

@ -24,6 +24,7 @@
/* SDL menu */ /* SDL menu */
#include "menu.h" #include "menu.h"
#include "VirtualKeyboard.h" #include "VirtualKeyboard.h"
#include "Network.h"
#endif #endif
#ifdef __BEOS__ #ifdef __BEOS__
@ -184,6 +185,10 @@ public:
#endif #endif
#ifdef HAVE_SDL #ifdef HAVE_SDL
VirtualKeyboard *virtual_keyboard; VirtualKeyboard *virtual_keyboard;
NetworkServer *network_server;
NetworkClient *network_client;
char server_hostname[255];
int server_port;
TTF_Font *menu_font; TTF_Font *menu_font;
bool fake_key_sequence; bool fake_key_sequence;
@ -201,6 +206,7 @@ public:
char * bind_one_key(Prefs *np, int which); char * bind_one_key(Prefs *np, int which);
void bind_keys(Prefs *np); void bind_keys(Prefs *np);
void other_options(Prefs *np); void other_options(Prefs *np);
void networking_menu(Prefs *np);
void save_load_state(Prefs *np); void save_load_state(Prefs *np);
#endif #endif

View File

@ -39,16 +39,6 @@ static const char *main_menu_messages[] = {
NULL, NULL,
}; };
static const char *other_options_messages[] = {
"Display resolution", /* 0 */
"^|double-center|stretched",
"Speed (approx)", /* 2 */
"^|95|100|110",
"Emulate 1541", /* 4 */
"^|On|Off",
NULL,
};
static const char *save_load_state_messages[] = { static const char *save_load_state_messages[] = {
"Load saved state", /* 0 */ "Load saved state", /* 0 */
"Save current state", /* 1 */ "Save current state", /* 1 */
@ -100,6 +90,12 @@ void C64::c64_ctor1(void)
} }
this->virtual_keyboard = new VirtualKeyboard(real_screen, this->menu_font); this->virtual_keyboard = new VirtualKeyboard(real_screen, this->menu_font);
this->network_server = NULL;
this->network_client = NULL;
strncpy(this->server_hostname, "localhost",
sizeof(this->server_hostname));
this->server_port = 19760;
} }
void C64::c64_ctor2(void) void C64::c64_ctor2(void)
@ -299,24 +295,90 @@ void C64::bind_keys(Prefs *np)
} }
} }
void C64::networking_menu(Prefs *np)
{
int opt;
do
{
char buf[2][255];
const char *network_client_messages[] = {
"Start network server", /* 0 */
buf[0], /* 1 */
buf[1], /* 2 */
"Connect to server", /* 3 */
NULL,
};
snprintf(buf[0], 255, "Server hostname (now %s)",
this->server_hostname);
snprintf(buf[1], 255, "Server port (now %d)",
this->server_port);
opt = menu_select(real_screen, this->menu_font,
network_client_messages, NULL);
if (opt == 1 || opt == 2)
{
const char *m = this->virtual_keyboard->get_string();
if (m && opt == 1)
strncpy(this->server_hostname, m,
sizeof(this->server_hostname));
if (m && opt == 2)
this->server_port = atoi(m);
}
else if (opt == 0) {
/* Cannot be both client and server */
if (this->network_client != NULL) {
delete this->network_client;
this->network_client = NULL;
}
this->network_server = new NetworkServer(this->server_port);
}
else if (opt == 3)
{
if (this->network_server != NULL) {
delete this->network_server;
this->network_server = NULL;
}
this->network_client = new NetworkClient(this->server_hostname,
this->server_port);
}
} while (opt == 1 || opt == 2);
this->prefs_changed = true;
}
void C64::other_options(Prefs *np) void C64::other_options(Prefs *np)
{ {
int submenus[3] = { np->DisplayOption, 0, !np->Emul1541Proc }; const char *other_options_messages[] = {
"Display resolution", /* 0 */
"^|double-center|stretched",
"Speed (approx)", /* 2 */
"^|95|100|110",
"Emulate 1541", /* 4 */
"^|On|Off",
"Networking", /* 6 */
NULL,
};
int submenus[3] = { np->DisplayOption, 0, !np->Emul1541Proc };
#define SPEED_95 33 #define SPEED_95 33
#define SPEED_100 28 #define SPEED_100 28
#define SPEED_110 25 #define SPEED_110 25
switch (np->MsPerFrame) switch (np->MsPerFrame)
{ {
case SPEED_95: case SPEED_95:
submenus[1] = 0; break; submenus[1] = 0; break;
case SPEED_110: case SPEED_110:
submenus[1] = 2; break; submenus[1] = 2; break;
default: default:
/* If it has some other value... */ /* If it has some other value... */
submenus[1] = 1; break; submenus[1] = 1; break;
} }
int opt = menu_select(real_screen, this->menu_font, int opt = menu_select(real_screen, this->menu_font,
other_options_messages, submenus); other_options_messages, submenus);
if (opt >= 0) if (opt >= 0)
@ -334,6 +396,10 @@ void C64::other_options(Prefs *np)
default: default:
np->MsPerFrame = SPEED_110; break; np->MsPerFrame = SPEED_110; break;
} }
if (opt == 6)
this->networking_menu(np);
this->prefs_changed = true; this->prefs_changed = true;
} }
} }
@ -536,6 +602,19 @@ void C64::VBlank(bool draw_frame)
TheDisplay->Speedometer((int)speed_index); TheDisplay->Speedometer((int)speed_index);
#endif #endif
} }
if (this->network_server) {
/* Perhaps accept a new connection */
this->network_server->CheckNewConnection();
for (int i = 0; i < this->network_server->n_clients; i++) {
Uint8 *master = this->TheDisplay->BitmapBase();
NetworkClient *remote = this->network_server->clients[i];
remote->EncodeDisplay(master, remote->screen);
remote->SendUpdate();
remote->ResetNetworkUpdate();
}
}
if (this->have_a_break) { if (this->have_a_break) {
int submenus[1]; int submenus[1];
int opt; int opt;

View File

@ -151,6 +151,7 @@ C64_SC.o: C64.cpp sysdeps.h sysconfig.h C64.h CPUC64.h CPU1541.h CIA.h C64_SDL.h
C64_SC.o: Prefs.h VIC.h SID.h REU.h IEC.h 1541job.h Display.h C64_SC.o: Prefs.h VIC.h SID.h REU.h IEC.h 1541job.h Display.h
CPUC64.o: sysdeps.h sysconfig.h CPUC64.h C64.h VIC.h SID.h CIA.h Prefs.h CPUC64.o: sysdeps.h sysconfig.h CPUC64.h C64.h VIC.h SID.h CIA.h Prefs.h
CPUC64.o: REU.h IEC.h Display.h Version.h CPU_emulline.h CPUC64.o: REU.h IEC.h Display.h Version.h CPU_emulline.h
Network.o: Network.h NetworkUnix.h
CPUC64_SC.o: sysdeps.h sysconfig.h CPUC64.h C64.h CPU_common.h VIC.h SID.h CPUC64_SC.o: sysdeps.h sysconfig.h CPUC64.h C64.h CPU_common.h VIC.h SID.h
CPUC64_SC.o: CIA.h Prefs.h REU.h IEC.h Display.h Version.h CPU_emulcycle.h CPUC64_SC.o: CIA.h Prefs.h REU.h IEC.h Display.h Version.h CPU_emulcycle.h
VIC.o: sysdeps.h sysconfig.h VIC.h C64.h CPUC64.h Display.h Prefs.h VIC.o: sysdeps.h sysconfig.h VIC.h C64.h CPUC64.h Display.h Prefs.h

View File

@ -22,8 +22,8 @@
#include "Network.h" #include "Network.h"
#include "Display.h" #include "Display.h"
#define N_SQUARES_W 6 #define N_SQUARES_W 20
#define N_SQUARES_H 4 #define N_SQUARES_H 20
#define SQUARE_W (DISPLAY_X / N_SQUARES_W) #define SQUARE_W (DISPLAY_X / N_SQUARES_W)
#define SQUARE_H (DISPLAY_Y / N_SQUARES_H) #define SQUARE_H (DISPLAY_Y / N_SQUARES_H)
@ -33,6 +33,20 @@
#define RAW_SIZE ( (SQUARE_W * SQUARE_H) / 2 ) #define RAW_SIZE ( (SQUARE_W * SQUARE_H) / 2 )
Network::Network()
{
const size_t size = NETWORK_UPDATE_SIZE;
/* "big enough" static buffer */
this->ud = (NetworkUpdate*)malloc( size );
this->ResetNetworkUpdate();
}
Network::~Network()
{
free(this->ud);
}
size_t Network::EncodeDisplayRaw(struct NetworkDisplayUpdate *dst, Uint8 *screen, size_t Network::EncodeDisplayRaw(struct NetworkDisplayUpdate *dst, Uint8 *screen,
int x_start, int y_start) int x_start, int y_start)
{ {
@ -193,6 +207,45 @@ size_t Network::EncodeDisplaySquare(struct NetworkDisplayUpdate *dst,
return dst->size; return dst->size;
} }
bool Network::CompareSquare(Uint8 *a, Uint8 *b)
{
for (int y = 0; y < SQUARE_H; y++)
{
for (int x = 0; x < SQUARE_W; x++)
{
Uint8 va = a[ y * DISPLAY_X + x ];
Uint8 vb = b[ y * DISPLAY_X + x ];
if (va == vb)
return false;
}
}
return true;
}
size_t Network::EncodeDisplay(Uint8 *master, Uint8 *remote)
{
for ( int sq = 0; sq < N_SQUARES_H * N_SQUARES_W; sq++ )
{
Uint8 *p_master = &master[ SQUARE_TO_Y(sq) * DISPLAY_X + SQUARE_TO_X(sq) ];
Uint8 *p_remote= &remote[ SQUARE_TO_Y(sq) * DISPLAY_X + SQUARE_TO_X(sq) ];
if (this->CompareSquare(p_master, p_remote) == false)
{
NetworkDisplayUpdate *dst = (NetworkDisplayUpdate *)this->cur_ud;
/* Updated, encode this */
this->EncodeDisplaySquare(dst, master, sq);
this->AddNetworkUpdate((NetworkUpdate*)dst);
}
}
/* Everything encoded, store in remote */
memcpy(remote, master, DISPLAY_X * DISPLAY_Y);
}
bool Network::DecodeDisplayUpdate(Uint8 *screen, bool Network::DecodeDisplayUpdate(Uint8 *screen,
struct NetworkDisplayUpdate *src) struct NetworkDisplayUpdate *src)
{ {
@ -246,37 +299,28 @@ size_t Network::DecodeSoundUpdate(struct NetworkSoundUpdate *src, char *buf)
return out; return out;
} }
NetworkUpdate *Network::GetNetworkUpdate(void) void Network::ResetNetworkUpdate(void)
{ {
static NetworkUpdate *out; memset(this->ud, 0, NETWORK_UPDATE_SIZE);
const size_t size = NETWORK_UPDATE_SIZE;
if (!out) this->ud->type = HEADER;
{ this->ud->size = sizeof(NetworkUpdate);
/* "big enough" static buffer */ this->cur_ud = (Uint8*)(this->ud + sizeof(NetworkUpdate));
out = (NetworkUpdate*)malloc( size );
}
memset(out, 0, size);
out->type = HEADER;
out->size = 0;
return out;
} }
bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock) bool Network::ReceiveUpdate(int sock)
{ {
struct timeval tv; struct timeval tv;
memset(&tv, 0, sizeof(tv)); memset(&tv, 0, sizeof(tv));
return this->ReceiveUpdate(dst, sock, &tv); return this->ReceiveUpdate(this->ud, sock, &tv);
} }
bool Network::ReceiveUpdateBlock(NetworkUpdate *dst, int sock) bool Network::ReceiveUpdateBlock(int sock)
{ {
return this->ReceiveUpdate(dst, sock, NULL); return this->ReceiveUpdate(this->ud, sock, NULL);
} }
void Network::MarshalData(NetworkUpdate *ud) void Network::MarshalData(NetworkUpdate *ud)
@ -370,5 +414,30 @@ NetworkUpdate *Network::IterateNext(NetworkUpdate *p, unsigned int *cookie)
return cur; return cur;
} }
void NetworkServer::AddClient(int sock)
{
NetworkClient *cli = new NetworkClient(sock);
this->clients[this->n_clients] = cli;
this->n_clients++;
}
NetworkClient::NetworkClient(int sock)
{
this->sock = sock;
this->screen = (Uint8 *)malloc(DISPLAY_X * DISPLAY_Y);
assert(this->screen);
/* Assume black screen */
memset(this->screen, 0, DISPLAY_X * DISPLAY_Y);
}
NetworkClient::~NetworkClient()
{
free(this->screen);
}
#include "NetworkUnix.h" #include "NetworkUnix.h"

View File

@ -36,6 +36,7 @@ struct NetworkJoystickUpdate
{ {
Uint8 type; Uint8 type;
Uint8 which; Uint8 which;
Uint16 size;
Uint8 data; /* New value */ Uint8 data; /* New value */
}; };
@ -52,6 +53,10 @@ struct NetworkUpdate
class Network class Network
{ {
public: public:
Network();
~Network();
/** Encode part of a screen into @a dst /** Encode part of a screen into @a dst
* *
* @param dst the destination update structure * @param dst the destination update structure
@ -63,6 +68,8 @@ public:
size_t EncodeDisplaySquare(struct NetworkDisplayUpdate *dst, size_t EncodeDisplaySquare(struct NetworkDisplayUpdate *dst,
Uint8 *screen, int square); Uint8 *screen, int square);
size_t EncodeDisplay(Uint8 *master, Uint8 *remote);
/** /**
* Encode the @a buf sound buffer into @a dst * Encode the @a buf sound buffer into @a dst
* *
@ -88,17 +95,13 @@ public:
size_t DecodeSoundUpdate(struct NetworkSoundUpdate *src, char *buf); size_t DecodeSoundUpdate(struct NetworkSoundUpdate *src, char *buf);
NetworkUpdate *GetNetworkUpdate(void); void ResetNetworkUpdate(void);
bool SendUpdate(NetworkUpdate *src, int sock); bool SendUpdate(int sock);
bool ReceiveUpdate(NetworkUpdate *dst, int sock); bool ReceiveUpdate(int sock);
bool ReceiveUpdateBlock(NetworkUpdate *dst, int sock); bool ReceiveUpdateBlock(int sock);
NetworkUpdate *IterateFirst(NetworkUpdate *p, unsigned int *cookie);
NetworkUpdate *IterateNext(NetworkUpdate *p, unsigned int *cookie);
private: private:
size_t EncodeDisplayRLE(struct NetworkDisplayUpdate *dst, Uint8 *screen, size_t EncodeDisplayRLE(struct NetworkDisplayUpdate *dst, Uint8 *screen,
@ -110,6 +113,25 @@ private:
size_t EncodeSoundRaw(struct NetworkSoundUpdate *dst, size_t EncodeSoundRaw(struct NetworkSoundUpdate *dst,
Uint8 *buffer, size_t len); Uint8 *buffer, size_t len);
NetworkUpdate *IterateFirst(NetworkUpdate *p, unsigned int *cookie);
NetworkUpdate *IterateNext(NetworkUpdate *p, unsigned int *cookie);
void AddNetworkUpdate(struct NetworkUpdate *update)
{
this->cur_ud += update->size;
this->ud->size += update->size;
}
/**
* Compare two display squares.
*
* @param a the first square (first byte)
* @param b the second square (first byte)
*
* @return true if they are equal
*/
bool CompareSquare(Uint8 *a, Uint8 *b);
bool DecodeDisplayRLE(Uint8 *screen, struct NetworkDisplayUpdate *src, bool DecodeDisplayRLE(Uint8 *screen, struct NetworkDisplayUpdate *src,
int x, int y); int x, int y);
bool DecodeDisplayRaw(Uint8 *screen, struct NetworkDisplayUpdate *src, bool DecodeDisplayRaw(Uint8 *screen, struct NetworkDisplayUpdate *src,
@ -120,6 +142,9 @@ private:
void MarshalData(NetworkUpdate *ud); void MarshalData(NetworkUpdate *ud);
void DeMarshalData(NetworkUpdate *ud); void DeMarshalData(NetworkUpdate *ud);
NetworkUpdate *ud;
Uint8 *cur_ud;
}; };
class NetworkClient : public Network class NetworkClient : public Network
@ -127,7 +152,30 @@ class NetworkClient : public Network
public: public:
NetworkClient(int sock); NetworkClient(int sock);
bool ConnectToServer(const char *hostname, int port); ~NetworkClient();
NetworkClient(const char *hostname, int port);
bool isConnected()
{
return this->sock >= 0;
}
bool SendUpdate()
{
return ((Network*)this)->SendUpdate(this->sock);
}
bool ReceiveUpdate()
{
return ((Network*)this)->ReceiveUpdate(this->sock);
}
bool ReceiveUpdateBlock()
{
return ((Network*)this)->ReceiveUpdateBlock(this->sock);
}
Uint8 *screen; Uint8 *screen;
int joystick_port; int joystick_port;
@ -135,19 +183,22 @@ private:
int sock; int sock;
}; };
#define MAX_NETWORK_CLIENTS 8
class NetworkServer : public Network class NetworkServer : public Network
{ {
public: public:
NetworkServer(); NetworkServer(int port);
NetworkClient *CheckNewConnection(); bool CheckNewConnection();
NetworkClient **clients; NetworkClient *clients[MAX_NETWORK_CLIENTS];
int n_clients; int n_clients;
private: private:
void AddClient(int sock);
int listen_sock; int listen_sock;
fd_set listen_fds;
}; };
#endif /* NETWORK_H */ #endif /* NETWORK_H */

View File

@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netdb.h>
/* From glibc docs */ /* From glibc docs */
static int make_socket (uint16_t port) static int make_socket (uint16_t port)
@ -30,51 +31,101 @@ static int make_socket (uint16_t port)
return sock; return sock;
} }
bool init_sockaddr (struct sockaddr_in *name,
const char *hostname, uint16_t port)
{
struct hostent *hostinfo;
NetworkServer::NetworkServer() name->sin_family = AF_INET;
name->sin_port = htons (port);
hostinfo = gethostbyname (hostname);
if (hostinfo == NULL)
{
fprintf (stderr, "Unknown host %s.\n", hostname);
return false;
}
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
return true;
}
NetworkServer::NetworkServer(int port)
{ {
this->n_clients = 0; this->n_clients = 0;
this->listen_sock = make_socket(27697); this->listen_sock = make_socket(port);
FD_ZERO(&this->listen_fds); if (listen(this->listen_sock, MAX_NETWORK_CLIENTS) < 0)
FD_SET(this->listen_sock, &this->listen_fds);
if (listen(this->listen_sock, 4) < 0)
{ {
perror("listen"); perror("listen");
exit(1); exit(1);
} }
} }
NetworkClient *NetworkServer::CheckNewConnection() bool NetworkServer::CheckNewConnection()
{ {
struct timeval tv; struct timeval tv;
struct sockaddr_in client_name; struct sockaddr_in client_name;
size_t size; size_t size;
int client_sock; int client_sock;
fd_set listen_fds;
/* No more than that thanks... */
if (this->n_clients >= MAX_NETWORK_CLIENTS)
return false;
FD_ZERO(&listen_fds);
FD_SET(this->listen_sock, &listen_fds);
/* If something connects, create a new client */ /* If something connects, create a new client */
memset(&tv, 0, sizeof(tv)); memset(&tv, 0, sizeof(tv));
if (select(1, &this->listen_fds, NULL, NULL, &tv) <= 0) int v = select(this->listen_sock + 1, &listen_fds, NULL, NULL, &tv);
return NULL;
if ( v < 0)
{
perror("select");
exit(1);
}
else if ( v == 0 )
return false;
client_sock = accept(this->listen_sock, (struct sockaddr*)&client_name, &size); client_sock = accept(this->listen_sock, (struct sockaddr*)&client_name, &size);
if (client_sock < 0) if (client_sock < 0)
{ {
fprintf(stderr, "Accepting client failed\n"); fprintf(stderr, "Accepting client failed\n");
return NULL; return false;
} }
return new NetworkClient(client_sock); printf("Nej men vobb! En klient har konnektat!\n");
/* And add the new one! */
this->AddClient(client_sock);
return true;
} }
NetworkClient::NetworkClient(const char *hostname, int port)
NetworkClient::NetworkClient(int sock)
{ {
this->sock = sock; /* Again from glibc docs */
struct sockaddr_in servername;
/* Assume black screen */ /* Create the socket. */
memset(this->screen, 0, DISPLAY_X * DISPLAY_Y); this->sock = socket (PF_INET, SOCK_STREAM, 0);
if (this->sock < 0)
{
perror ("socket (client)");
return;
}
/* Connect to the server. */
init_sockaddr (&servername, hostname, port);
if (connect(sock, (struct sockaddr *) &servername,
sizeof (servername)) != 0)
{
perror ("connect (client)");
return;
}
NetworkClient::NetworkClient(this->sock);
} }
bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv) bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv)
@ -103,13 +154,16 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv)
return true; return true;
} }
bool Network::SendUpdate(NetworkUpdate *src, int sock) bool Network::SendUpdate(int sock)
{ {
NetworkUpdate *src = this->ud;
int sz = src->size; int sz = src->size;
bool out = true;
this->MarshalData(src); this->MarshalData(src);
sz = write(sock, (void*)src, sz); sz = write(sock, (void*)src, sz);
if (sz < src->size) if (sz < src->size)
return false; out = false;
return true;
return out;
} }