Exemple #1
0
/**
 * load_content_into_memory:
 * @path         : buffer of the content file.
 * @buf          : size   of the content file.
 * @length       : size of the content file that has been read from.
 *
 * Read the content file. If read into memory, also performs soft patching
 * (see patch_content function) in case soft patching has not been
 * blocked by the enduser.
 *
 * Returns: true if successful, false on error.
 **/
static bool load_content_into_memory(unsigned i, const char *path, void **buf,
      ssize_t *length)
{
   uint32_t *content_crc_ptr = NULL;
   uint8_t *ret_buf          = NULL;

   RARCH_LOG("%s: %s.\n",
         msg_hash_to_str(MSG_LOADING_CONTENT_FILE), path);
   if (!content_file_read(path, (void**) &ret_buf, length))
      return false;

   if (*length < 0)
      return false;

   if (i == 0)
   {
      /* First content file is significant, attempt to do patching,
       * CRC checking, etc. */

      /* Attempt to apply a patch. */
      if (!rarch_ctl(RARCH_CTL_IS_PATCH_BLOCKED, NULL))
         patch_content(&ret_buf, length);

      content_get_crc(&content_crc_ptr);

      *content_crc_ptr = encoding_crc32(0, ret_buf, *length);

      RARCH_LOG("CRC32: 0x%x .\n", (unsigned)*content_crc_ptr);
   }

   *buf = ret_buf;

   return true;
}
Exemple #2
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;
}
static void netplay_announce(void)
{
   char buf [2048];
   char url [2048]               = "http://newlobby.libretro.com/add/";
   char *username                = NULL;
   char *corename                = NULL;
   char *gamename                = NULL;
   char *coreversion             = NULL;
   char *frontend_ident          = NULL;
   settings_t *settings          = config_get_ptr();
   rarch_system_info_t *system   = runloop_get_system_info();
   uint32_t content_crc          = content_get_crc();
   char frontend_architecture[PATH_MAX_LENGTH];

   netplay_get_architecture(frontend_architecture, sizeof(frontend_architecture));

   net_http_urlencode(&username, settings->paths.username);
   net_http_urlencode(&corename, system->info.library_name);
   net_http_urlencode(&gamename,
      !string_is_empty(path_basename(path_get(RARCH_PATH_BASENAME))) ?
      path_basename(path_get(RARCH_PATH_BASENAME)) : "N/A");
   net_http_urlencode(&coreversion, system->info.library_version);
   net_http_urlencode(&frontend_ident, frontend_architecture);

   buf[0] = '\0';

   snprintf(buf, sizeof(buf), "username=%s&core_name=%s&core_version=%s&"
      "game_name=%s&game_crc=%08X&port=%d&mitm_server=%s"
      "&has_password=%d&has_spectate_password=%d&force_mitm=%d&retroarch_version=%s&frontend=%s",
      username, corename, coreversion, gamename, content_crc,
      settings->uints.netplay_port,
      settings->arrays.netplay_mitm_server,
      *settings->paths.netplay_password ? 1 : 0,
      *settings->paths.netplay_spectate_password ? 1 : 0,
      settings->bools.netplay_use_mitm_server,
      PACKAGE_VERSION, frontend_architecture);
#if 0
   RARCH_LOG("[netplay] announcement URL: %s\n", buf);
#endif
   task_push_http_post_transfer(url, buf, true, NULL, netplay_announce_cb, NULL);

   if (username)
      free(username);
   if (corename)
      free(corename);
   if (gamename)
      free(gamename);
   if (coreversion)
      free(coreversion);
   if (frontend_ident)
      free(frontend_ident);
}
Exemple #4
0
/**
 * read_content_file:
 * @path         : buffer of the content file.
 * @buf          : size   of the content file.
 * @length       : size of the content file that has been read from.
 *
 * Read the content file. If read into memory, also performs soft patching
 * (see patch_content function) in case soft patching has not been
 * blocked by the enduser.
 *
 * Returns: true if successful, false on error.
 **/
