Example #1
0
// Grab our own input state and send this over the network.
static bool get_self_input_state(netplay_t *handle)
{
   unsigned i;
   struct delta_frame *ptr = &handle->buffer[handle->self_ptr];

   uint32_t state = 0;
   if (handle->frame_count > 0) // First frame we always give zero input since relying on input from first frame screws up when we use -F 0.
   {
      retro_input_state_t cb = handle->cbs.state_cb;
      for (i = 0; i < RARCH_FIRST_META_KEY; i++)
      {
         int16_t tmp = cb(g_settings.input.netplay_client_swap_input ? 0 : !handle->port,
               RETRO_DEVICE_JOYPAD, 0, i);
         state |= tmp ? 1 << i : 0;
      }
   }

   memmove(handle->packet_buffer, handle->packet_buffer + 2,
         sizeof (handle->packet_buffer) - 2 * sizeof(uint32_t));
   handle->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2] = htonl(handle->frame_count); 
   handle->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2 + 1] = htonl(state);

   if (!send_chunk(handle))
   {
      warn_hangup();
      handle->has_connection = false;
      return false;
   }

   ptr->self_state = state;
   handle->self_ptr = NEXT_PTR(handle->self_ptr);
   return true;
}
Example #2
0
static bool send_chunk(netplay_t *netplay)
{
   const struct sockaddr *addr = NULL;

   if (netplay->addr)
      addr = netplay->addr->ai_addr;
   else if (netplay->has_client_addr)
      addr = (const struct sockaddr*)&netplay->their_addr;

   if (addr)
   {
      if (sendto(netplay->udp_fd, (const char*)netplay->packet_buffer,
               sizeof(netplay->packet_buffer), 0, addr,
#ifdef ANDROID
               sizeof(struct sockaddr_in6)
#else
               sizeof(struct sockaddr_in)
#endif
         )
            != sizeof(netplay->packet_buffer))
      {
         warn_hangup();
         netplay->has_connection = false;
         return false;
      }
   }
   return true;
}
Example #3
0
static bool send_chunk(netplay_t *netplay)
{
    const struct sockaddr *addr = NULL;

    if (netplay->addr)
        addr = netplay->addr->ai_addr;
    else if (netplay->has_client_addr)
        addr = (const struct sockaddr*)&netplay->their_addr;

    if (addr)
    {
        ssize_t bytes_sent;

#ifdef HAVE_IPV6
        bytes_sent = (sendto(netplay->udp_fd, (const char*)netplay->packet_buffer,
                             sizeof(netplay->packet_buffer), 0, addr,
                             sizeof(struct sockaddr_in6)));
#else
        bytes_sent = (sendto(netplay->udp_fd, (const char*)netplay->packet_buffer,
                             sizeof(netplay->packet_buffer), 0, addr,
                             sizeof(struct sockaddr_in)));
#endif

        if (bytes_sent != sizeof(netplay->packet_buffer))
        {
            warn_hangup();
            netplay->has_connection = false;
            return false;
        }
    }
    return true;
}
Example #4
0
static int poll_input(netplay_t *netplay, bool block)
{
    int max_fd        = (netplay->fd > netplay->udp_fd ?
                         netplay->fd : netplay->udp_fd) + 1;
    struct timeval tv = {0};
    tv.tv_sec         = 0;
    tv.tv_usec        = block ? (RETRY_MS * 1000) : 0;

    do
    {
        fd_set fds;
        /* select() does not take pointer to const struct timeval.
         * Technically possible for select() to modify tmp_tv, so
         * we go paranoia mode. */
        struct timeval tmp_tv = tv;

        netplay->timeout_cnt++;

        FD_ZERO(&fds);
        FD_SET(netplay->udp_fd, &fds);
        FD_SET(netplay->fd, &fds);

        if (socket_select(max_fd, &fds, NULL, NULL, &tmp_tv) < 0)
            return -1;

        /* Somewhat hacky,
         * but we aren't using the TCP connection for anything useful atm. */
        if (FD_ISSET(netplay->fd, &fds) && !netplay_get_cmd(netplay))
            return -1;

        if (FD_ISSET(netplay->udp_fd, &fds))
            return 1;

        if (!block)
            continue;

        if (!send_chunk(netplay))
        {
            warn_hangup();
            netplay->has_connection = false;
            return -1;
        }

        RARCH_LOG("Network is stalling, resending packet... Count %u of %d ...\n",
                  netplay->timeout_cnt, MAX_RETRIES);
    } while ((netplay->timeout_cnt < MAX_RETRIES) && block);

    if (block)
        return -1;
    return 0;
}
Example #5
0
static int poll_input(netplay_t *handle, bool block)
{
   int max_fd = (handle->fd > handle->udp_fd ? handle->fd : handle->udp_fd) + 1;

   struct timeval tv = {0};
   tv.tv_sec = 0;
   tv.tv_usec = block ? (RETRY_MS * 1000) : 0;

   do
   { 
      handle->timeout_cnt++;

      // select() does not take pointer to const struct timeval.
      // Technically possible for select() to modify tmp_tv, so we go paranoia mode.
      struct timeval tmp_tv = tv;

      fd_set fds;
      FD_ZERO(&fds);
      FD_SET(handle->udp_fd, &fds);
      FD_SET(handle->fd, &fds);

      if (select(max_fd, &fds, NULL, NULL, &tmp_tv) < 0)
         return -1;

      // Somewhat hacky,
      // but we aren't using the TCP connection for anything useful atm.
      if (FD_ISSET(handle->fd, &fds) && !netplay_get_cmd(handle))
         return -1; 

      if (FD_ISSET(handle->udp_fd, &fds))
         return 1;

      if (block && !send_chunk(handle))
      {
         warn_hangup();
         handle->has_connection = false;
         return -1;
      }

      if (block)
      {
         RARCH_LOG("Network is stalling, resending packet... Count %u of %d ...\n",
               handle->timeout_cnt, MAX_RETRIES);
      }
   } while ((handle->timeout_cnt < MAX_RETRIES) && block);

   if (block)
      return -1;
   return 0;
}
Example #6
0
/**
 * get_self_input_state:
 * @netplay              : pointer to netplay object
 *
 * Grab our own input state and send this over the network.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool get_self_input_state(netplay_t *netplay)
{
   uint32_t state          = 0;
   struct delta_frame *ptr = &netplay->buffer[netplay->self_ptr];
   driver_t *driver        = driver_get_ptr();
   settings_t *settings    = config_get_ptr();

   if (!driver->block_libretro_input && netplay->frame_count > 0)
   {
      unsigned i;

      /* First frame we always give zero input since relying on 
       * input from first frame screws up when we use -F 0. */
      retro_input_state_t cb = netplay->cbs.state_cb;
      for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
      {
         int16_t tmp = cb(settings->input.netplay_client_swap_input ?
               0 : !netplay->port,
               RETRO_DEVICE_JOYPAD, 0, i);
         state |= tmp ? 1 << i : 0;
      }

      for (i = RARCH_FIRST_CUSTOM_BIND; i < RARCH_FIRST_META_KEY; i++)
      {
         int16_t tmp = cb(settings->input.netplay_client_swap_input ?
               0 : !netplay->port,
               RETRO_DEVICE_ANALOG, 0, i);
         state |= tmp ? 1 << i : 0;
      }
   }

   memmove(netplay->packet_buffer, netplay->packet_buffer + 2,
         sizeof (netplay->packet_buffer) - 2 * sizeof(uint32_t));
   netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2] = htonl(netplay->frame_count); 
   netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * 2 + 1] = htonl(state);

   if (!send_chunk(netplay))
   {
      warn_hangup();
      netplay->has_connection = false;
      return false;
   }

   ptr->self_state = state;
   netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
   return true;
}
Example #7
0
static bool send_chunk(netplay_t *handle)
{
   const struct sockaddr *addr = NULL;
   if (handle->addr)
      addr = handle->addr->ai_addr;
   else if (handle->has_client_addr)
      addr = (const struct sockaddr*)&handle->their_addr;

   if (addr)
   {
      if (sendto(handle->udp_fd, CONST_CAST handle->packet_buffer,
               sizeof(handle->packet_buffer), 0, addr,
               sizeof(struct sockaddr)) != sizeof(handle->packet_buffer))
      {
         warn_hangup();
         handle->has_connection = false;
         return false;
      }
   }
   return true;
}
Example #8
0
// Poll network to see if we have anything new. If our network buffer is full, we simply have to block for new input data.
static bool netplay_poll(netplay_t *handle)
{
   if (!handle->has_connection)
      return false;

   handle->can_poll = false;

   if (!get_self_input_state(handle))
      return false;

   // We skip reading the first frame so the host has a chance to grab our host info so we don't block forever :')
   if (handle->frame_count == 0)
   {
      handle->buffer[0].used_real = true;
      handle->buffer[0].is_simulated = false;
      handle->buffer[0].real_input_state = 0;
      handle->read_ptr = NEXT_PTR(handle->read_ptr);
      handle->read_frame_count++;
      return true;
   }

   // We might have reached the end of the buffer, where we simply have to block.
   int res = poll_input(handle, handle->other_ptr == handle->self_ptr);
   if (res == -1)
   {
      handle->has_connection = false;
      warn_hangup();
      return false;
   }

   if (res == 1)
   {
      uint32_t first_read = handle->read_frame_count;
      do 
      {
         uint32_t buffer[UDP_FRAME_PACKETS * 2];
         if (!receive_data(handle, buffer, sizeof(buffer)))
         {
            warn_hangup();
            handle->has_connection = false;
            return false;
         }
         parse_packet(handle, buffer, UDP_FRAME_PACKETS);

      } while ((handle->read_frame_count <= handle->frame_count) && 
            poll_input(handle, (handle->other_ptr == handle->self_ptr) && 
               (first_read == handle->read_frame_count)) == 1);
   }
   else
   {
      // Cannot allow this. Should not happen though.
      if (handle->self_ptr == handle->other_ptr)
      {
         warn_hangup();
         return false;
      }
   }

   if (handle->read_ptr != handle->self_ptr)
      simulate_input(handle);
   else
      handle->buffer[PREV_PTR(handle->self_ptr)].used_real = true;

   return true;
}
Example #9
0
/**
 * netplay_poll:
 * @netplay              : pointer to netplay object
 *
 * Polls network to see if we have anything new. If our
 * network buffer is full, we simply have to block
 * for new input data.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool netplay_poll(netplay_t *netplay)
{
    int res;

    if (!netplay->has_connection)
        return false;

    netplay->can_poll = false;

    if (!get_self_input_state(netplay))
        return false;

    /* We skip reading the first frame so the host has a chance to grab
     * our host info so we don't block forever :') */
    if (netplay->frame_count == 0)
    {
        netplay->buffer[0].used_real        = true;
        netplay->buffer[0].is_simulated     = false;

        memset(netplay->buffer[0].real_input_state,
               0, sizeof(netplay->buffer[0].real_input_state));

        netplay->read_ptr                   = NEXT_PTR(netplay->read_ptr);
        netplay->read_frame_count++;
        return true;
    }

    /* We might have reached the end of the buffer, where we
     * simply have to block. */
    res = poll_input(netplay, netplay->other_ptr == netplay->self_ptr);
    if (res == -1)
    {
        netplay->has_connection = false;
        warn_hangup();
        return false;
    }

    if (res == 1)
    {
        uint32_t first_read = netplay->read_frame_count;
        do
        {
            uint32_t buffer[UDP_FRAME_PACKETS * UDP_WORDS_PER_FRAME];
            if (!receive_data(netplay, buffer, sizeof(buffer)))
            {
                warn_hangup();
                netplay->has_connection = false;
                return false;
            }
            parse_packet(netplay, buffer, UDP_FRAME_PACKETS);

        } while ((netplay->read_frame_count <= netplay->frame_count) &&
                 poll_input(netplay, (netplay->other_ptr == netplay->self_ptr) &&
                            (first_read == netplay->read_frame_count)) == 1);
    }
    else
    {
        /* Cannot allow this. Should not happen though. */
        if (netplay->self_ptr == netplay->other_ptr)
        {
            warn_hangup();
            return false;
        }
    }

    if (netplay->read_ptr != netplay->self_ptr)
        simulate_input(netplay);
    else
        netplay->buffer[PREV_PTR(netplay->self_ptr)].used_real = true;

    return true;
}
Example #10
0
static bool netplay_get_cmd(netplay_t *netplay)
{
    uint32_t cmd;
    uint32_t flip_frame;
    size_t cmd_size;

    if (!socket_receive_all_blocking(netplay->fd, &cmd, sizeof(cmd)))
        return false;

    cmd      = ntohl(cmd);

    cmd_size = cmd & 0xffff;
    cmd      = cmd >> 16;

    switch (cmd)
    {
    case NETPLAY_CMD_FLIP_PLAYERS:
        if (cmd_size != sizeof(uint32_t))
        {
            RARCH_ERR("CMD_FLIP_PLAYERS recieved an unexpected command size.\n");
            return netplay_cmd_nak(netplay);
        }

        if (!socket_receive_all_blocking(
                    netplay->fd, &flip_frame, sizeof(flip_frame)))
        {
            RARCH_ERR("Failed to receive CMD_FLIP_PLAYERS argument.\n");
            return netplay_cmd_nak(netplay);
        }

        flip_frame = ntohl(flip_frame);

        if (flip_frame < netplay->flip_frame)
        {
            RARCH_ERR("Host asked us to flip users in the past. Not possible ...\n");
            return netplay_cmd_nak(netplay);
        }

        netplay->flip ^= true;
        netplay->flip_frame = flip_frame;

        RARCH_LOG("Netplay users are flipped.\n");
        runloop_msg_queue_push("Netplay users are flipped.", 1, 180, false);

        return netplay_cmd_ack(netplay);

    case NETPLAY_CMD_SPECTATE:
        RARCH_ERR("NETPLAY_CMD_SPECTATE unimplemented.\n");
        return netplay_cmd_nak(netplay);

    case NETPLAY_CMD_DISCONNECT:
        warn_hangup();
        return netplay_cmd_ack(netplay);

    case NETPLAY_CMD_LOAD_SAVESTATE:
        RARCH_ERR("NETPLAY_CMD_LOAD_SAVESTATE unimplemented.\n");
        return netplay_cmd_nak(netplay);

    case NETPLAY_CMD_PAUSE:
        event_cmd_ctl(EVENT_CMD_PAUSE, NULL);
        return netplay_cmd_ack(netplay);

    case NETPLAY_CMD_RESUME:
        event_cmd_ctl(EVENT_CMD_UNPAUSE, NULL);
        return netplay_cmd_ack(netplay);

    default:
        break;
    }

    RARCH_ERR("Unknown netplay command received.\n");
    return netplay_cmd_nak(netplay);
}
Example #11
0
/**
 * get_self_input_state:
 * @netplay              : pointer to netplay object
 *
 * Grab our own input state and send this over the network.
 *
 * Returns: true (1) if successful, otherwise false (0).
 **/
