Do actual domain resolution
[carveJwlIkooP6JGAAIwe30JlM.git] / network.c
index 67fae51e0309ed37d4c6d92324816b6ea7f7506b..4c9c61afd7424fb9e5d9fd66da47cacc3851e390 100644 (file)
--- a/network.c
+++ b/network.c
@@ -1,3 +1,8 @@
+#include "skaterift.h"
+#include "vg/vg_steam.h"
+#include "vg/vg_steam_networking.h"
+#include "vg/vg_steam_auth.h"
+#include "vg/vg_steam_friends.h"
 #include "player.h"
 #include "network.h"
 #include "network_msg.h"
 #include "world_sfd.h"
 #include "world_routes.h"
 #include "vg/vg_imgui.h"
+#include "gui.h"
+#include "ent_region.h"
+#include "vg/vg_loader.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+struct network_client network_client =
+{
+   .auth_mode = eServerModeAuthentication,
+   .state = k_ESteamNetworkingConnectionState_None,
+   .last_intent_change = -99999.9
+};
 
 static void scores_update(void);
 
-static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
+int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
    if( msg->m_cbSize < size ) {
       vg_error( "Invalid packet size (must be at least %u)\n", size );
       return 0;
@@ -77,6 +96,26 @@ static void network_send_username(void){
          k_nSteamNetworkingSend_Reliable, NULL );
 }
 