static bool read_content_file(unsigned i, const char *path, void **buf,
      ssize_t *length)
{
#ifdef HAVE_ZLIB
   content_stream_t stream_info;
   uint32_t *content_crc_ptr = NULL;
#endif
   uint8_t *ret_buf          = NULL;
   global_t *global          = global_get_ptr();

   RARCH_LOG("%s: %s.\n",
         msg_hash_to_str(MSG_LOADING_CONTENT_FILE), path);
   if (!content_file_read(path, (void**) &ret_buf, length))
      return false;

   if (*length < 0)
      return false;

   if (i != 0)
      return true;

   /* Attempt to apply a patch. */
   if (!global->patch.block_patch)
      patch_content(&ret_buf, length);

#ifdef HAVE_ZLIB
   content_get_crc(&content_crc_ptr);

   stream_info.a = 0;
   stream_info.b = ret_buf;
   stream_info.c = *length;

   if (!stream_backend)
      stream_backend = file_archive_get_default_file_backend();
   stream_info.crc = stream_backend->stream_crc_calculate(
         stream_info.a, stream_info.b, stream_info.c);
   *content_crc_ptr = stream_info.crc;

   RARCH_LOG("CRC32: 0x%x .\n", (unsigned)*content_crc_ptr);
#endif
   *buf = ret_buf;

   return true;
}
Exemple #5
0
bool netplay_bsv_parse_header(const uint32_t *header, uint32_t magic)
{
   retro_ctx_size_info_t info;
   uint32_t *content_crc_ptr;
   uint32_t in_crc, in_magic, in_state_size;
   uint32_t in_bsv = swap_if_little32(header[MAGIC_INDEX]);

   if (in_bsv != BSV_MAGIC)
   {
      RARCH_ERR("BSV magic mismatch, got 0x%x, expected 0x%x.\n",
            in_bsv, BSV_MAGIC);
      return false;
   }

   in_magic = swap_if_big32(header[SERIALIZER_INDEX]);
   if (in_magic != magic)
   {
      RARCH_ERR("Magic mismatch, got 0x%x, expected 0x%x.\n", in_magic, magic);
      return false;
   }

   in_crc = swap_if_big32(header[CRC_INDEX]);

   content_get_crc(&content_crc_ptr);

   if (in_crc != *content_crc_ptr)
   {
      RARCH_ERR("CRC32 mismatch, got 0x%x, expected 0x%x.\n", in_crc,
            *content_crc_ptr);
      return false;
   }

   core_serialize_size(&info);

   in_state_size = swap_if_big32(header[STATE_SIZE_INDEX]);
   if (in_state_size != info.size)
   {
      RARCH_ERR("Serialization size mismatch, got 0x%x, expected 0x%x.\n",
            (unsigned)in_state_size, (unsigned)info.size);
      return false;
   }

   return true;
}
Exemple #6
0
uint32_t *netplay_bsv_header_generate(size_t *size, uint32_t magic)
{
   retro_ctx_serialize_info_t serial_info;
   retro_ctx_size_info_t info;
   uint32_t *content_crc_ptr;
   size_t serialize_size, header_size;
   uint32_t *header, bsv_header[4] = {0};

   core_serialize_size(&info);
   
   serialize_size = info.size;
   header_size    = sizeof(bsv_header) + serialize_size;
   *size          = header_size;
   header         = (uint32_t*)malloc(header_size);
   if (!header)
      goto error;

   content_get_crc(&content_crc_ptr);

   bsv_header[MAGIC_INDEX]      = swap_if_little32(BSV_MAGIC);
   bsv_header[SERIALIZER_INDEX] = swap_if_big32(magic);
   bsv_header[CRC_INDEX]        = swap_if_big32(*content_crc_ptr);
   bsv_header[STATE_SIZE_INDEX] = swap_if_big32(serialize_size);

   serial_info.data             = header + 4;
   serial_info.size             = serialize_size;

   if (serialize_size && !core_serialize(&serial_info))
      goto error;

   memcpy(header, bsv_header, sizeof(bsv_header));
   return header;

error:
   if (header)
      free(header);
   return NULL;
}
/**
 * netplay_lan_ad_server
 *
 * Respond to any LAN ad queries that the netplay server has received.
 */
bool netplay_lan_ad_server(netplay_t *netplay)
{
   fd_set fds;
   struct timeval tmp_tv = {0};
   struct sockaddr their_addr;
   socklen_t addr_size;
   rarch_system_info_t *info = NULL;

   if (lan_ad_server_fd < 0 && !init_lan_ad_server_socket(netplay, RARCH_DEFAULT_PORT))
       return false;

   /* Check for any ad queries */
   while (1)
   {
      FD_ZERO(&fds);
      FD_SET(lan_ad_server_fd, &fds);
      if (socket_select(lan_ad_server_fd + 1, &fds, NULL, NULL, &tmp_tv) <= 0)
         break;
      if (!FD_ISSET(lan_ad_server_fd, &fds))
         break;

      /* Somebody queried, so check that it's valid */
      addr_size = sizeof(their_addr);

      if (recvfrom(lan_ad_server_fd, (char*)&ad_packet_buffer,
            sizeof(struct ad_packet), 0, &their_addr, &addr_size) >=
            (ssize_t) (2*sizeof(uint32_t)))
      {
         char s[NETPLAY_HOST_STR_LEN];
         uint32_t content_crc         = 0;

         /* Make sure it's a valid query */
         if (memcmp((void *) &ad_packet_buffer, "RANQ", 4))
            continue;

         /* For this version */
         if (ntohl(ad_packet_buffer.protocol_version) !=
               NETPLAY_PROTOCOL_VERSION)
            continue;

         info              = runloop_get_system_info();

         /* Now build our response */
         content_crc = content_get_crc();

         memset(&ad_packet_buffer, 0, sizeof(struct ad_packet));
         memcpy(&ad_packet_buffer, "RANS", 4);

         ad_packet_buffer.protocol_version =
            htonl(NETPLAY_PROTOCOL_VERSION);
         ad_packet_buffer.port = htonl(netplay->tcp_port);
         strlcpy(ad_packet_buffer.retroarch_version, PACKAGE_VERSION,
            NETPLAY_HOST_STR_LEN);
         strlcpy(ad_packet_buffer.content, !string_is_empty(
                  path_basename(path_get(RARCH_PATH_BASENAME))) 
               ? path_basename(path_get(RARCH_PATH_BASENAME)) : "N/A",
               NETPLAY_HOST_LONGSTR_LEN);
         strlcpy(ad_packet_buffer.nick, netplay->nick, NETPLAY_HOST_STR_LEN);

         if (info)
         {
            strlcpy(ad_packet_buffer.core, info->info.library_name,
               NETPLAY_HOST_STR_LEN);
            strlcpy(ad_packet_buffer.core_version, info->info.library_version,
               NETPLAY_HOST_STR_LEN);
         }

         snprintf(s, sizeof(s), "%d", content_crc);
         strlcpy(ad_packet_buffer.content_crc, s,
            NETPLAY_HOST_STR_LEN);

         /* And send it */
         sendto(lan_ad_server_fd, (const char*)&ad_packet_buffer,
            sizeof(struct ad_packet), 0, &their_addr, addr_size);
      }
   }

   return true;
}
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;
}
Exemple #9
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;
}