Esempio n. 1
0
bool netplay_send_info(netplay_t *netplay)
{
   unsigned sram_size;
   retro_ctx_memory_info_t mem_info;
   char msg[512]             = {0};
   uint32_t *content_crc_ptr = NULL;
   void *sram                = NULL;
   uint32_t header[3]        = {0};

   mem_info.id = RETRO_MEMORY_SAVE_RAM;

   core_get_memory(&mem_info);
   content_get_crc(&content_crc_ptr);
   
   header[0] = htonl(*content_crc_ptr);
   header[1] = htonl(netplay_impl_magic());
   header[2] = htonl(mem_info.size);

   if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false))
      return false;

   if (!netplay_send_nickname(netplay, netplay->fd))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST));
      return false;
   }

   /* Get SRAM data from User 1. */
   sram      = mem_info.data;
   sram_size = mem_info.size;

   if (!socket_receive_all_blocking(netplay->fd, sram, sram_size))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
      return false;
   }

   if (!netplay_get_nickname(netplay, netplay->fd))
   {
      RARCH_ERR("%s\n", 
            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST));
      return false;
   }

   snprintf(msg, sizeof(msg), "%s: \"%s\"",
         msg_hash_to_str(MSG_CONNECTED_TO),
         netplay->other_nick);
   RARCH_LOG("%s\n", msg);
   runloop_msg_queue_push(msg, 1, 180, false);

   return true;
}
Esempio n. 2
0
bool netplay_handshake(netplay_t *netplay)
{
   size_t i;
   uint32_t local_pmagic, remote_pmagic;
   unsigned sram_size, remote_sram_size;
   retro_ctx_memory_info_t mem_info;
   char msg[512];
   uint32_t *content_crc_ptr = NULL;
   void *sram                = NULL;
   uint32_t header[5]        = {0};
   bool is_server            = netplay->is_server;
   int compression           = 0;

   msg[0] = '\0';

   mem_info.id = RETRO_MEMORY_SAVE_RAM;

   core_get_memory(&mem_info);
   content_get_crc(&content_crc_ptr);

   local_pmagic = netplay_platform_magic();

   header[0] = htonl(*content_crc_ptr);
   header[1] = htonl(netplay_impl_magic());
   header[2] = htonl(mem_info.size);
   header[3] = htonl(local_pmagic);
   header[4] = htonl(NETPLAY_COMPRESSION_SUPPORTED);

   if (!socket_send_all_blocking(netplay->fd, header, sizeof(header), false))
      return false;

   if (!socket_receive_all_blocking(netplay->fd, header, sizeof(header)))
   {
      strlcpy(msg, msg_hash_to_str(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT), sizeof(msg));
      goto error;
   }

   if (*content_crc_ptr != ntohl(header[0]))
   {
      strlcpy(msg, msg_hash_to_str(MSG_CONTENT_CRC32S_DIFFER), sizeof(msg));
      goto error;
   }

   if (netplay_impl_magic() != ntohl(header[1]))
   {
      strlcpy(msg, "Implementations differ. Make sure you're using exact same "
         "libretro implementations and RetroArch version.", sizeof(msg));
      goto error;
   }

   /* Some cores only report the correct sram size late, so we can't actually
    * error out if the sram size seems wrong. */
   sram_size = mem_info.size;
   remote_sram_size = ntohl(header[2]);
   if (sram_size != 0 && remote_sram_size != 0 && sram_size != remote_sram_size)
   {
      RARCH_WARN("Content SRAM sizes do not correspond.\n");
   }

   /* We only care about platform magic if our core is quirky */
   remote_pmagic = ntohl(header[3]);
   if ((netplay->quirks & NETPLAY_QUIRK_ENDIAN_DEPENDENT) &&
       netplay_endian_mismatch(local_pmagic, remote_pmagic))
   {
      RARCH_ERR("Endianness mismatch with an endian-sensitive core.\n");
      strlcpy(msg, "This core does not support inter-architecture netplay "
         "between these systems.", sizeof(msg));
      goto error;
   }
   if ((netplay->quirks & NETPLAY_QUIRK_PLATFORM_DEPENDENT) &&
       (local_pmagic != remote_pmagic))
   {
      RARCH_ERR("Platform mismatch with a platform-sensitive core.\n");
      strlcpy(msg, "This core does not support inter-architecture netplay.",
         sizeof(msg));
      goto error;
   }

   /* Clear any existing compression */
   if (netplay->compression_stream)
      netplay->compression_backend->stream_free(netplay->compression_stream);
   if (netplay->decompression_stream)
      netplay->decompression_backend->stream_free(netplay->decompression_stream);

   /* Check what compression is supported */
   compression = ntohl(header[4]);
   compression &= NETPLAY_COMPRESSION_SUPPORTED;
   if (compression & NETPLAY_COMPRESSION_ZLIB)
   {
      netplay->compression_backend = trans_stream_get_zlib_deflate_backend();
      if (!netplay->compression_backend)
         netplay->compression_backend = trans_stream_get_pipe_backend();
   }
   else
   {
      netplay->compression_backend = trans_stream_get_pipe_backend();
   }
   netplay->decompression_backend = netplay->compression_backend->reverse;

   /* Allocate our compression stream */
   netplay->compression_stream = netplay->compression_backend->stream_new();
   netplay->decompression_stream = netplay->decompression_backend->stream_new();
   if (!netplay->compression_stream || !netplay->decompression_stream)
   {
      RARCH_ERR("Failed to allocate compression transcoder!\n");
      return false;
   }

   /* Client sends nickname first, server replies with nickname */
   if (!is_server)
   {
      if (!netplay_send_nickname(netplay, netplay->fd))
      {
         strlcpy(msg, msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST),
            sizeof(msg));
         goto error;
      }
   }

   if (!netplay_get_nickname(netplay, netplay->fd))
   {
      if (is_server)
         strlcpy(msg, msg_hash_to_str(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT),
            sizeof(msg));
      else
         strlcpy(msg,
            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST),
            sizeof(msg));
      goto error;
   }

   if (is_server)
   {
      if (!netplay_send_nickname(netplay, netplay->fd))
      {
         RARCH_ERR("%s\n",
               msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT));
         return false;
      }
   }

   /* Server sends SRAM, client receives */
   if (is_server)
   {
      /* Send SRAM data to the client */
      sram      = mem_info.data;

      if (!socket_send_all_blocking(netplay->fd, sram, sram_size, false))
      {
         RARCH_ERR("%s\n",
               msg_hash_to_str(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT));
         return false;
      }

   }
   else
   {
      /* Get SRAM data from User 1. */
      if (sram_size != 0 && sram_size == remote_sram_size)
      {
         sram      = mem_info.data;

         if (!socket_receive_all_blocking(netplay->fd, sram, sram_size))
         {
            RARCH_ERR("%s\n",
                  msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
            return false;
         }

      }
      else if (remote_sram_size != 0)
      {
         /* We can't load this, but we still need to get rid of the data */
         uint32_t quickbuf;
         while (remote_sram_size > 0)
         {
            if (!socket_receive_all_blocking(netplay->fd, &quickbuf, (remote_sram_size > sizeof(uint32_t)) ? sizeof(uint32_t) : remote_sram_size))
            {
               RARCH_ERR("%s\n",
                     msg_hash_to_str(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST));
               return false;
            }
            if (remote_sram_size > sizeof(uint32_t))
               remote_sram_size -= sizeof(uint32_t);
            else
               remote_sram_size = 0;
         }

      }

   }

   /* Reset our frame count so it's consistent with the server */
   netplay->self_frame_count = netplay->other_frame_count = 0;
   netplay->read_frame_count = 1;
   for (i = 0; i < netplay->buffer_size; i++)
   {
      netplay->buffer[i].used = false;
      if (i == netplay->self_ptr)
      {
         netplay_delta_frame_ready(netplay, &netplay->buffer[i], 0);
         netplay->buffer[i].have_remote = true;
         netplay->other_ptr = i;
         netplay->read_ptr = NEXT_PTR(i);
      }
      else
      {
         netplay->buffer[i].used = false;
      }
   }

   if (is_server)
   {
      netplay_log_connection(&netplay->other_addr, 0, netplay->other_nick);
   }
   else
   {
      snprintf(msg, sizeof(msg), "%s: \"%s\"",
            msg_hash_to_str(MSG_CONNECTED_TO),
            netplay->other_nick);
      RARCH_LOG("%s\n", msg);
      runloop_msg_queue_push(msg, 1, 180, false);
   }

   return true;

error:
   if (msg[0])
   {
      RARCH_ERR("%s\n", msg);
      runloop_msg_queue_push(msg, 1, 180, false);
   }
   return false;
}
Esempio n. 3
0
bool netplay_get_info(netplay_t *netplay)
{
   unsigned sram_size;
   uint32_t header[3];
   retro_ctx_memory_info_t mem_info;
   uint32_t *content_crc_ptr = NULL;
   const void *sram          = NULL;

   if (!socket_receive_all_blocking(netplay->fd, header, sizeof(header)))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT));
      return false;
   }

   content_get_crc(&content_crc_ptr);

   if (*content_crc_ptr != ntohl(header[0]))
   {
      RARCH_ERR("%s\n", msg_hash_to_str(MSG_CONTENT_CRC32S_DIFFER));
      return false;
   }

   if (netplay_impl_magic() != ntohl(header[1]))
   {
      RARCH_ERR("Implementations differ, make sure you're using exact same "
            "libretro implementations and RetroArch version.\n");
      return false;
   }

   mem_info.id = RETRO_MEMORY_SAVE_RAM;

   core_get_memory(&mem_info);

   if (mem_info.size != ntohl(header[2]))
   {
      RARCH_ERR("Content SRAM sizes do not correspond.\n");
      return false;
   }

   if (!netplay_get_nickname(netplay, netplay->fd))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT));
      return false;
   }

   /* Send SRAM data to our User 2. */
   sram      = mem_info.data;
   sram_size = mem_info.size;

   if (!socket_send_all_blocking(netplay->fd, sram, sram_size, false))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT));
      return false;
   }

   if (!netplay_send_nickname(netplay, netplay->fd))
   {
      RARCH_ERR("%s\n",
            msg_hash_to_str(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT));
      return false;
   }

#ifndef HAVE_SOCKET_LEGACY
   netplay_log_connection(&netplay->other_addr, 0, netplay->other_nick);
#endif

   return true;
}