static bool get_self_input_state(netplay_t *netplay)
{
    uint32_t state[UDP_WORDS_PER_FRAME - 1] = {0};
    struct delta_frame *ptr                 = &netplay->buffer[netplay->self_ptr];
    settings_t *settings                    = config_get_ptr();

    if (!input_driver_ctl(RARCH_INPUT_CTL_IS_LIBRETRO_INPUT_BLOCKED, NULL)
            && netplay->frame_count > 0)
    {
        unsigned i;

        /* First frame we always give zero input since relying on
         * input from first frame screws up when we use -F 0. */
        retro_input_state_t cb = netplay->cbs.state_cb;
        for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++)
        {
            int16_t tmp = cb(settings->input.netplay_client_swap_input ?
                             0 : !netplay->port,
                             RETRO_DEVICE_JOYPAD, 0, i);
            state[0] |= tmp ? 1 << i : 0;
        }

        for (i = 0; i < 2; i++)
        {
            int16_t tmp_x = cb(settings->input.netplay_client_swap_input ?
                               0 : !netplay->port,
                               RETRO_DEVICE_ANALOG, i, 0);
            int16_t tmp_y = cb(settings->input.netplay_client_swap_input ?
                               0 : !netplay->port,
                               RETRO_DEVICE_ANALOG, i, 1);
            state[1 + i] = (uint16_t)tmp_x | (((uint16_t)tmp_y) << 16);
        }
    }

    /* Here we construct the payload format:
     * frame {
     *    uint32_t frame_number
     *    uint32_t RETRO_DEVICE_JOYPAD state (top 16 bits zero)
     *    uint32_t ANALOG state[0]
     *    uint32_t ANALOG state[1]
     * }
     *
     * payload {
     *    ; To compat packet losses, send input in a sliding window
     *    frame redundancy_frames[UDP_FRAME_PACKETS];
     * }
     */
    memmove(netplay->packet_buffer, netplay->packet_buffer + UDP_WORDS_PER_FRAME,
            sizeof (netplay->packet_buffer) - UDP_WORDS_PER_FRAME * sizeof(uint32_t));
    netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * UDP_WORDS_PER_FRAME] = htonl(netplay->frame_count);
    netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * UDP_WORDS_PER_FRAME + 1] = htonl(state[0]);
    netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * UDP_WORDS_PER_FRAME + 2] = htonl(state[1]);
    netplay->packet_buffer[(UDP_FRAME_PACKETS - 1) * UDP_WORDS_PER_FRAME + 3] = htonl(state[2]);

    if (!send_chunk(netplay))
    {
        warn_hangup();
        netplay->has_connection = false;
        return false;
    }

    memcpy(ptr->self_state, state, sizeof(state));
    netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
    return true;
}