+void network_send_region(void)
+{
+   if( !network_connected() )
+      return;
+   
+   netmsg_region *region = alloca( sizeof(netmsg_region) + NETWORK_REGION_MAX );
+
+   region->inetmsg_id = k_inetmsg_region;
+   region->client = 0;
+   region->flags = global_ent_region.flags;
+
+   u32 l = vg_strncpy( global_ent_region.location, region->loc, 
+                       NETWORK_REGION_MAX, k_strncpy_always_add_null );
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, 
+         region, sizeof(netmsg_region)+l+1,
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
 static void network_send_request( netmsg_request *req, vg_msg *body,
                                   void (*callback)( 
                                      netmsg_request *res, vg_msg *body, 
@@ -138,9 +177,9 @@ static void network_scoreboard_callback( netmsg_request *res, vg_msg *body,
  *   .
  *   10+ specific week index
  */
-static void network_request_scoreboard( const char *mod_uid, 
-                                        const char *route_uid,
-                                        u32 week, u64 userdata ){
+void network_request_scoreboard( const char *mod_uid, 
+                                 const char *route_uid,
+                                 u32 week, u64 userdata ){
    if( !network_connected() ) 
       return;
 
@@ -152,7 +191,7 @@ static void network_request_scoreboard( const char *mod_uid,
    vg_msg_wkvstr( &data, "endpoint", "scoreboard" );
    vg_msg_wkvstr( &data, "mod", mod_uid );
    vg_msg_wkvstr( &data, "route", route_uid );
-   vg_msg_wkvu32( &data, "week", week );
+   vg_msg_wkvnum( &data, "week", k_vg_msg_u32, 1, &week );
    network_send_request( req, &data, network_scoreboard_callback, userdata );
 }
 
@@ -163,8 +202,8 @@ static void network_publish_callback( netmsg_request *res, vg_msg *body,
    }
 }
 
-static void network_publish_laptime( const char *mod_uid, 
-                                     const char *route_uid, f64 lap_time ){
+void network_publish_laptime( const char *mod_uid, 
+                              const char *route_uid, f64 lap_time ){
    if( !network_connected() )
       return;
 
@@ -178,7 +217,7 @@ static void network_publish_laptime( const char *mod_uid,
    vg_msg_wkvstr( &data, "endpoint", "setlap" );
    vg_msg_wkvstr( &data, "mod", mod_uid );
    vg_msg_wkvstr( &data, "route", route_uid );
-   vg_msg_wkvi32( &data, "time", time_centiseconds );
+   vg_msg_wkvnum( &data, "time", k_vg_msg_i32, 1, &time_centiseconds );
    network_send_request( req, &data, network_publish_callback, 0 );
 }
 
@@ -213,7 +252,8 @@ static void network_request_rx_300_400( SteamNetworkingMessage_t *msg ){
    }
 }
 
-static void network_send_item( enum netmsg_playeritem_type type ){
+void network_send_item( enum netmsg_playeritem_type type )
+{
    if( !network_connected() )
       return;
 
@@ -245,8 +285,6 @@ static void network_send_item( enum netmsg_playeritem_type type ){
          view_id = localplayer.playermodel_view_slot;
          addon_type = k_addon_type_player;
       }
-      else 
-         assert(0);
 
       struct addon_cache *cache = &addon_system.cache[addon_type];
       vg_pool *pool = &cache->pool;
@@ -278,7 +316,13 @@ static void network_disconnect(void){
    }
 }
 
-static void network_status_string( vg_str *str, u32 *colour ){
+void network_status_string( vg_str *str, u32 *colour )
+{
+   if( skaterift.demo_mode ){
+      vg_strcat( str, "Offline" );
+      return;
+   }
+
    if( steam_ready ){
       if( network_client.user_intent == k_server_intent_offline ){
          vg_strcat( str, "Offline" );
@@ -288,8 +332,9 @@ static void network_status_string( vg_str *str, u32 *colour ){
 
          if( state == k_ESteamNetworkingConnectionState_None )
             vg_strcat( str, "No Connection" );
-         else if( state == k_ESteamNetworkingConnectionState_Connecting ){
-            vg_strcat( str, "Connecting to:\nskaterift.com" );
+         else if( state == k_ESteamNetworkingConnectionState_Connecting )
+         {
+            vg_strcatf( str, "Connecting...\n%s", network_client.host_adress );
 
             if( network_client.retries ){
                vg_strcat( str, "\n(" );
@@ -298,7 +343,7 @@ static void network_status_string( vg_str *str, u32 *colour ){
             }
          }
          else if( state == k_ESteamNetworkingConnectionState_Connected ){
-            vg_strcat( str, "Connected to:\nskaterift.com" );
+            vg_strcatf( str, "Connected to:\n%s", network_client.host_adress );
             *colour = 0xff00a020;
          }
          else if( state == k_ESteamNetworkingConnectionState_ClosedByPeer )
@@ -320,7 +365,8 @@ static void network_status_string( vg_str *str, u32 *colour ){
    }
 }
 
-static void render_server_status_gui(void){
+void render_server_status_gui(void)
+{
    render_fb_bind( gpipeline.fb_workshop_preview, 0 );
 
    /* HACK */
@@ -428,26 +474,37 @@ static void on_persona_state_change( CallbackMsg_t *msg ){
    }
 }
 
-static void network_connect(void){
-   char ip_buf[128];
-   vg_str str;
-   vg_strnull( &str, ip_buf, sizeof(ip_buf) );
-   vg_strcat( &str, network_client.server_adress );
-   vg_strcat( &str, ":" );
-   vg_strcati32( &str, NETWORK_PORT );
+void network_set_host( const char *host_str, const char *port_str )
+{
+   vg_strncpy( host_str, network_client.host_adress, 
+               sizeof(network_client.host_adress), k_strncpy_overflow_fatal );
 
-   if( !vg_strgood(&str) ) return;
+   memset( &network_client.ip, 0, sizeof(network_client.ip) );
+   network_client.ip_resolved = 0;
+
+   if( port_str )
+   {
+      vg_strncpy( port_str, network_client.host_port, 
+                  sizeof(network_client.host_port), k_strncpy_overflow_fatal );
+   }
+   else
+   {
+      vg_str str;
+      vg_strnull( &str, network_client.host_port, 
+                  sizeof(network_client.host_port) );
+      vg_strcati32( &str, NETWORK_PORT );
+   }
 
-   /* Connect to server if not connected */
-   SteamNetworkingIPAddr remoteAddr;
-   SteamAPI_SteamNetworkingIPAddr_ParseString( &remoteAddr, str.buffer );
+   network_client.ip.m_port = atoi( network_client.host_port );
+}
 
-   char buf[256];
-   SteamAPI_SteamNetworkingIPAddr_ToString( &remoteAddr, buf, 256, 1 );
-   vg_info( "connect to: %s\n", buf );
+static void network_connect(void)
+{
+   VG_ASSERT( network_client.ip_resolved );
 
+   vg_info( "connecting...\n" );
    network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress( 
-                  hSteamNetworkingSockets, &remoteAddr, 0, NULL );
+                  hSteamNetworkingSockets, &network_client.ip, 0, NULL );
 }
 
 static void network_sign_on_complete(void){
@@ -458,6 +515,7 @@ static void network_sign_on_complete(void){
    for( u32 i=0; i<k_netmsg_playeritem_max; i ++ ){
       network_send_item(i);
    }
+   network_send_region();
 }
 
 static void poll_remote_connection(void){
@@ -510,37 +568,102 @@ static void poll_remote_connection(void){
    }
 }
 
-static void network_update(void){
+static void network_resolve_host_async( void *payload, u32 size )
+{
+   u32 *status = payload;
+   network_client.ip_resolved = *status;
+
+   char buf[256];
+   SteamAPI_SteamNetworkingIPAddr_ToString( &network_client.ip, buf, 256, 1 );
+   vg_info( "Resolved host address to: %s\n", buf );
+}
+
+static void network_resolve_host_thread( void *_ )
+{
+   vg_async_item *call = vg_async_alloc(8);
+   u32 *status = call->payload;
+   *status = 0;
+
+   if( (network_client.host_adress[0] >= '0') && 
+       (network_client.host_adress[0] <= '9') )
+   {
+      SteamAPI_SteamNetworkingIPAddr_ParseString( 
+            &network_client.ip, 
+            network_client.host_adress );
+      network_client.ip.m_port = atoi( network_client.host_port );
+      *status = 1;
+      goto end;
+   }
+
+   vg_info( "Resolving host.. %s (:%s)\n",
+             network_client.host_adress, network_client.host_port );
+
+   struct addrinfo  hints;
+   struct addrinfo  *result;
+
+   /* Obtain address(es) matching host/port. */
+
+   memset( &hints, 0, sizeof(hints) );
+   hints.ai_family = AF_INET6;
+   hints.ai_socktype = SOCK_DGRAM;
+   hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+   hints.ai_protocol = 0;
+
+   int s = getaddrinfo( network_client.host_adress, network_client.host_port, 
+                        &hints, &result);
+   if( s != 0 ) 
+   {
+      vg_error( "getaddrinfo: %s\n", gai_strerror(s) );
+      goto end;
+   }
+
+   struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)result->ai_addr;
+   memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 );
+   freeaddrinfo( result );
+
+   *status = 1;
+
+end: vg_async_dispatch( call, network_resolve_host_async );
+}
+
+void network_update(void)
+{
    if( !steam_ready )
       return;
 
    ESteamNetworkingConnectionState state = network_client.state;
 
-   if( network_client.user_intent == k_server_intent_offline ){
+   if( network_client.user_intent == k_server_intent_offline )
+   {
       if( state != k_ESteamNetworkingConnectionState_None )
          network_disconnect();
 
       return;
    }
 
-   if( state == k_ESteamNetworkingConnectionState_Connected ){
+   if( state == k_ESteamNetworkingConnectionState_Connected )
+   {
       poll_remote_connection();
       f64 frame_delta = vg.time_real - network_client.last_frame;
 
-      if( frame_delta > NETWORK_FRAMERATE ){
+      if( frame_delta > NETWORK_FRAMERATE )
+      {
          network_client.last_frame = vg.time_real;
          remote_player_send_playerframe();
-         player__clear_sfx_buffer();
+         localplayer.sfx_buffer_count = 0;
       }
 
       remote_player_debug_update();
    }
-   else {
+   else 
+   {
       if( (state == k_ESteamNetworkingConnectionState_Connecting) ||
-          (state == k_ESteamNetworkingConnectionState_FindingRoute) ){
+          (state == k_ESteamNetworkingConnectionState_FindingRoute) )
+      {
          return;
       }
-      else {
+      else 
+      {
          f64 waited = vg.time_real - network_client.last_attempt,
              min_wait = 1.0;
 
@@ -549,15 +672,26 @@ static void network_update(void){
 
          if( waited < min_wait )
             return;
+
+         if( !network_client.ip_resolved )
+         {
+            if( vg_loader_availible() )
+            {
+               vg_loader_start( network_resolve_host_thread, NULL );
+            }
+            else return;
+         }
+         else
+            network_connect();
          
-         network_connect();
          network_client.retries ++;
          network_client.last_attempt = vg.time_real;
       }
    }
 }
 
-static void chat_send_message( const char *message ){
+void chat_send_message( const char *message )
+{
    if( !network_connected() ){
       return;
    }
@@ -591,9 +725,12 @@ static int cmd_network_send_message( int argc, const char *argv[] ){
    return 0;
 }
 
-static void network_init(void){
+void network_init(void)
+{
    vg_console_reg_var( "network_info", &network_client.network_info,
                        k_var_dtype_i32, VG_VAR_PERSISTENT );
+   vg_console_reg_var( "auto_connect", &network_client.auto_connect,
+                       k_var_dtype_i32, VG_VAR_PERSISTENT );
    if( steam_ready ){
       u32 alloc_size = sizeof(struct network_request)*NETWORK_MAX_REQUESTS;
       network_client.request_buffer = 
@@ -617,7 +754,8 @@ static void network_init(void){
    }
 }
 
-static void network_end(void){
+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) )