gameserver monitor initial work
authorhgn <hgodden00@gmail.com>
Wed, 27 Sep 2023 15:05:39 +0000 (16:05 +0100)
committerhgn <hgodden00@gmail.com>
Wed, 27 Sep 2023 15:05:39 +0000 (16:05 +0100)
build.c
gameserver.c [new file with mode: 0644]
gameserver.h [new file with mode: 0644]
monitorinfo.h [new file with mode: 0644]
network.c [new file with mode: 0644]
network.h
network_msg.h
servermonitor_client.c [new file with mode: 0644]
servermonitor_server.c [new file with mode: 0644]
skaterift.c

diff --git a/build.c b/build.c
index 1c17f14e2be01a5814faf0088244f2f7015a53f3..d318d5c6297520b87ab7d27a99e7931e1ea7519d 100644 (file)
--- a/build.c
+++ b/build.c
 
 int compiled_something = 0;
 
-void build_server( enum compiler compiler )
-{
+/* old highscores server */
+void build_server( enum compiler compiler ){
    vg_build_start( "skaterift_server", compiler );
    vg_build_object( "server.c " );
    vg_build_link( "-lm -lsdkencryptedappticket -lsteam_api " );
    vg_build_library_dir( "-L./vg/dep/steam " );
 
-   vg_build_bin_dependency_file( "vg/dep/steam/steamclient.so" );
+   vg_build_bin_dependency_file( "vg/dep/steam/steamclient.so" );//TODO????
    vg_build_bin_dependency_file( "vg/dep/steam/libsteam_api.so" );
    vg_build_bin_dependency_file( "vg/dep/steam/libsdkencryptedappticket.so" );
 
@@ -30,6 +30,34 @@ void build_server( enum compiler compiler )
    compiled_something = 1;
 }
 
+/* new game server */
+void build_gameserver( enum compiler compiler ){
+   vg_build_start( "skaterift_gameserver", compiler );
+   vg_build_object( "gameserver.c" );
+
+   vg_build_link( "-lm -lsdkencryptedappticket -lsteam_api " );
+   vg_build_library_dir( "-L./vg/dep/steam " );
+
+   //vg_build_bin_dependency_file( "vg/dep/steam/steamclient.so" );?????
+   vg_build_bin_dependency_file( "vg/dep/steam/libsteam_api.so" );
+   vg_build_bin_dependency_file( "vg/dep/steam/libsdkencryptedappticket.so" );
+
+   vg_build();
+   compiled_something = 1;
+}
+
+void build_servermonitor( enum compiler compiler ){
+   vg_build_start( "skaterift_servermonitor", compiler );
+   vg_build_object( "servermonitor_client.c " );
+
+   vg_build_add_link_for_graphics();
+   vg_build_include( "-I./vg/dep " );
+   vg_build_copy_graphics_dependencies();
+
+   vg_build();
+   compiled_something = 1;
+}
+
 void write_msg( vg_msg *msg, const char *path ){
    FILE *fp = fopen( path, "wb" );
    if( !fp ){
@@ -58,8 +86,7 @@ void write_generic_addon_inf( u32 type, const char *title,
 }
 
 void build_shaders(void);
-void build_game( enum compiler compiler )
-{
+void build_game( enum compiler compiler ){
    static int shaders_built = 0;
    if( !shaders_built ){
       shaders_built = 1;
@@ -129,8 +156,7 @@ int main( int argc, char *argv[] ){
    time_t uid = time(NULL);
 
    char *arg;
-   while( vg_argp( argc, argv ) )
-   {
+   while( vg_argp( argc, argv ) ){
       if( vg_long_opt( "debug" ) || vg_opt( 'd' ) )
          vg_build_mode_debug();
 
@@ -140,6 +166,12 @@ int main( int argc, char *argv[] ){
       if( vg_long_opt( "clang-server" ) )
          build_server( k_compiler_clang );
 
+      if( vg_long_opt( "gcc-gameserver" ) )
+         build_gameserver( k_compiler_gcc );
+
+      if( vg_long_opt( "gcc-servermonitor" ) )
+         build_servermonitor( k_compiler_gcc );
+
       if( vg_long_opt( "clean" ) )
          vg_build_clean();
 
@@ -152,8 +184,7 @@ int main( int argc, char *argv[] ){
       if( vg_long_opt( "mingw" ) )
          build_game( k_compiler_mingw );
 
-      if( vg_opt('p') || vg_long_opt("run") )
-      {
+      if( vg_opt('p') || vg_long_opt("run") ){
          chdir( vg_compiler.build_dir );
          if( vg_compiler.compiler == k_compiler_mingw )
             vg_build_syscall( "wine %s.exe", vg_compiler.name );
@@ -162,16 +193,14 @@ int main( int argc, char *argv[] ){
          chdir( "../../" );
       }
 
-      if( vg_long_opt( "tar" ) || vg_opt( 't' ) )
-      {
+      if( vg_long_opt( "tar" ) || vg_opt( 't' ) ){
          vg_build_syscall( "mkdir -p dist" );
          if( compiled_something )
             vg_build_syscall( "tar -chzvf dist/%s-%u.tar.gz %s", 
                               vg_compiler.name, uid, vg_compiler.build_dir );
       }
 
-      if( vg_long_opt( "zip" ) || vg_opt( 'z' ) )
-      {
+      if( vg_long_opt( "zip" ) || vg_opt( 'z' ) ){
          vg_build_syscall( "mkdir -p dist" );
          if( compiled_something )
             vg_build_syscall( "zip -r9 dist/%s-%u.zip %s", 
@@ -183,8 +212,7 @@ int main( int argc, char *argv[] ){
 #define _S( NAME, VS, FS ) \
    vg_build_shader( "shaders/" VS, "shaders/" FS, NULL, "shaders", NAME )
 
-void build_shaders(void)
-{
+void build_shaders(void){
    vg_shader_set_include_dir( "shaders" );
 
    /* Scene */
diff --git a/gameserver.c b/gameserver.c
new file mode 100644 (file)
index 0000000..c63711a
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ */
+
+#define _DEFAULT_SOURCE
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+
+volatile sig_atomic_t sig_stop;
+
+static void inthandler( int signum ) {
+   sig_stop = 1;
+}
+
+#include "gameserver.h" 
+#include "highscores.c"
+#include "servermonitor_server.c"
+#include "vg/vg_opt.h"
+
+static const u64 k_connection_unauthorized = 0xffffffffffffffff;
+
+static u64_steamid get_connection_authsteamid( SteamNetworkingMessage_t *msg ){
+   i64 userdata = SteamAPI_ISteamNetworkingSockets_GetConnectionUserData(
+            hSteamNetworkingSockets, msg->m_conn );
+
+   return *((u64_steamid *)&userdata);
+}
+
+static void set_connection_authsteamid(HSteamNetConnection con, u64_steamid id){
+   i64 userdata = *((i64 *)&id);
+   
+   SteamAPI_ISteamNetworkingSockets_SetConnectionUserData(
+         hSteamNetworkingSockets, con, userdata );
+}
+
+static void new_client_connecting( HSteamNetConnection client ){
+   EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
+            hSteamNetworkingSockets, client );
+
+   if( accept_status == k_EResultOK ){
+      vg_success( "Accepted client (id: %u)\n", client );
+      SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
+            hSteamNetworkingSockets,
+            client, gameserver.client_group );
+      
+      /* Just to be sure */
+      set_connection_authsteamid( client, -1 );
+   }
+   else{
+      vg_warn( "Error accepting client (id: %u)\n", client );
+   }
+}
+
+static void on_auth_status( CallbackMsg_t *msg ){
+   SteamNetAuthenticationStatus_t *info = (void *)msg->m_pubParam;
+   vg_info( "  Authentication availibility: %s\n", 
+         string_ESteamNetworkingAvailability(info->m_eAvail) );
+   vg_info( "  %s\n", info->m_debugMsg );
+}
+
+static void on_connect_status( CallbackMsg_t *msg ){
+   SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
+   vg_info( "  Connection status changed for %lu\n", info->m_hConn );
+
+   vg_info( "  %s -> %s\n", 
+         string_ESteamNetworkingConnectionState(info->m_eOldState),
+         string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
+
+   if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ){
+      new_client_connecting( info->m_hConn );
+   }
+}
+
+static void on_inet_auth( SteamNetworkingMessage_t *msg ){
+   if( gameserver.auth_mode != eServerModeAuthentication ){
+      vg_error( "Running server without authentication. "
+                "Connection %u tried to authenticate.\n", msg->m_conn );
+      return;
+   }
+
+   if( get_connection_authsteamid( msg ) != k_connection_unauthorized ){
+      vg_warn( "Already authorized this user but app ticket was sent"
+               " again (%u)\n", msg->m_conn );
+      return;
+   }
+
+   vg_low( "Attempting to verify user\n" );
+
+   if( msg->m_cbSize < sizeof(netmsg_auth) ){
+      vg_error( "Malformed auth ticket, too small (%u)\n", msg->m_conn );
+      return;
+   }
+
+   netmsg_auth *auth = msg->m_pData;
+
+   if( msg->m_cbSize < sizeof(netmsg_auth)+auth->ticket_length ||
+       auth->ticket_length > 1024 ){
+      vg_error( "Malformed auth ticket, ticket_length incorrect (%u)\n",
+            auth->ticket_length );
+      return;
+   }
+
+   u8 decrypted[1024];
+   u32 ticket_len = 1024;
+
+   int success = SteamEncryptedAppTicket_BDecryptTicket(
+         auth->ticket, auth->ticket_length, decrypted,
+         &ticket_len, gameserver.app_symmetric_key,
+         k_nSteamEncryptedAppTicketSymmetricKeyLen );
+
+   if( !success ){
+      vg_error( "Failed to decrypt users ticket (client %u)\n", msg->m_conn );
+      vg_error( "  ticket length: %u\n", auth->ticket_length );
+
+      SteamAPI_ISteamNetworkingSockets_CloseConnection(
+            hSteamNetworkingSockets,
+            msg->m_conn, 0, NULL, 1 );
+      return;
+   }
+
+   if( SteamEncryptedAppTicket_GetTicketIssueTime( decrypted, ticket_len )){
+      RTime32 ctime = time(NULL),
+              tickettime = SteamEncryptedAppTicket_GetTicketIssueTime(
+                    decrypted, ticket_len ),
+              expiretime = tickettime + 24*3*60*60;
+      
+      if( ctime > expiretime ){
+         vg_error( "Ticket expired (client %u)\n", msg->m_conn );
+
+         /* TODO: Send expired information */
+         SteamAPI_ISteamNetworkingSockets_CloseConnection(
+               hSteamNetworkingSockets,
+               msg->m_conn, 0, NULL, 1 );
+         return;
+      }
+   }
+
+   CSteamID steamid;
+   SteamEncryptedAppTicket_GetTicketSteamID( decrypted, ticket_len, &steamid );
+   vg_success( "User is authenticated! steamid %lu (%u)\n", 
+         steamid.m_unAll64Bits, msg->m_conn );
+
+   set_connection_authsteamid( msg->m_conn, steamid.m_unAll64Bits );
+}
+
+static int inet_require_auth( SteamNetworkingMessage_t *msg ){
+   if( gameserver.auth_mode == eServerModeNoAuthentication )
+      return 1;
+
+   if( get_connection_authsteamid( msg ) == k_connection_unauthorized ){
+      vg_warn( "Unauthorized request! Disconnecting client: %u\n", 
+            msg->m_conn );
+
+      SteamAPI_ISteamNetworkingSockets_CloseConnection(
+            hSteamNetworkingSockets,
+            msg->m_conn, 0, NULL, 1 );
+
+      return 0;
+   }
+   else return 1;
+}
+
+static void on_inet_score_request( SteamNetworkingMessage_t *msg ){
+   if( !inet_require_auth(msg) ) return;
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, msg->m_conn, 
+         &scoreboard_client_data, sizeof(netmsg_scoreboard),
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+static void on_inet_set_nickname( SteamNetworkingMessage_t *msg ){
+   if(!inet_require_auth(msg)) return;
+
+   u64_steamid steamid = get_connection_authsteamid(msg);
+   netmsg_set_nickname *setnick = msg->m_pData;
+   if( msg->m_cbSize < sizeof(netmsg_set_nickname) ){
+      vg_warn( "Invalid nickname request from client: %u, steamid: %lu\n", 
+            msg->m_conn, steamid );
+      return;
+   }
+   
+   highscore_set_user_nickname( steamid, setnick->nickname );
+}
+
+static void on_inet_set_score( SteamNetworkingMessage_t *msg ){
+   if(!inet_require_auth(msg)) return;
+
+   u64_steamid steamid = get_connection_authsteamid(msg);
+   
+   if( msg->m_cbSize < sizeof(netmsg_set_score) ){
+      vg_warn( "Invalid set score post from client: %u, steamid: %lu\n",
+            msg->m_conn, steamid );
+      return;
+   }
+
+   netmsg_set_score *info = msg->m_pData;
+
+   if( msg->m_cbSize < sizeof(netmsg_set_score) +
+                       sizeof(struct netmsg_score_record)*info->record_count ){
+      vg_warn( "Malformed set score post from client: %u, steamid: %lu\n",
+            msg->m_conn, steamid );
+      return;
+   }
+
+   for( int i=0; i<info->record_count; i++ ){
+      highscore_record temp;
+      temp.trackid  = info->records[i].trackid;
+      temp.datetime = time(NULL);
+      temp.playerid = steamid;
+      temp.points   = info->records[i].points;
+      temp.time     = info->records[i].time;
+
+      highscores_push_record( &temp );
+   }
+}
+
+static void on_inet_playerframe( SteamNetworkingMessage_t *msg ){
+   if( msg->m_cbSize < sizeof(netmsg_playerframe) ){
+      return;
+   }
+
+
+   netmsg_playerframe *info = msg->m_pData;
+   vg_info( "... @: %.2f %.2f %.2f\n", 
+               //msg->m_identityPeer,
+               info->pos_temp[0], info->pos_temp[1], info->pos_temp[2] );
+}
+
+static void poll_connections(void){
+   SteamNetworkingMessage_t *messages[32];
+   int len;
+
+   while(1){
+      len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
+            hSteamNetworkingSockets,
+            gameserver.client_group, messages, vg_list_size(messages) );
+
+      if( len <= 0 )
+         return;
+
+      for( int i=0; i<len; i++ ){
+         SteamNetworkingMessage_t *msg = messages[i];
+
+         if( msg->m_cbSize < sizeof(netmsg_blank) ){
+            vg_warn( "Discarding message (too small: %d)\n", 
+                  msg->m_cbSize );
+            continue;
+         }
+
+         netmsg_blank *tmp = msg->m_pData;
+
+         if( tmp->inetmsg_id == k_inetmsg_auth )
+            on_inet_auth( msg );
+         else if( tmp->inetmsg_id == k_inetmsg_scores_request )
+            on_inet_score_request( msg );
+         else if( tmp->inetmsg_id == k_inetmsg_set_nickname )
+            on_inet_set_nickname( msg );
+         else if( tmp->inetmsg_id == k_inetmsg_set_score )
+            on_inet_set_score( msg );
+         else if( tmp->inetmsg_id == k_inetmsg_playerframe )
+            on_inet_playerframe( msg );
+         else {
+            vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
+                     tmp->inetmsg_id );
+         }
+
+         SteamAPI_SteamNetworkingMessage_t_Release( msg );
+      }
+   }
+}
+
+static u64 seconds_to_server_ticks( double s ){
+   return s / 0.01;
+}
+
+static void generate_boards(void){
+   FILE *fp = fopen( "www/html/srhighscores.txt", "w" );
+
+   if( !fp ){
+      vg_error( "Can't write boards to www/html/srhighscores.txt\n" );
+      return;
+   }
+
+   for( int i=0; i<vg_list_size(track_infos); i++ ){
+      struct netmsg_board *board = &scoreboard_client_data.boards[i];
+
+      highscores_board_generate( board->data, i, 10 );
+      highscores_board_printf( fp, board->data, 10 );
+   }
+
+   fclose( fp );
+}
+
+int main( int argc, char *argv[] ){
+   signal( SIGINT, inthandler );
+   signal( SIGQUIT, inthandler );
+   signal( SIGPIPE, SIG_IGN );
+
+   char *arg;
+   while( vg_argp( argc, argv ) ){
+      if( vg_long_opt( "noauth" ) )
+         gameserver.auth_mode = eServerModeNoAuthentication;
+   }
+   
+   /* TODO: Options to override, ammend, remove etc */
+
+   vg_set_mem_quota( 80*1024*1024 );
+   vg_alloc_quota();
+
+   highscores_init( 250000, 10000 );
+   
+   if( !highscores_read() )
+      highscores_create_db();
+
+   steamworks_ensure_txt( "2103940" );
+
+   if( gameserver.auth_mode == eServerModeAuthentication ){
+      if( !vg_load_steam_symetric_key( "application_key", 
+                                       gameserver.app_symmetric_key )){
+         return 0;
+      }
+   }
+   else{
+      vg_warn( "Running without user authentication.\n" );
+   }
+
+   if( !SteamGameServer_Init( 0, 27400, 27401, 
+                              gameserver.auth_mode, "1.0.0.0" ) ){
+      vg_error( "SteamGameServer_Init failed\n" );
+      return 0;
+   }
+
+   void *hSteamGameServer = SteamAPI_SteamGameServer();
+   SteamAPI_ISteamGameServer_LogOnAnonymous( hSteamGameServer );
+
+   SteamAPI_ManualDispatch_Init();
+   HSteamPipe hsteampipe = SteamGameServer_GetHSteamPipe();
+
+   //hSteamHTTP = SteamAPI_SteamGameServerHTTP();
+   hSteamNetworkingSockets = 
+      SteamAPI_SteamGameServerNetworkingSockets_SteamAPI();
+
+   /* 
+    * Server code
+    */
+
+   steam_register_callback( k_iSteamNetAuthenticationStatus, on_auth_status );
+   steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
+                             on_connect_status );
+
+   vg_success( "Steamworks API running\n" );
+   steamworks_event_loop( hsteampipe );
+
+   /*
+    * Create a listener
+    */
+
+   HSteamListenSocket listener;
+   SteamNetworkingIPAddr localAddr;
+   SteamAPI_SteamNetworkingIPAddr_Clear( &localAddr );
+   localAddr.m_port = 27402;
+
+   listener = SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
+                  hSteamNetworkingSockets, &localAddr, 0, NULL );
+   gameserver.client_group = SteamAPI_ISteamNetworkingSockets_CreatePollGroup(
+         hSteamNetworkingSockets );
+
+   u64 server_ticks = 8000,
+       last_record_save = 8000,
+       last_scoreboard_gen = 0,
+       last_monitor_heartbeat = 0;
+
+   generate_boards();
+   monitor_start_server();
+
+   while( !sig_stop ){
+      monitor_event_loop();
+      steamworks_event_loop( hsteampipe );
+      poll_connections();
+
+      usleep(10000);
+      server_ticks ++;
+
+      if( server_ticks > 
+            (last_monitor_heartbeat + seconds_to_server_ticks(10.0))){
+         last_monitor_heartbeat = server_ticks;
+         monitor_heartbeat();
+      }
+
+      if( server_ticks > last_scoreboard_gen + seconds_to_server_ticks(60.0) ){
+         last_scoreboard_gen = server_ticks;
+         generate_boards();
+      }
+
+      if( server_ticks > last_record_save + seconds_to_server_ticks(10.0*60.0)){
+         last_record_save = server_ticks;
+         highscores_serialize_all();
+      }
+   }
+   
+   highscores_serialize_all();
+   
+   SteamAPI_ISteamNetworkingSockets_DestroyPollGroup( hSteamNetworkingSockets,
+         gameserver.client_group );
+   SteamAPI_ISteamNetworkingSockets_CloseListenSocket( 
+         hSteamNetworkingSockets, listener );
+   
+   vg_info( "Shutting down\n..." );
+   SteamGameServer_Shutdown();
+
+   return 0;
+}
diff --git a/gameserver.h b/gameserver.h
new file mode 100644 (file)
index 0000000..670a9ba
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef GAMESERVER_H
+#define GAMESERVER_H
+
+#define VG_SERVER
+#include "vg/vg.h"
+#include "vg/vg_steam.h"
+#include "vg/vg_steam_networking.h"
+#include "vg/vg_steam_http.h"
+#include "vg/vg_steam_auth.h"
+#include "network_msg.h"
+#include "highscores.h"
+#include <sys/socket.h>
+
+struct {
+   HSteamNetPollGroup client_group;
+   EServerMode auth_mode;
+
+   u8 app_symmetric_key[ k_nSteamEncryptedAppTicketSymmetricKeyLen ];
+
+   int monitor_fd;
+   int monitor_clients[ 4 ];
+}
+static gameserver = {
+   .auth_mode = eServerModeAuthentication
+};
+
+static ISteamNetworkingSockets *hSteamNetworkingSockets = NULL;
+
+#endif /* GAMESERVER_H */
diff --git a/monitorinfo.h b/monitorinfo.h
new file mode 100644 (file)
index 0000000..7823e9e
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef MONITORINFO_H
+#define MONITORINFO_H
+
+static const char *MONITOR_SOCK_PATH = "\0skaterift.server_monitor";
+
+#endif /* MONITORINFO_H */
diff --git a/network.c b/network.c
new file mode 100644 (file)
index 0000000..ef7dee5
--- /dev/null
+++ b/network.c
@@ -0,0 +1,295 @@
+VG_STATIC void scores_update(void);
+
+VG_STATIC void on_auth_ticket_recieved( void *result, void *context ){
+   EncryptedAppTicketResponse_t *response = result;
+
+   if( response->m_eResult == k_EResultOK ){
+      vg_info( "  New app ticket ready\n" );
+   }
+   else{
+      vg_warn( "  Could not request new encrypted app ticket (%u)\n",
+                  response->m_eResult );
+   }
+   
+   if( SteamAPI_ISteamUser_GetEncryptedAppTicket( hSteamUser, 
+            network_client.app_symmetric_key,
+            vg_list_size(network_client.app_symmetric_key),
+            &network_client.app_key_length )){
+      vg_success( "  Loaded app ticket\n" );
+   }
+   else{
+      vg_error( "  No ticket availible\n" );
+      network_client.app_key_length = 0;
+   }
+}
+
+VG_STATIC void request_auth_ticket(void){
+   /* 
+    * TODO Check for one thats cached on the disk and load it.
+    * This might be OK though because steam seems to cache the result 
+    */
+
+   vg_info( "Requesting new authorization ticket\n" );
+
+   vg_steam_async_call *call = vg_alloc_async_steam_api_call();
+   call->userdata = NULL;
+   call->p_handler = on_auth_ticket_recieved;
+   call->id = 
+      SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, NULL, 0 );
+}
+
+VG_STATIC void send_auth_ticket(void){
+   u32 size = sizeof(netmsg_auth) + network_client.app_key_length;
+   netmsg_auth *auth = alloca(size);
+
+   auth->inetmsg_id = k_inetmsg_auth;
+   auth->ticket_length = network_client.app_key_length;
+   for( int i=0; i<network_client.app_key_length; i++ )
+      auth->ticket[i] = network_client.app_symmetric_key[i];
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, auth, size,
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+VG_STATIC void send_score_request(void){
+   vg_info( "Requesting scores\n" );
+   netmsg_scores_request req;
+   req.inetmsg_id = k_inetmsg_scores_request;
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, 
+         &req, sizeof(netmsg_scores_request),
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+VG_STATIC void send_score_update(void){
+   vg_info( "Sending scores\n" );
+   u32 size = sizeof(netmsg_set_score) + 
+                  vg_list_size(track_infos)*sizeof(struct netmsg_score_record);
+   netmsg_set_score *setscore = alloca( size );
+   setscore->inetmsg_id = k_inetmsg_set_score;
+
+   int count = 0;
+   for( u32 i=0; i<vg_list_size(track_infos); i++ ){
+      if( track_infos[i].push ){
+         track_infos[i].push = 0;
+
+#if 0
+         highscore_record *user_record = highscore_find_user_record( 0, i );
+
+         if( !user_record ){
+            vg_error( "No score set but tried to upload for track %u\n", i );
+            continue;
+         }
+#endif
+         highscore_record *user_record = &track_infos[i].record;
+
+         setscore->records[count].trackid = i;
+         setscore->records[count].playerid = 0;
+         setscore->records[count].points = user_record->points;
+         setscore->records[count].time = user_record->time;
+
+         count ++;
+      }
+   }
+
+   if( count == 0 ) return;
+   u32 send_size = sizeof(netmsg_set_score) +
+                  count*sizeof(struct netmsg_score_record);
+   setscore->record_count = count;
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, setscore, send_size,
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+VG_STATIC void send_nickname(void){
+   netmsg_set_nickname nick;
+   nick.inetmsg_id = k_inetmsg_set_nickname;
+
+   memset( nick.nickname, 0, 16 );
+   vg_strncpy( steam_username_at_startup, nick.nickname, 16,
+               k_strncpy_allow_cutoff );
+   
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, 
+         &nick, sizeof(netmsg_set_nickname),
+         k_nSteamNetworkingSend_Reliable, NULL );
+
+   network_client.name_update = 0;
+}
+
+static void network_send_playerframe(void){
+   netmsg_playerframe frame;
+   frame.inetmsg_id = k_inetmsg_playerframe;
+   v3_copy( localplayer.rb.co, frame.pos_temp );
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, 
+         &frame, sizeof(frame),
+         k_nSteamNetworkingSend_Unreliable, NULL );
+}
+
+VG_STATIC void server_routine_update(void){
+   if( network_client.name_update )
+      send_nickname();
+
+   send_score_update();
+   send_score_request();
+}
+
+VG_STATIC void on_server_connect_status( CallbackMsg_t *msg ){
+   SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
+   vg_info( "  Connection status changed for %lu\n", info->m_hConn );
+   vg_info( "  %s -> %s\n", 
+         string_ESteamNetworkingConnectionState(info->m_eOldState),
+         string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
+
+   if( info->m_hConn == network_client.remote ){
+      network_client.state = info->m_info.m_eState;
+      if( info->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected ){
+         vg_success("  Connected to remote server.. authenticating\n");
+         send_auth_ticket();
+      }
+   }
+   else{
+      vg_warn( "  Recieved signal from unknown connection\n" );
+   }
+}
+
+VG_STATIC void network_connect(void){
+   /* Connect to server if not connected */
+   SteamNetworkingIPAddr remoteAddr;
+
+#ifdef SR_USE_LOCALHOST
+   SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 );
+#else
+   const char *server_lon1 = "46.101.34.155:27402";
+   SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, server_lon1 );
+#endif
+
+   char buf[256];
+   SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
+   vg_info( "connect to: %s\n", buf );
+
+   network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( 
+                  hSteamNetworkingSockets, &remoteAddr, 0, NULL );
+}
+
+VG_STATIC void on_inet_scoreboard( SteamNetworkingMessage_t *msg ){
+   netmsg_scoreboard *sb = msg->m_pData;
+
+   u32 base_size = sizeof(netmsg_scoreboard)-
+      sizeof(struct netmsg_board)*vg_list_size(track_infos),
+       expected = base_size+sizeof(struct netmsg_board)*sb->board_count;
+
+   if( msg->m_cbSize != expected ){
+      vg_error( "Server scoreboard was corrupted. Size: %u != %u\n",
+            msg->m_cbSize, expected );
+   }
+   else{
+      if( vg_list_size(track_infos) > sb->board_count )
+         vg_warn( "Server is out of date, not enough boards recieved\n");
+      else if( vg_list_size(track_infos) < sb->board_count )
+         vg_warn( "Client out of date, server sent more boards than we have\n");
+      else
+         vg_success( "Recieved new scoreboards from server\n" );
+
+      for( int i=0; i < vg_min(sb->board_count,vg_list_size(track_infos)); i++){
+         scoreboard_client_data.boards[i] = sb->boards[i];
+         highscores_board_printf( stdout, sb->boards[i].data, 10 );
+      }
+   }
+
+   /* We dont need to stay on the server currently */
+   SteamAPI_ISteamNetworkingSockets_CloseConnection(
+         hSteamNetworkingSockets, network_client.remote, 0, NULL, 1 );
+
+   network_scores_updated = 1;
+}
+
+VG_STATIC void poll_remote_connection(void){
+   SteamNetworkingMessage_t *messages[32];
+   int len;
+
+   for( int i=0; i<10; i++ ){
+      len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(
+            hSteamNetworkingSockets, network_client.remote, 
+            messages, vg_list_size(messages));
+
+      if( len <= 0 )
+         return;
+
+      for( int i=0; i<len; i++ ){
+         SteamNetworkingMessage_t *msg = messages[i];
+
+         if( msg->m_cbSize < sizeof(netmsg_blank) ){
+            vg_warn( "Discarding message (too small: %d)\n", msg->m_cbSize );
+            continue;
+         }
+
+         netmsg_blank *tmp = msg->m_pData;
+
+         if( tmp->inetmsg_id == k_inetmsg_scoreboard )
+            on_inet_scoreboard( msg );
+
+         SteamAPI_SteamNetworkingMessage_t_Release( msg );
+      }
+   }
+}
+
+VG_STATIC void network_update(void){
+   if( !steam_ready )
+      return;
+
+   ESteamNetworkingConnectionState state = network_client.state;
+
+   if( state == k_ESteamNetworkingConnectionState_Connected ){
+      poll_remote_connection();
+      f64 frame_delta = vg.time_real - network_client.last_frame;
+
+      if( frame_delta > 0.1 ){
+         network_client.last_frame = vg.time_real;
+         network_send_playerframe();
+      }
+   }
+   else {
+      if( (state == k_ESteamNetworkingConnectionState_Connecting) ||
+          (state == k_ESteamNetworkingConnectionState_FindingRoute) ){
+         return;
+      }
+      else {
+         f64 waited = vg.time_real - network_client.last_attempt,
+             min_wait = 1.0;
+
+         if( network_client.retries > 5 )
+            min_wait = 60.0;
+
+         if( waited < min_wait )
+            return;
+         
+         network_connect();
+         network_client.retries ++;
+         network_client.last_attempt = vg.time_real;
+      }
+   }
+}
+
+VG_STATIC void network_init(void){
+   if( steam_ready ){
+      steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
+                               on_server_connect_status );
+      request_auth_ticket();
+   }
+}
+
+VG_STATIC void network_end(void){
+   /* TODO: Send buffered highscores that were not already */
+   if( (network_client.state == k_ESteamNetworkingConnectionState_Connected) ||
+       (network_client.state == k_ESteamNetworkingConnectionState_Connecting) )
+   {
+      SteamAPI_ISteamNetworkingSockets_CloseConnection(
+            hSteamNetworkingSockets, network_client.remote, 0, NULL, 1 );
+   }
+}
index 83564f019f8ecb7347353c840569526f756c8759..6121f0fb8b22a460df51483aa1caf4ca4bb141af 100644 (file)
--- a/network.h
+++ b/network.h
@@ -39,318 +39,24 @@ VG_STATIC void network_submit_highscore( u32 trackid, u16 points, u16 time );
  */
 #ifdef SR_NETWORKED
 
-/* 
- * Runtime connection stuff
- */
-VG_STATIC u8 steam_app_ticket[ 1024 ];
-VG_STATIC u32 steam_app_ticket_length;
-VG_STATIC int network_name_update = 1;
-
-VG_STATIC HSteamNetConnection cremote;
-VG_STATIC ESteamNetworkingConnectionState cremote_state = 
-     k_ESteamNetworkingConnectionState_None;
-
-/* 
- * Implementation
- */
-
-VG_STATIC void scores_update(void);
-
-VG_STATIC void on_auth_ticket_recieved( void *result, void *context )
-{
-   EncryptedAppTicketResponse_t *response = result;
-
-   if( response->m_eResult == k_EResultOK )
-   {
-      vg_info( "  New app ticket ready\n" );
-   }
-   else
-   {
-      vg_warn( "  Could not request new encrypted app ticket (%u)\n",
-                  response->m_eResult );
-   }
+struct {
+   u8 app_symmetric_key[ 1024 ];
+   u32 app_key_length;
+   EServerMode auth_mode;
    
-   if( SteamAPI_ISteamUser_GetEncryptedAppTicket( hSteamUser, 
-            steam_app_ticket,
-            vg_list_size(steam_app_ticket),
-            &steam_app_ticket_length ))
-   {
-      vg_success( "  Loaded app ticket (%u bytes)\n", steam_app_ticket_length );
-   }
-   else
-   {
-      vg_error( "  No ticket availible\n" );
-      steam_app_ticket_length = 0;
-   }
-}
-
-VG_STATIC void request_auth_ticket(void)
-{
-   /* 
-    * TODO Check for one thats cached on the disk and load it.
-    * This might be OK though because steam seems to cache the result 
-    */
-
-   vg_info( "Requesting new authorization ticket\n" );
-
-   vg_steam_async_call *call = vg_alloc_async_steam_api_call();
-   call->userdata = NULL;
-   call->p_handler = on_auth_ticket_recieved;
-   call->id = 
-      SteamAPI_ISteamUser_RequestEncryptedAppTicket( hSteamUser, NULL, 0 );
-}
-
-VG_STATIC void send_auth_ticket(void)
-{
-   u32 size = sizeof(netmsg_auth) + steam_app_ticket_length;
-   netmsg_auth *auth = alloca(size);
-
-   auth->inetmsg_id = k_inetmsg_auth;
-   auth->ticket_length = steam_app_ticket_length; 
-   for( int i=0; i<steam_app_ticket_length; i++ )
-      auth->ticket[i] = steam_app_ticket[i];
-
-   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
-         hSteamNetworkingSockets, cremote, auth, size,
-         k_nSteamNetworkingSend_Reliable, NULL );
-}
-
-VG_STATIC void send_score_request(void)
-{
-   vg_info( "Requesting scores\n" );
-   netmsg_scores_request req;
-   req.inetmsg_id = k_inetmsg_scores_request;
-
-   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
-         hSteamNetworkingSockets, cremote, &req, sizeof(netmsg_scores_request),
-         k_nSteamNetworkingSend_Reliable, NULL );
-}
-
-VG_STATIC void send_score_update(void)
-{
-   vg_info( "Sending scores\n" );
-   u32 size = sizeof(netmsg_set_score) + 
-                  vg_list_size(track_infos)*sizeof(struct netmsg_score_record);
-   netmsg_set_score *setscore = alloca( size );
-   setscore->inetmsg_id = k_inetmsg_set_score;
-
-   int count = 0;
-   for( u32 i=0; i<vg_list_size(track_infos); i++ ){
-      if( track_infos[i].push ){
-         track_infos[i].push = 0;
-
-#if 0
-         highscore_record *user_record = highscore_find_user_record( 0, i );
-
-         if( !user_record ){
-            vg_error( "No score set but tried to upload for track %u\n", i );
-            continue;
-         }
-#endif
-         highscore_record *user_record = &track_infos[i].record;
-
-         setscore->records[count].trackid = i;
-         setscore->records[count].playerid = 0;
-         setscore->records[count].points = user_record->points;
-         setscore->records[count].time = user_record->time;
-
-         count ++;
-      }
-   }
-
-   if( count == 0 ) return;
-   u32 send_size = sizeof(netmsg_set_score) +
-                  count*sizeof(struct netmsg_score_record);
-   setscore->record_count = count;
-
-   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
-         hSteamNetworkingSockets, cremote, setscore, send_size,
-         k_nSteamNetworkingSend_Reliable, NULL );
-}
-
-VG_STATIC void send_nickname(void)
-{
-   netmsg_set_nickname nick;
-   nick.inetmsg_id = k_inetmsg_set_nickname;
-
-   memset( nick.nickname, 0, 16 );
-   vg_strncpy( steam_username_at_startup, nick.nickname, 16,
-               k_strncpy_allow_cutoff );
-   
-   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
-         hSteamNetworkingSockets, cremote, &nick, sizeof(netmsg_set_nickname),
-         k_nSteamNetworkingSend_Reliable, NULL );
-
-   network_name_update = 0;
-}
+   int name_update;
 
-VG_STATIC void server_routine_update(void)
-{
-   send_auth_ticket();
-
-   if( network_name_update )
-      send_nickname();
-
-   send_score_update();
-   send_score_request();
-}
-
-VG_STATIC void on_server_connect_status( CallbackMsg_t *msg )
-{
-   SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
-   vg_info( "  Connection status changed for %lu\n", info->m_hConn );
-   vg_info( "  %s -> %s\n", 
-         string_ESteamNetworkingConnectionState(info->m_eOldState),
-         string_ESteamNetworkingConnectionState(info->m_info.m_eState) );
-
-   if( info->m_hConn == cremote )
-   {
-      cremote_state = info->m_info.m_eState;
-      if( info->m_info.m_eState ==
-            k_ESteamNetworkingConnectionState_Connected )
-      {
-         vg_success("  Connected to remote server.. running updates\n");
-         server_routine_update();
-      }
-   }
-   else
-   {
-      vg_warn( "  Recieved signal from unknown connection\n" );
-   }
-}
-
-VG_STATIC void network_connect_gc(void)
-{
-   /* Connect to server if not connected */
-   SteamNetworkingIPAddr remoteAddr;
-
-#ifdef SR_USE_LOCALHOST
-   SteamAPI_SteamNetworkingIPAddr_SetIPv6LocalHost( &remoteAddr, 27402 );
-#else
-   const char *server_lon1 = "46.101.34.155:27402";
-   SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, server_lon1 );
-#endif
-
-   char buf[256];
-   SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
-   vg_info( "connect to: %s\n", buf );
-
-   cremote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( 
-                  hSteamNetworkingSockets, &remoteAddr, 0, NULL );
-}
-
-VG_STATIC void on_inet_scoreboard( SteamNetworkingMessage_t *msg )
-{
-   netmsg_scoreboard *sb = msg->m_pData;
-
-   u32 base_size = sizeof(netmsg_scoreboard)-
-      sizeof(struct netmsg_board)*vg_list_size(track_infos),
-       expected = base_size+sizeof(struct netmsg_board)*sb->board_count;
-
-   if( msg->m_cbSize != expected ){
-      vg_error( "Server scoreboard was corrupted. Size: %u != %u\n",
-            msg->m_cbSize, expected );
-   }
-   else{
-      if( vg_list_size(track_infos) > sb->board_count )
-         vg_warn( "Server is out of date, not enough boards recieved\n");
-      else if( vg_list_size(track_infos) < sb->board_count )
-         vg_warn( "Client out of date, server sent more boards than we have\n");
-      else
-         vg_success( "Recieved new scoreboards from server\n" );
-
-      for( int i=0; i < vg_min(sb->board_count,vg_list_size(track_infos)); i++){
-         scoreboard_client_data.boards[i] = sb->boards[i];
-         highscores_board_printf( stdout, sb->boards[i].data, 10 );
-      }
-   }
-
-   /* We dont need to stay on the server currently */
-   SteamAPI_ISteamNetworkingSockets_CloseConnection(
-         hSteamNetworkingSockets, cremote, 0, NULL, 1 );
-
-   network_scores_updated = 1;
-}
-
-VG_STATIC void poll_connection(void)
-{
-   SteamNetworkingMessage_t *messages[32];
-   int len;
-
-   while(1){
-      len = SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(
-            hSteamNetworkingSockets, cremote, messages, vg_list_size(messages));
-
-      if( len <= 0 )
-         return;
-
-      for( int i=0; i<len; i++ ){
-         SteamNetworkingMessage_t *msg = messages[i];
-
-         if( msg->m_cbSize < sizeof(netmsg_blank) ){
-            vg_warn( "Discarding message (too small: %d)\n", msg->m_cbSize );
-            continue;
-         }
-
-         netmsg_blank *tmp = msg->m_pData;
-
-         if( tmp->inetmsg_id == k_inetmsg_scoreboard )
-            on_inet_scoreboard( msg );
-
-         SteamAPI_SteamNetworkingMessage_t_Release( msg );
-      }
-   }
-}
-
-/*
- * Subroutine to be connected to main game loop, runs all routines on timers
- */
-VG_STATIC void network_update(void)
-{
-   if( steam_ready ){
-      static double last_update = 0.0;
-      poll_connection();
-      
-      if( vg.time > (last_update + 60.0) ){
-         last_update = vg.time;
-
-         if( steam_app_ticket_length ){
-            network_connect_gc();
-         }
-         else{
-            vg_low( "Not making remote connection; app ticket not gotten\n" );
-         }
-      }
-
-      if( vg.time > (last_update + 10.0) && 
-            (cremote_state == k_ESteamNetworkingConnectionState_Connected ))
-      {
-         vg_warn( "Connected to server but no return... disconnecting\n" );
-         SteamAPI_ISteamNetworkingSockets_CloseConnection(
-               hSteamNetworkingSockets, cremote, 0, NULL, 1 );
-      }
-   }
-}
-
-VG_STATIC void network_init(void)
-{
-   if( steam_ready ){
-      steam_register_callback( k_iSteamNetConnectionStatusChangedCallBack,
-                               on_server_connect_status );
-      request_auth_ticket();
-   }
-}
+   HSteamNetConnection remote;
+   ESteamNetworkingConnectionState state;
 
-VG_STATIC void network_end(void)
-{
-   /* TODO: Fire off any buffered highscores that need to be setn */
-   if( cremote_state == k_ESteamNetworkingConnectionState_Connected ||
-       cremote_state == k_ESteamNetworkingConnectionState_Connecting )
-   {
-      SteamAPI_ISteamNetworkingSockets_CloseConnection(
-            hSteamNetworkingSockets, cremote, 0, NULL, 1 );
-   }
+   f64 last_attempt, last_frame;
+   u32 retries;
 }
+static network_client = {
+   .state = k_ESteamNetworkingConnectionState_None,
+   .auth_mode = eServerModeAuthentication,
+   .name_update = 1
+};
 
 #else /* SR_NETWORKED */
 
index 1df9434a8ca1cb03d91ef7a586192cfbb73fddea..4b36a3e3ca9838df1b52f66e617aaf23fe418a4f 100644 (file)
@@ -81,5 +81,13 @@ VG_STATIC scoreboard_client_data = {
 }; 
 /* probably about 10k */
 
+typedef struct netmsg_playerframe netmsg_playerframe;
+enum{ k_inetmsg_playerframe = 20 };
+struct netmsg_playerframe{
+   u32 inetmsg_id;
+
+   v3f pos_temp;
+};
+
 #pragma pack(pop)
 #endif /* NETWORK_MSG_H */
diff --git a/servermonitor_client.c b/servermonitor_client.c
new file mode 100644 (file)
index 0000000..5c16db1
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef SERVERMONITOR_H
+#define SERVERMONITOR_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef VG_RELEASE
+ #define VG_DEVWINDOW
+#endif
+
+#define VG_3D
+#define VG_GAME
+#define VG_MSG_V1_SUPPORT
+#define VG_LOG_SOURCE_INFO
+#define VG_TIMESTEP_FIXED (1.0/60.0)
+#define VG_NO_STEAM
+#define VG_NO_AUDIO
+#include "vg/vg.h"
+#include "vg/vg_lines.h"
+#include "vg/vg_imgui.h"
+#include "monitorinfo.h"
+
+int main( int argc, char *argv[] ){
+   vg_mem.use_libc_malloc = 0;
+   vg_set_mem_quota( 160*1024*1024 );
+   vg_enter( argc, argv, "Server Monitor" ); 
+   return 0;
+}
+
+VG_STATIC void vg_launch_opt(void){}
+
+static int sockfd = -1;
+
+static void connect_to_monitor_server(void){
+       struct sockaddr_un serv_addr;
+
+       if((sockfd = socket(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0){
+               vg_error("Could not create socket\n");
+      sockfd = -1;
+      return;
+       }
+
+       memset( &serv_addr, 0, sizeof(serv_addr) );
+
+       serv_addr.sun_family = AF_UNIX;
+   strcpy( serv_addr.sun_path, MONITOR_SOCK_PATH );
+
+   vg_info( "Connecting...\n" );
+       if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 ){
+               vg_error("Connect Failed \n");
+      close( sockfd );
+      sockfd = -1;
+      return;
+       }
+
+   vg_success( "Connected\n" );
+}
+
+VG_STATIC void vg_preload(void){}
+
+VG_STATIC void vg_load(void){
+   vg_bake_shaders();
+   vg_console_load_autos();
+}
+
+/* 
+ * UPDATE LOOP
+ * ---------------------------------------------------------------------------*/
+
+VG_STATIC void vg_pre_update(void){
+   if( sockfd == -1 ) return;
+
+       char recvBuff[1024];
+   int len = read(sockfd, recvBuff, sizeof(recvBuff)-1);
+
+   if( len > 0 ){
+      recvBuff[ len ] = 0;
+      vg_info( "%s", recvBuff );
+   }
+}
+
+VG_STATIC void vg_fixed_update(void){
+}
+
+VG_STATIC void vg_post_update(void){
+}
+
+/*
+ * RENDERING
+ * ---------------------------------------------------------------------------*/
+
+VG_STATIC void vg_framebuffer_resize( int w, int h ){
+}
+
+VG_STATIC void vg_render(void){
+   glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+   glViewport( 0,0, vg.window_x, vg.window_y );
+   glDisable( GL_DEPTH_TEST );
+   glDisable( GL_BLEND );
+
+   glClearColor( 0.1f, 0.1f, 0.1f, 1.0f );
+   glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
+
+   vg_lines_drawall();
+}
+
+VG_STATIC void vg_gui(void){
+   vg_ui.wants_mouse = 1;
+   static i32 page = 0;
+   ui_rect panel = { 0, 0, vg.window_x, vg.window_y };
+   ui_rect_pad( panel, (ui_px[]){ 8, 8 } );
+
+   const char *pages[] = { "Status", "Options" };
+   ui_tabs( panel, panel, pages, vg_list_size(pages), &page );
+
+   if( page == 0 ){
+      char buf[512];
+      snprintf( buf, 511, "%sSockfd: %d", (sockfd==-1?KRED:KGRN), sockfd );
+      ui_info( panel, buf );
+
+      if( sockfd == -1 ){
+         if( ui_button( panel, "Reconnect" ) == 1 ){
+            connect_to_monitor_server();
+         }
+      }
+      else{
+         if( ui_button( panel, "Disconnect" ) == 1 ){
+            close( sockfd );
+            sockfd = -1;
+         }
+      }
+   }
+}
+
+#endif /* SERVERMONITOR_H */
diff --git a/servermonitor_server.c b/servermonitor_server.c
new file mode 100644 (file)
index 0000000..7e0e21c
--- /dev/null
@@ -0,0 +1,86 @@
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include "monitorinfo.h"
+#include "gameserver.h"
+
+static int monitor_write_index( int index, const void *buf, size_t nbyte ){
+   int fd = gameserver.monitor_clients[ index ];
+   if( write( fd, buf, nbyte ) == -1 ){
+      gameserver.monitor_clients[ index ] = -1;
+      vg_error( "Monitor client disconnected (%d)\n", index );
+      close( fd );
+      return 0;
+   }
+   else
+      return 1;
+}
+
+static void monitor_accept_connections(void){
+       char sendbuff[1025];
+   int fd = accept( gameserver.monitor_fd, (struct sockaddr*)NULL, NULL );
+
+   if( fd == -1 )
+      return;
+
+   int index = -1;
+   for( int i=0; i<vg_list_size(gameserver.monitor_clients); i ++ ){
+      if( gameserver.monitor_clients[i] == -1 ){
+         index = i;
+         break;
+      }
+   }
+
+   vg_info( "New monitor client (fd: %d, index: %d)\n", fd, index );
+
+   if( index == -1 ){
+      snprintf( sendbuff, sizeof(sendbuff), "MONITOR_FULL\n" );
+      write( fd, sendbuff, strlen(sendbuff) );
+      close( fd );
+      return;
+   }
+
+   gameserver.monitor_clients[ index ] = fd;
+   
+   time_t ticks = time( NULL );
+   snprintf( sendbuff, sizeof(sendbuff), "logged in %.24s\n", ctime(&ticks) );
+   if( monitor_write_index( index, sendbuff, strlen(sendbuff) ) )
+      vg_success( "Accepted\n" );
+}
+
+static void monitor_heartbeat(void){
+   for( int i=0; i<vg_list_size(gameserver.monitor_clients); i++ ){
+      if( gameserver.monitor_clients[i] != -1 )
+         monitor_write_index( i, NULL, 0 );
+   }
+}
+
+static void monitor_start_server(void){
+   for( int i=0; i<vg_list_size(gameserver.monitor_clients); i++ ){
+      gameserver.monitor_clients[i] = -1;
+   }
+
+       struct sockaddr_un serv_addr;
+
+       char sendbuff[1025];
+
+       gameserver.monitor_fd = socket( AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK, 0 );
+       memset( &serv_addr, 0, sizeof(serv_addr) );
+       memset( sendbuff, 0, sizeof(sendbuff) );
+
+       serv_addr.sun_family = AF_UNIX;
+   strcpy( serv_addr.sun_path, MONITOR_SOCK_PATH );
+   
+   unlink( MONITOR_SOCK_PATH );
+       bind( gameserver.monitor_fd, 
+         (struct sockaddr*)&serv_addr, sizeof(serv_addr) );
+       listen( gameserver.monitor_fd, 4 );
+}
+
+static void monitor_event_loop(void){
+   monitor_accept_connections();
+}
index 983ca9ba99c5fddc1b7d112fa7d36b5053ecf259..2e6fca696a9191b32cc022a78b96dfc2eca6df32 100644 (file)
@@ -14,6 +14,7 @@
 #if 1
 
 #define SR_NETWORKED
+#define SR_USE_LOCALHOST
 
 #ifndef VG_RELEASE
  #define VG_DEVWINDOW
@@ -51,6 +52,7 @@
 #include "highscores.c"
 #include "save.c"
 #include "respawn.c"
+#include "network.c"
 
 static struct player_avatar localplayer_avatar;
 
@@ -61,7 +63,11 @@ int main( int argc, char *argv[] ){
    return 0;
 }
 
-VG_STATIC void vg_launch_opt(void){}
+VG_STATIC void vg_launch_opt(void){
+   if( vg_long_opt( "noauth" ) ){
+      network_client.auth_mode = eServerModeNoAuthentication;
+   }
+}
 
 VG_STATIC void vg_preload(void){
    //skaterift_read_savedata();