From 8c73c900df47a39066bd0b5c7af1b45153f0f3b7 Mon Sep 17 00:00:00 2001 From: "simon.kagstrom" Date: Sun, 1 Feb 2009 19:47:21 +0000 Subject: [PATCH] Refactored the network implementation. It's now based on a singleton/factory pattern where peers are equal (almost!). This has simplified the code a bit and also in theory allows clients to "re-export" connections to third/fourth/... parties. --- Src/C64.h | 10 ++- Src/C64_SDL.h | 201 +++++++++++++++++++++------------------------- Src/Display_SDL.h | 10 +-- Src/Network.cpp | 107 ++++++++++++------------ Src/Network.h | 109 ++++++++++--------------- Src/NetworkUnix.h | 61 ++++++++------ 6 files changed, 233 insertions(+), 265 deletions(-) diff --git a/Src/C64.h b/Src/C64.h index ab22efc..a9d1354 100644 --- a/Src/C64.h +++ b/Src/C64.h @@ -41,6 +41,13 @@ #include "ROlib.h" #endif +/* Network connection type */ +enum +{ + NONE, + MASTER, + CLIENT +}; // Sizes of memory areas const int C64_RAM_SIZE = 0x10000; @@ -185,10 +192,9 @@ public: #endif #ifdef HAVE_SDL VirtualKeyboard *virtual_keyboard; - NetworkServer *network_server; - NetworkClient *network_client; char server_hostname[255]; int server_port; + int network_connection_type; TTF_Font *menu_font; bool fake_key_sequence; diff --git a/Src/C64_SDL.h b/Src/C64_SDL.h index 7f48928..adf8b1b 100644 --- a/Src/C64_SDL.h +++ b/Src/C64_SDL.h @@ -95,20 +95,21 @@ void C64::c64_ctor1(void) } 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; + this->network_connection_type = NONE; - if (fixme_tmp_network_server) - this->network_server = new NetworkServer(this->server_port); + if (fixme_tmp_network_server) { + Network::StartListener(this->server_port); + this->network_connection_type = MASTER; + } if (fixme_tmp_network_client) { strcpy(this->server_hostname, fixme_tmp_network_client); - this->network_client = new NetworkClient(this->server_hostname, - this->server_port); + Network::ConnectTo(this->server_hostname, this->server_port); + this->network_connection_type = CLIENT; } } @@ -317,16 +318,16 @@ void C64::networking_menu(Prefs *np) { char buf[2][255]; const char *network_client_messages[] = { - "Start network server", /* 0 */ + "Listen for connections",/* 0 */ buf[0], /* 1 */ buf[1], /* 2 */ - "Connect to server", /* 3 */ + "Connect to remote", /* 3 */ NULL, }; - snprintf(buf[0], 255, "Server hostname (now %s)", + snprintf(buf[0], 255, "Remote hostname (now %s)", this->server_hostname); - snprintf(buf[1], 255, "Server port (now %d)", + snprintf(buf[1], 255, "Port (now %d)", this->server_port); opt = menu_select(real_screen, this->menu_font, network_client_messages, NULL); @@ -342,22 +343,12 @@ void C64::networking_menu(Prefs *np) 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); + Network::StartListener(this->server_port); + this->network_connection_type = MASTER; } - 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); + else if (opt == 3) { + Network::ConnectTo(this->server_hostname, this->server_port); + this->network_connection_type = CLIENT; } } while (opt == 1 || opt == 2); @@ -566,97 +557,84 @@ void C64::network_vblank() Uint32 now = SDL_GetTicks(); #endif - if (this->network_server) { - /* Perhaps accept a new connection */ - this->network_server->CheckNewConnection(); + /* Perhaps accept a new connection */ + Network::CheckNewConnection(); - for (int i = 0; i < this->network_server->n_clients; i++) { - Uint8 *master = this->TheDisplay->BitmapBase(); - NetworkClient *remote = this->network_server->clients[i]; - static bool has_throttled; + for (int i = 0; i < Network::n_peers; i++) { + Uint8 *master = this->TheDisplay->BitmapBase(); + Network *remote = Network::peers[i]; + uint8 *js; + static bool has_throttled; - remote->Tick( now - last_time_update ); - /* Has the client sent any data? */ - if (remote->ReceiveUpdate() == true) - { - uint8 *js = &TheCIA1->Joystick2; + if (this->quit_thyself) + { + remote->Disconnect(); + continue; + } - if (ThePrefs.JoystickSwap) - js = &TheCIA1->Joystick1; - if (remote->DecodeUpdate(NULL, js, true) == false) - { - /* Disconnect or sending crap, remove this guy! */ - this->network_server->RemoveClient(remote); - continue; - } - remote->ResetNetworkUpdate(); - } - if (remote->ThrottleTraffic()) { - /* Skip this frame if the data rate is too high */ - has_throttled = true; - continue; - } - remote->EncodeDisplay(master, remote->screen); - if (remote->SendUpdate() == false) - { - /* Disconnect or broken data */ - printf("Could not send update\n"); - this->network_server->RemoveClient(remote); - } + remote->Tick( now - last_time_update ); + if (this->network_connection_type == MASTER) { + if (ThePrefs.JoystickSwap) + js = &TheCIA1->Joystick1; + else + js = &TheCIA1->Joystick2; + } else { + if (ThePrefs.JoystickSwap) + js = &TheCIA1->Joystick2; + else + js = &TheCIA1->Joystick1; + } + + /* Has the peer sent any data? */ + if (remote->ReceiveUpdate() == true) + { + if (remote->DecodeUpdate(remote->GetScreen(), js) == false) + { + /* Disconnect or sending crap, remove this guy! */ + Network::RemovePeer(remote); + continue; + } + if (this->network_connection_type == CLIENT) + this->TheDisplay->Update(remote->GetScreen()); + } + remote->ResetNetworkUpdate(); + + /* Perhaps send updates to the other side (what is determinted by + * if this is the master or not) */ + remote->EncodeJoystickUpdate(*js); + remote->EncodeDisplay(master, remote->GetScreen()); + + if (this->network_connection_type == MASTER && + remote->ThrottleTraffic()) { + /* Skip this frame if the data rate is too high */ + has_throttled = true; + continue; + } + + if (remote->SendUpdate() == false) + { + /* Disconnect or broken data */ + printf("Could not send update\n"); + Network::RemovePeer(remote); + } + else remote->ResetNetworkUpdate(); - if (1) - { - static uint32_t last_traffic_update; + if (1) + { + static uint32_t last_traffic_update; - if (last_time_update - last_traffic_update > 300) - { - TheDisplay->NetworkTrafficMeter(remote->GetKbps() / (8 * 1024.0), - has_throttled); - last_traffic_update = now; - has_throttled = false; - } - } - } - } - else if (this->network_client) { - Uint8 js = TheCIA1->Joystick2; + if (last_time_update - last_traffic_update > 300) + { + TheDisplay->NetworkTrafficMeter(remote->GetKbps() / (8 * 1024.0), + has_throttled); + last_traffic_update = now; + has_throttled = false; + } + } + } - if (this->quit_thyself) - { - this->network_client->Disconnect(); - delete this->network_client; - this->network_client = NULL; - return; - } - - /* Perhaps send joystick data */ - if (this->network_client->cur_joystick_data != js) - { - this->network_client->EncodeJoystickUpdate(js); - this->network_client->SendUpdate(); - this->network_client->cur_joystick_data = js; - this->network_client->ResetNetworkUpdate(); - } - - if (this->network_client->ReceiveUpdate()) - { - /* Got something? */ - if (this->network_client->DecodeUpdate(this->network_client->screen) == true) - { - TheDisplay->Update(this->network_client->screen); - this->network_client->ResetNetworkUpdate(); - } - else - { - /* Disconnect or broken data */ - this->network_client->Disconnect(); - delete this->network_client; - this->network_client = NULL; - } - } - } - last_time_update = now; + last_time_update = now; } /* @@ -693,7 +671,7 @@ void C64::VBlank(bool draw_frame) j2 &= joykey; #endif - if (this->network_server) + if (this->network_connection_type == MASTER) { /* Only poll one joystick for network servers */ if (ThePrefs.JoystickSwap) @@ -712,7 +690,7 @@ void C64::VBlank(bool draw_frame) TheCIA2->CountTOD(); // Update window if needed - if (draw_frame && this->network_client == NULL) { + if (draw_frame && this->network_connection_type != CLIENT) { TheDisplay->Update(); } @@ -778,6 +756,7 @@ void C64::VBlank(bool draw_frame) ThePrefs.Save(PREFS_PATH); } this->network_vblank(); + #if defined(GEKKO) now = ticks_to_millisecs(gettime()); #else diff --git a/Src/Display_SDL.h b/Src/Display_SDL.h index 2e865bf..5d8f028 100644 --- a/Src/Display_SDL.h +++ b/Src/Display_SDL.h @@ -227,13 +227,11 @@ void C64Display::Update(uint8 *src_pixels) } draw_string(real_screen, 0, 0, networktraffic_string, black, fill_gray); - if (this->TheC64->network_server) { - for (int i = 0; i < this->TheC64->network_server->n_clients; i++) - { - NetworkClient *client = this->TheC64->network_server->clients[i]; + for (int i = 0; i < Network::n_peers; i++) + { + Network *peer = Network::peers[i]; - client->DrawTransferredBlocks(real_screen); - } + peer->DrawTransferredBlocks(real_screen); } SDL_Flip(real_screen); } diff --git a/Src/Network.cpp b/Src/Network.cpp index 2ad5361..7b6c5bb 100644 --- a/Src/Network.cpp +++ b/Src/Network.cpp @@ -36,10 +36,13 @@ #define RLE_SIZE ( RAW_SIZE * 4 + 8) #define DIFF_SIZE ( RAW_SIZE * 4 + 8) -Network::Network() +Network::Network(int sock, bool is_master) { const size_t size = NETWORK_UPDATE_SIZE; + this->sock = sock; + this->is_master = is_master; + /* "big enough" buffer */ this->ud = (NetworkUpdate*)malloc( size ); this->tmp_ud = (NetworkUpdate*)malloc( size ); @@ -59,6 +62,12 @@ Network::Network() this->square_updated = (Uint32*)malloc( N_SQUARES_W * N_SQUARES_H * sizeof(Uint32)); assert(this->square_updated); memset(this->square_updated, 0, N_SQUARES_W * N_SQUARES_H * sizeof(Uint32)); + + this->screen = (Uint8 *)malloc(DISPLAY_X * DISPLAY_Y); + assert(this->screen); + + /* Assume black screen */ + memset(this->screen, 0, DISPLAY_X * DISPLAY_Y); } Network::~Network() @@ -69,6 +78,9 @@ Network::~Network() free(this->raw_buf); free(this->rle_buf); free(this->diff_buf); + free(this->screen); + + this->CloseSocket(); } void Network::Tick(int ms) @@ -223,8 +235,10 @@ bool Network::CompareSquare(Uint8 *a, Uint8 *b) return true; } -size_t Network::EncodeDisplay(Uint8 *master, Uint8 *remote) +void Network::EncodeDisplay(Uint8 *master, Uint8 *remote) { + if (!this->is_master) + return; 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) ]; @@ -366,11 +380,14 @@ void Network::EncodeJoystickUpdate(Uint8 v) { struct NetworkUpdate *dst = this->cur_ud; + if (this->is_master || this->cur_joystick_data == v) + return; dst->type = JOYSTICK_UPDATE; dst->u.joystick.val = v; dst->size = sizeof(NetworkUpdate); this->AddNetworkUpdate(dst); + this->cur_joystick_data = v; } @@ -436,26 +453,20 @@ void Network::DrawTransferredBlocks(SDL_Surface *screen) } } -bool Network::ReceiveUpdate(int sock) +bool Network::ReceiveUpdate() { struct timeval tv; memset(&tv, 0, sizeof(tv)); - return this->ReceiveUpdate(this->ud, sock, &tv); + return this->ReceiveUpdate(this->ud, &tv); } - -bool Network::ReceiveUpdateBlock(int sock) -{ - return this->ReceiveUpdate(this->ud, sock, NULL); -} - -bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv) +bool Network::ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv) { Uint8 *pp = (Uint8*)dst; NetworkUpdate *p; - if (this->Select(sock, tv) == false) + if (this->Select(this->sock, tv) == false) return false; /* Receive until the stop */ do @@ -463,7 +474,7 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv) p = (NetworkUpdate*)pp; /* Receive the header */ - if (this->ReceiveData((void*)p, sock, sizeof(NetworkUpdate)) == false) + if (this->ReceiveData((void*)p, this->sock, sizeof(NetworkUpdate)) == false) return false; pp = pp + sizeof(NetworkUpdate); @@ -474,7 +485,7 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv) { size_t sz_diff = sz - sizeof(NetworkUpdate); - if (this->ReceiveData((void*)pp, sock, sz_diff) == false) + if (this->ReceiveData((void*)pp, this->sock, sz_diff) == false) return false; pp = pp + sz_diff; } @@ -485,12 +496,16 @@ bool Network::ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv) return true; } -bool Network::SendUpdate(int sock) +bool Network::SendUpdate() { NetworkUpdate *src = this->ud; NetworkUpdate *stop = this->cur_ud; size_t sz; + /* Nothing to send, that's OK */ + if ( src == stop ) + return true; + /* Add a stop at the end of the update */ stop->type = STOP; stop->u.stop.val = STOP; @@ -503,7 +518,7 @@ bool Network::SendUpdate(int sock) sz = this->GetNetworkUpdateSize(); if (sz <= 0) return false; - if (this->SendData((void*)src, sock, sz) == false) + if (this->SendData((void*)src, this->sock, sz) == false) return false; this->traffic += sz; @@ -585,7 +600,7 @@ bool Network::DeMarshalData(NetworkUpdate *p) return true; } -bool Network::DecodeUpdate(uint8 *screen, uint8 *js, bool server) +bool Network::DecodeUpdate(uint8 *screen, uint8 *js) { NetworkUpdate *p = this->ud; bool out = true; @@ -597,13 +612,15 @@ bool Network::DecodeUpdate(uint8 *screen, uint8 *js, bool server) case DISPLAY_UPDATE_RAW: case DISPLAY_UPDATE_RLE: case DISPLAY_UPDATE_DIFF: - if (screen == NULL) + /* No screen updates _to_ the master */ + if (this->is_master) break; if (this->DecodeDisplayUpdate(screen, p) == false) out = false; break; case JOYSTICK_UPDATE: - if (js) + /* No joystick updates _from_ the master */ + if (js && this->is_master) *js = p->u.joystick.val; break; case DISCONNECT: @@ -618,56 +635,32 @@ bool Network::DecodeUpdate(uint8 *screen, uint8 *js, bool server) return out; } -void NetworkServer::AddClient(int sock) +void Network::AddPeer(Network *peer) { - NetworkClient *cli = new NetworkClient(sock); - - this->clients[this->n_clients] = cli; - this->n_clients++; + Network::peers[Network::n_peers] = peer; + Network::n_peers++; } -void NetworkServer::RemoveClient(NetworkClient *client) +void Network::RemovePeer(Network *peer) { - for (int i = 0; i < this->n_clients; i++) + for (int i = 0; i < Network::n_peers; i++) { - if (this->clients[i] == client) + if (Network::peers[i] == peer) { - if (i < this->n_clients - 1) + if (i < Network::n_peers - 1) { /* Swap with last */ - this->clients[i] = this->clients[this->n_clients - 1]; + Network::peers[i] = Network::peers[Network::n_peers - 1]; } - delete client; - this->n_clients--; + delete peer; + Network::n_peers--; return; } } /* Not found */ } -void NetworkClient::Init() -{ - this->screen = (Uint8 *)malloc(DISPLAY_X * DISPLAY_Y); - assert(this->screen); - - /* Assume black screen */ - memset(this->screen, 0, DISPLAY_X * DISPLAY_Y); -} - - -NetworkClient::NetworkClient(int sock) -{ - this->Init(); - this->sock = sock; -} - -NetworkClient::~NetworkClient() -{ - free(this->screen); - this->CloseSocket(this->sock); -} - -void NetworkClient::Disconnect() +void Network::Disconnect() { NetworkUpdate *disconnect= this->cur_ud; size_t sz; @@ -677,6 +670,12 @@ void NetworkClient::Disconnect() disconnect->size = sizeof(NetworkUpdate); this->AddNetworkUpdate(disconnect); this->SendUpdate(); + + Network::RemovePeer(this); } +int Network::n_peers; +int Network::listen_sock; +Network *Network::peers[MAX_NETWORK_PEERS]; + #include "NetworkUnix.h" diff --git a/Src/Network.h b/Src/Network.h index b250a19..80ee0f2 100644 --- a/Src/Network.h +++ b/Src/Network.h @@ -8,6 +8,8 @@ #endif #include +#define MAX_NETWORK_PEERS 8 + #define NETWORK_UPDATE_SIZE (256 * 1024) enum { @@ -49,16 +51,16 @@ struct NetworkUpdate class Network { public: - Network(); + Network(int sock, bool is_master); ~Network(); - size_t EncodeDisplay(Uint8 *master, Uint8 *remote); + void EncodeDisplay(Uint8 *master, Uint8 *remote); void EncodeJoystickUpdate(Uint8 v); - bool DecodeUpdate(uint8 *screen, uint8 *js = NULL, bool server = false); + bool DecodeUpdate(uint8 *screen, uint8 *js = NULL); void ResetNetworkUpdate(void); @@ -78,13 +80,41 @@ public: void Tick(int ms); - void CloseSocket(int sock); + void CloseSocket(); - bool SendUpdate(int sock); + bool SendUpdate(); - bool ReceiveUpdate(int sock); + bool ReceiveUpdate(); - bool ReceiveUpdateBlock(int sock); + static bool StartListener(int port); + + static bool CheckNewConnection(); + + static bool ConnectTo(const char *hostname, int port); + + bool isConnected() + { + return this->sock >= 0; + } + + Uint8 *GetScreen() + { + return this->screen; + } + + /** + * Disconnect from the other end. You should delete the object + * after having done this. + */ + void Disconnect(); + + static void AddPeer(Network *who); + + static void RemovePeer(Network *peer); + + /* Listener-related */ + static Network *peers[MAX_NETWORK_PEERS]; + static int n_peers; protected: size_t DecodeSoundUpdate(struct NetworkUpdate *src, char *buf); @@ -150,7 +180,7 @@ protected: bool DecodeDisplayRaw(Uint8 *screen, struct NetworkUpdate *src, int x, int y); - bool ReceiveUpdate(NetworkUpdate *dst, int sock, struct timeval *tv); + bool ReceiveUpdate(NetworkUpdate *dst, struct timeval *tv); bool ReceiveData(void *dst, int sock, size_t sz); @@ -181,72 +211,17 @@ protected: int time_since_last_reset; int target_kbps; int kbps; -}; - -class NetworkClient : public Network -{ -public: - NetworkClient(int sock); - - ~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); - } - - bool ReceiveData(void *dst, int sock, size_t sz); - - /** - * Disconnect from the other end. You should delete the object - * after having done this. - */ - void Disconnect(); Uint8 *screen; int joystick_port; + bool is_master; /* Some peers are more equal than others */ Uint8 cur_joystick_data; -private: - void Init(); + /* Connection to the peer */ int sock; -}; -#define MAX_NETWORK_CLIENTS 8 - -class NetworkServer : public Network -{ -public: - NetworkServer(int port); - - bool CheckNewConnection(); - - NetworkClient *clients[MAX_NETWORK_CLIENTS]; - int n_clients; - - void RemoveClient(NetworkClient *client); - -private: - void AddClient(int sock); - - int listen_sock; + /* Listener-related */ + static int listen_sock; }; #endif /* NETWORK_H */ diff --git a/Src/NetworkUnix.h b/Src/NetworkUnix.h index ad4c2d4..b39791d 100644 --- a/Src/NetworkUnix.h +++ b/Src/NetworkUnix.h @@ -66,36 +66,44 @@ bool init_sockaddr (struct sockaddr_in *name, } -NetworkServer::NetworkServer(int port) : Network() +bool Network::StartListener(int port) { - this->n_clients = 0; - this->listen_sock = make_socket(port); + Network::listen_sock = make_socket(port); - if (listen(this->listen_sock, MAX_NETWORK_CLIENTS) < 0) + if (Network::listen_sock < 0) + return false; + if (listen(Network::listen_sock, MAX_NETWORK_PEERS) < 0) { perror("listen"); - exit(1); + return false; } + + return true; } -bool NetworkServer::CheckNewConnection() +bool Network::CheckNewConnection() { struct timeval tv; - struct sockaddr_in client_name; + struct sockaddr_in peer_name; size_t size; - int client_sock; + int peer_sock; fd_set listen_fds; + Network *peer; + + /* Not initialized yet */ + if (Network::listen_sock <= 0) + return false; /* No more than that thanks... */ - if (this->n_clients >= MAX_NETWORK_CLIENTS) + if (Network::n_peers >= MAX_NETWORK_PEERS) return false; FD_ZERO(&listen_fds); - FD_SET(this->listen_sock, &listen_fds); + FD_SET(Network::listen_sock, &listen_fds); /* If something connects, create a new client */ memset(&tv, 0, sizeof(tv)); - int v = select(this->listen_sock + 1, &listen_fds, NULL, NULL, &tv); + int v = select(Network::listen_sock + 1, &listen_fds, NULL, NULL, &tv); if ( v < 0) { @@ -105,33 +113,32 @@ bool NetworkServer::CheckNewConnection() else if ( v == 0 ) return false; - size = sizeof(client_name); - client_sock = accept(this->listen_sock, (struct sockaddr*)&client_name, &size); - if (client_sock < 0) + size = sizeof(peer_name); + peer_sock = accept(Network::listen_sock, (struct sockaddr*)&peer_name, &size); + if (peer_sock < 0) { - fprintf(stderr, "Accepting client failed\n"); + fprintf(stderr, "Accepting peer failed\n"); return false; } /* And add the new one! */ - this->AddClient(client_sock); + Network::AddPeer(new Network(peer_sock, true)); return true; } -NetworkClient::NetworkClient(const char *hostname, int port) +bool Network::ConnectTo(const char *hostname, int port) { /* Again from glibc docs */ struct sockaddr_in servername; - - this->Init(); + int sock; /* Create the socket. */ - this->sock = socket (PF_INET, SOCK_STREAM, 0); - if (this->sock < 0) + sock = socket (PF_INET, SOCK_STREAM, 0); + if (sock < 0) { perror ("socket (client)"); - return; + return false; } set_sock_opts(sock); @@ -142,8 +149,12 @@ NetworkClient::NetworkClient(const char *hostname, int port) sizeof (servername)) != 0) { perror ("connect (client)"); - return; + return false; } + + Network::AddPeer( new Network(sock, false) ); + + return true; } bool Network::ReceiveData(void *dst, int sock, size_t sz) @@ -198,7 +209,7 @@ bool Network::Select(int sock, struct timeval *tv) return v > 0; } -void Network::CloseSocket(int sock) +void Network::CloseSocket() { - close(sock); + close(this->sock); }