Example #1
0
// TODO: Somewhat better prediction. :P
static void simulate_input(netplay_t *handle)
{
   size_t ptr = PREV_PTR(handle->self_ptr);
   size_t prev = PREV_PTR(handle->read_ptr);

   handle->buffer[ptr].simulated_input_state = handle->buffer[prev].real_input_state;
   handle->buffer[ptr].is_simulated = true;
   handle->buffer[ptr].used_real = false;
}
Example #2
0
/**
 * Removes this block from the list of
 * free blocks.
 * @param - bp - pointer to a block that is on the list of free blocks.
 */
static void mm_remove(void *bp){
	/* if prev bp, then set it's next to bp next */
	if (PREV_PTR(bp)){ 
		SET_NEXT(PREV_PTR(bp), NEXT_PTR(bp));
	}
	else{	/* set listp to bp's next */
		listp = NEXT_PTR(bp);
	}		
	/* set prev of next after bp to prev of bp */
	SET_PREV(NEXT_PTR(bp), PREV_PTR(bp));
}
Example #3
0
/* TODO: Somewhat better prediction. :P */
static void simulate_input(netplay_t *netplay)
{
    size_t ptr  = PREV_PTR(netplay->self_ptr);
    size_t prev = PREV_PTR(netplay->read_ptr);

    memcpy(netplay->buffer[ptr].simulated_input_state,
           netplay->buffer[prev].real_input_state,
           sizeof(netplay->buffer[prev].real_input_state));

    netplay->buffer[ptr].is_simulated = true;
    netplay->buffer[ptr].used_real = false;
}
Example #4
0
/**
 * netplay_simulate_input:
 * @netplay             : pointer to netplay object
 * @sim_ptr             : frame index for which to simulate input
 *
 * "Simulate" input by assuming it hasn't changed since the last read input.
 */
void netplay_simulate_input(netplay_t *netplay, uint32_t sim_ptr)
{
   size_t prev = PREV_PTR(netplay->read_ptr);
   memcpy(netplay->buffer[sim_ptr].simulated_input_state,
         netplay->buffer[prev].real_input_state,
         sizeof(netplay->buffer[prev].real_input_state));
}
Example #5
0
static int16_t netplay_input_state(netplay_t *netplay,
                                   bool port, unsigned device,
                                   unsigned idx, unsigned id)
{
    size_t ptr = netplay->is_replay ?
                 netplay->tmp_ptr : PREV_PTR(netplay->self_ptr);

    const uint32_t *curr_input_state = netplay->buffer[ptr].self_state;

    if (netplay->port == (netplay_flip_port(netplay, port) ? 1 : 0))
    {
        if (netplay->buffer[ptr].is_simulated)
            curr_input_state = netplay->buffer[ptr].simulated_input_state;
        else
            curr_input_state = netplay->buffer[ptr].real_input_state;
    }

    switch (device)
    {
    case RETRO_DEVICE_JOYPAD:
        return ((1 << id) & curr_input_state[0]) ? 1 : 0;

    case RETRO_DEVICE_ANALOG:
    {
        uint32_t state = curr_input_state[1 + idx];
        return (int16_t)(uint16_t)(state >> (id * 16));
    }

    default:
        return 0;
    }
}
Example #6
0
static void del(void *bp){

	/* if previous bp exists, then we link it to next to bp next */

	if (PREV_PTR(bp))

		NEXT_PTR(PREV_PTR(bp))=NEXT_PTR(bp);

	else	/* else our new top will be next of bp, if we are deleting our top */

		lptr = NEXT_PTR(bp);

	/*  relinking */

	PREV_PTR(NEXT_PTR(bp))=PREV_PTR(bp);

}
Example #7
0
static void insert(void *bp){

	/* linking bp to our stack top */

	NEXT_PTR(bp)=lptr;

	/* previous of our stack top will be our bp */

	PREV_PTR(lptr)=bp;

	/* prev bp will be NULL  because it is our new top */

	PREV_PTR(bp)=NULL;

	/* now we need to save our new top */

	lptr = bp;

}
Example #8
0
/* put header, footer and free_list pointers in a free block */
void free_ptr(void *ptr, void *prev, void *next, unsigned size)
{
    unsigned header = PACK(size, 0);
    // header
    PUT_INT(HDRP(ptr), header);
    // footer
    PUT_INT(FTRP(ptr), header);
    // prev and next
    PUT(PREV_PTR(ptr), prev);
    PUT(NEXT_PTR(ptr), next);
}
Example #9
0
/*
 * mm_init - initialize the malloc package.
 *
 * Allocates free_list next and prev pointers as a circular linked list.
 * Creates an "allocated" footer to prevent coalescing at the start of the
 * heap.
 */
int mm_init(void)
{
    // for free_list head and tail
    mem_sbrk(2 * DSIZE);
    // set head and tail to point to free_list
    PUT(PREV_PTR(free_list), free_list);
    PUT(NEXT_PTR(free_list), free_list);
    // ensure there is space for an extra double word before the heap begins
    void *heap_start = mem_sbrk(DSIZE);
    // set allocation before the first block
    PUT_INT(heap_start, 1);
    return 0;
}
Example #10
0
/**
 * netplay_simulate_input
 * @netplay             : pointer to netplay object
 * @sim_ptr             : frame index for which to simulate input
 * @resim               : are we resimulating, or simulating this frame for the
 *                        first time?
 *
 * "Simulate" input by assuming it hasn't changed since the last read input.
 */
void netplay_simulate_input(netplay_t *netplay, size_t sim_ptr, bool resim)
{
   uint32_t player;
   size_t prev;
   struct delta_frame *simframe, *pframe;

   simframe = &netplay->buffer[sim_ptr];

   for (player = 0; player < MAX_USERS; player++)
   {
      if (!(netplay->connected_players & (1<<player))) continue;
      if (simframe->have_real[player]) continue;

      prev = PREV_PTR(netplay->read_ptr[player]);
      pframe = &netplay->buffer[prev];

      if (resim)
      {
         /* In resimulation mode, we only copy the buttons. The reason for this
          * is nonobvious:
          *
          * If we resimulated nothing, then the /duration/ with which any input
          * was pressed would be approximately correct, since the original
          * simulation came in as the input came in, but the /number of times/
          * the input was pressed would be wrong, as there would be an
          * advancing wavefront of real data overtaking the simulated data
          * (which is really just real data offset by some frames).
          *
          * That's acceptable for arrows in most situations, since the amount
          * you move is tied to the duration, but unacceptable for buttons,
          * which will seem to jerkily be pressed numerous times with those
          * wavefronts.
          */
         const uint32_t keep = (1U<<RETRO_DEVICE_ID_JOYPAD_UP) |
                               (1U<<RETRO_DEVICE_ID_JOYPAD_DOWN) |
                               (1U<<RETRO_DEVICE_ID_JOYPAD_LEFT) |
                               (1U<<RETRO_DEVICE_ID_JOYPAD_RIGHT);
         uint32_t sim_state = simframe->simulated_input_state[player][0] & keep;
         sim_state |= pframe->real_input_state[player][0] & ~keep;
         simframe->simulated_input_state[player][0] = sim_state;
      }
      else
      {
         memcpy(simframe->simulated_input_state[player],
                pframe->real_input_state[player],
                WORDS_PER_INPUT * sizeof(uint32_t));
      }
   }
}
Example #11
0
static int16_t netplay_input_state(netplay_t *netplay, bool port, unsigned device,
      unsigned idx, unsigned id)
{
   size_t ptr = netplay->is_replay ? 
      netplay->tmp_ptr : PREV_PTR(netplay->self_ptr);
   uint16_t curr_input_state = netplay->buffer[ptr].self_state;

   if (netplay->port == (netplay_flip_port(netplay, port) ? 1 : 0))
   {
      if (netplay->buffer[ptr].is_simulated)
         curr_input_state = netplay->buffer[ptr].simulated_input_state;
      else
         curr_input_state = netplay->buffer[ptr].real_input_state;
   }

   return ((1 << id) & curr_input_state) ? 1 : 0;
}
Example #12
0
int16_t netplay_input_state(netplay_t *handle, bool port, unsigned device, unsigned index, unsigned id)
{
   uint16_t input_state = 0;
   size_t ptr = handle->is_replay ? handle->tmp_ptr : PREV_PTR(handle->self_ptr);

   port = netplay_flip_port(handle, port);

   if ((port ? 1 : 0) == handle->port)
   {
      if (handle->buffer[ptr].is_simulated)
         input_state = handle->buffer[ptr].simulated_input_state;
      else
         input_state = handle->buffer[ptr].real_input_state;
   }
   else
      input_state = handle->buffer[ptr].self_state;

   return ((1 << id) & input_state) ? 1 : 0;
}
Example #13
0
/**
 * Prints the block payload which 
 * bp is pointing to.
 * @param bp - pointer to block
 */ 
static void printBlock(void *bp){
	size_t hsize = GET_HSIZE(bp);
	size_t halloc = GET_HALLOC(bp);
	size_t fsize = GET_HSIZE(bp);
	size_t falloc = GET_HALLOC(bp);

	if (hsize == 0) 
	{
		printf("%p: EOL\n", bp);
		return;
	}
	if (halloc)
		printf("%p: header:[%d:%c] footer:[%d:%c]\n", bp,
			hsize, (halloc ? 'a' : 'f'),
			fsize, (falloc ? 'a' : 'f'));
	else
		printf("%p:header:[%d:%c] prev:%p next:%p footer:[%d:%c]\n",
			bp, hsize, (halloc ? 'a' : 'f'), 
			PREV_PTR(bp),
			NEXT_PTR(bp), 
			fsize, (falloc ? 'a' : 'f'));
}
Example #14
0
/**
 * netplay_net_post_frame:
 * @netplay              : pointer to netplay object
 *
 * Post-frame for Netplay (normal version).
 * We check if we have new input and replay from recorded input.
 **/
static void netplay_net_post_frame(netplay_t *netplay)
{
   netplay->self_ptr = NEXT_PTR(netplay->self_ptr);
   netplay->self_frame_count++;

   /* Only relevant if we're connected */
   if (!netplay->has_connection)
   {
      netplay->read_frame_count = netplay->other_frame_count = netplay->self_frame_count;
      netplay->read_ptr = netplay->other_ptr = netplay->self_ptr;
      return;
   }

#ifndef DEBUG_NONDETERMINISTIC_CORES
   if (!netplay->force_rewind)
   {
      /* Skip ahead if we predicted correctly.
       * Skip until our simulation failed. */
      while (netplay->other_frame_count < netplay->read_frame_count &&
            netplay->other_frame_count < netplay->self_frame_count)
      {
         struct delta_frame *ptr = &netplay->buffer[netplay->other_ptr];

         if (memcmp(ptr->simulated_input_state, ptr->real_input_state,
                  sizeof(ptr->real_input_state)) != 0
               && !ptr->used_real)
            break;
         netplay_handle_frame_hash(netplay, ptr);
         netplay->other_ptr = NEXT_PTR(netplay->other_ptr);
         netplay->other_frame_count++;
      }
   }
#endif

   /* Now replay the real input if we've gotten ahead of it */
   if (netplay->force_rewind ||
       (netplay->other_frame_count < netplay->read_frame_count &&
        netplay->other_frame_count < netplay->self_frame_count))
   {
      retro_ctx_serialize_info_t serial_info;

      /* Replay frames. */
      netplay->is_replay = true;
      netplay->replay_ptr = netplay->other_ptr;
      netplay->replay_frame_count = netplay->other_frame_count;

      if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
         /* Make sure we're initialized before we start loading things */
         netplay_wait_and_init_serialization(netplay);

      serial_info.data       = NULL;
      serial_info.data_const = netplay->buffer[netplay->replay_ptr].state;
      serial_info.size       = netplay->state_size;

      if (!core_unserialize(&serial_info))
      {
         RARCH_ERR("Netplay savestate loading failed: Prepare for desync!\n");
      }

      while (netplay->replay_frame_count < netplay->self_frame_count)
      {
         struct delta_frame *ptr = &netplay->buffer[netplay->replay_ptr];
         serial_info.data       = ptr->state;
         serial_info.size       = netplay->state_size;
         serial_info.data_const = NULL;

         /* Remember the current state */
         memset(serial_info.data, 0, serial_info.size);
         core_serialize(&serial_info);
         if (netplay->replay_frame_count < netplay->read_frame_count)
            netplay_handle_frame_hash(netplay, ptr);

         /* Simulate this frame's input */
         if (netplay->replay_frame_count >= netplay->read_frame_count)
            netplay_simulate_input(netplay, netplay->replay_ptr);

         autosave_lock();
         core_run();
         autosave_unlock();
         netplay->replay_ptr = NEXT_PTR(netplay->replay_ptr);
         netplay->replay_frame_count++;

#ifdef DEBUG_NONDETERMINISTIC_CORES
         if (ptr->have_remote && netplay_delta_frame_ready(netplay, &netplay->buffer[netplay->replay_ptr], netplay->replay_frame_count))
         {
            RARCH_LOG("PRE  %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr));
            if (netplay->is_server)
               RARCH_LOG("INP  %X %X\n", ptr->real_input_state[0], ptr->self_state[0]);
            else
               RARCH_LOG("INP  %X %X\n", ptr->self_state[0], ptr->real_input_state[0]);
            ptr = &netplay->buffer[netplay->replay_ptr];
            serial_info.data = ptr->state;
            memset(serial_info.data, 0, serial_info.size);
            core_serialize(&serial_info);
            RARCH_LOG("POST %u: %X\n", netplay->replay_frame_count-1, netplay_delta_frame_crc(netplay, ptr));
         }
#endif
      }

      if (netplay->read_frame_count < netplay->self_frame_count)
      {
         netplay->other_ptr = netplay->read_ptr;
         netplay->other_frame_count = netplay->read_frame_count;
      }
      else
      {
         netplay->other_ptr = netplay->self_ptr;
         netplay->other_frame_count = netplay->self_frame_count;
      }
      netplay->is_replay = false;
      netplay->force_rewind = false;
   }

   /* If we're supposed to stall, rewind (we shouldn't get this far if we're
    * stalled, so this is a last resort) */
   if (netplay->stall)
   {
      retro_ctx_serialize_info_t serial_info;

      netplay->self_ptr = PREV_PTR(netplay->self_ptr);
      netplay->self_frame_count--;

      serial_info.data       = NULL;
      serial_info.data_const = netplay->buffer[netplay->self_ptr].state;
      serial_info.size       = netplay->state_size;

      core_unserialize(&serial_info);
   }
}
Example #15
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 #16
0
/*
 * mm_malloc - Allocate as an explicit free list.
 *
 * This is done using a first fit policy on the minimum size of the block.
 * The first fitting block may be split up into a smaller free block and an
 * allocated free block to fit the block requested by malloc. The free block
 * will precede the allocated block to prevent the need to move pointers.
 *
 * If the block does not fit, a new allocated block is created, which may
 * round the block size up to the nearest power of 2. An "allocated" block is
 * created at the end to prevent coalescing past the heap end.
 */
void *mm_malloc(size_t size)
{
    // use malloc_size or fit_size
    unsigned newsize = fit_size(size);
    // finger = free_list->next
    size_t *finger = (size_t *)GET(NEXT_PTR(free_list));
    size_t *p = (size_t *)free_list;
    unsigned fitSize = ~0;
    // iterate linked list
    while (finger != free_list) {
      unsigned blkSize = GET_SIZE(HDRP(finger));
      // look for best fit, exit early if perfect fit
      if (blkSize == newsize) {
        p = finger;
        break;
      }
      // remember best fit
      if (blkSize > newsize && blkSize < fitSize) {
        p = finger;
        fitSize = blkSize;
      }
      // finger = finger->next
      finger = (size_t *)GET(NEXT_PTR(finger));
    }
    // if block doesn't fit in any free block, allocate more heap space
    if (p == free_list) {
      // round up with malloc_size
      newsize = malloc_size(size);
      // if block before end of heap is a free block, coalesce
      void *prevPtr = PREV_BLKP(ADD_PTR(mem_heap_hi(), 1));
      if (prevPtr < mem_heap_hi() && !GET_ALLOC(HDRP(prevPtr))) {
        // calculate new size to sbrk
        unsigned allocSize = newsize - GET_SIZE(HDRP(prevPtr));
        p = mem_sbrk(allocSize);
        if ((int)(p) == -1)
          return NULL;

        // prevPtr->prev->next = prevPtr->next;
        PUT(NEXT_PTR(GET(PREV_PTR(prevPtr))), GET(NEXT_PTR(prevPtr)));
        // prevPtr->next->prev = prevPtr->prev;
        PUT(PREV_PTR(GET(NEXT_PTR(prevPtr))), GET(PREV_PTR(prevPtr)));
        // allocate prevPtr to new size
        alloc_ptr(prevPtr, newsize);

        // set allocation before the last block
        PUT_INT(HDRP(NEXT_BLKP(prevPtr)), 1);

        return prevPtr;
      }
      p = mem_sbrk(newsize);
      if ((int)(p) == -1)
        return NULL;

      alloc_ptr(p, newsize);

      // set allocation before the last block
      PUT_INT(HDRP(NEXT_BLKP(p)), 1);
      
      return p;
    }
    unsigned freeSize = GET_SIZE(HDRP(p));
    if (freeSize - newsize >= FREE_OVERHEAD) {
      // split free block into free and allocated blocks

      unsigned header = freeSize - newsize;
      // header
      PUT_INT(HDRP(p), header);
      // footer
      PUT_INT(FTRP(p), header);
      p = ADD_PTR(p, freeSize - newsize);
    } else {
      // allocate the whole free block
      newsize = freeSize;
      // p->prev->next = p->next
      PUT(NEXT_PTR(GET(PREV_PTR(p))), GET(NEXT_PTR(p)));
      // p->next->prev = p->prev
      PUT(PREV_PTR(GET(NEXT_PTR(p))), GET(PREV_PTR(p)));
    }
    // sets header and footer with allocate bit set 
    alloc_ptr(p, newsize);

    return p;
}
Example #17
0
/* coalesce a pointer and free it */
void coalesce_free_ptr(void *ptr, unsigned size)
{
    // check next ptr
    if (!GET_ALLOC(HDRP(NEXT_BLKP(ptr)))) {
      unsigned nextSize = GET_SIZE(HDRP(NEXT_BLKP(ptr)));
      void *nextPtr = NEXT_BLKP(ptr);
      // check prev ptr
      if (!GET_ALLOC(HDRP(PREV_BLKP(ptr)))) {
        // coalesce with both adjacent blocks
        unsigned prevSize = GET_SIZE(HDRP(PREV_BLKP(ptr)));
        void *prevPtr = ADD_PTR(ptr, -prevSize);
        // prevPtr->next->prev = prevPtr->prev;
        PUT(PREV_PTR(GET(NEXT_PTR(prevPtr))), GET(PREV_PTR(prevPtr)));
        // prevPtr->prev->next = prevPtr->next;
        PUT(NEXT_PTR(GET(PREV_PTR(prevPtr))), GET(NEXT_PTR(prevPtr)));
        // nextPtr->next->prev = nextPtr->prev;
        PUT(PREV_PTR(GET(NEXT_PTR(nextPtr))), GET(PREV_PTR(nextPtr)));
        // nextPtr->prev->next = nextPtr->next;
        PUT(NEXT_PTR(GET(PREV_PTR(nextPtr))), GET(NEXT_PTR(nextPtr)));
        // create coalesced free block, stick block at end of free_list
        free_ptr(prevPtr, (void *)GET(PREV_PTR(free_list)), free_list,
            prevSize + size + nextSize);
        // tail->prev->next = prevPtr;
        PUT(NEXT_PTR(GET(PREV_PTR(free_list))), prevPtr);
        // tail->prev = prevPtr;
        PUT(PREV_PTR(free_list), prevPtr);
        return;
      }
      // coalesce with next block
      // nextPtr->prev->next = ptr;
      PUT(NEXT_PTR(GET(PREV_PTR(nextPtr))), ptr);
      // nextPtr->next->prev = ptr;
      PUT(PREV_PTR(GET(NEXT_PTR(nextPtr))), ptr);
      // create coalesced free block
      free_ptr(ptr, (void *)GET(PREV_PTR(nextPtr)),
          (void *)GET(NEXT_PTR(nextPtr)), size + nextSize);
      return;
    }
    if (!GET_ALLOC(HDRP(PREV_BLKP(ptr)))) {
      // coalesce with previous block
      unsigned prevSize = GET_SIZE(HDRP(PREV_BLKP(ptr)));
      void *prevPtr = ADD_PTR(ptr, -prevSize);
      // create coalesced free block
      free_ptr(prevPtr, (void *)GET(PREV_PTR(prevPtr)),
          (void *)GET(NEXT_PTR(prevPtr)), prevSize + size);
    } else {
      // don't coalesce
      // tail->prev->next = ptr;
      PUT(NEXT_PTR(GET(PREV_PTR(free_list))), ptr);
      // create free block
      free_ptr(ptr, (void *)GET(PREV_PTR(free_list)), free_list, size);
      // tail->prev = ptr;
      PUT(PREV_PTR(free_list), ptr);
    }
}
Example #18
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 #19
0
static bool netplay_get_cmd(netplay_t *netplay)
{
   uint32_t cmd;
   uint32_t flip_frame;
   uint32_t cmd_size;

   /* FIXME: This depends on delta_frame_ready */

   netplay->timeout_cnt = 0;

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

   cmd      = ntohl(cmd);

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

   cmd_size = ntohl(cmd_size);

   switch (cmd)
   {
      case NETPLAY_CMD_ACK:
         /* Why are we even bothering? */
         return true;

      case NETPLAY_CMD_NAK:
         /* Disconnect now! */
         return false;

      case NETPLAY_CMD_INPUT:
         {
            uint32_t buffer[WORDS_PER_FRAME];
            unsigned i;

            if (cmd_size != WORDS_PER_FRAME * sizeof(uint32_t))
            {
               RARCH_ERR("NETPLAY_CMD_INPUT received an unexpected payload size.\n");
               return netplay_cmd_nak(netplay);
            }

            if (!socket_receive_all_blocking(netplay->fd, buffer, sizeof(buffer)))
            {
               RARCH_ERR("Failed to receive NETPLAY_CMD_INPUT input.\n");
               return netplay_cmd_nak(netplay);
            }

            for (i = 0; i < WORDS_PER_FRAME; i++)
               buffer[i] = ntohl(buffer[i]);

            if (buffer[0] < netplay->read_frame_count)
            {
               /* We already had this, so ignore the new transmission */
               return true;
            }
            else if (buffer[0] > netplay->read_frame_count)
            {
               /* Out of order = out of luck */
               return netplay_cmd_nak(netplay);
            }

            /* The data's good! */
            netplay->buffer[netplay->read_ptr].have_remote = true;
            memcpy(netplay->buffer[netplay->read_ptr].real_input_state,
                  buffer + 1, sizeof(buffer) - sizeof(uint32_t));
            netplay->read_ptr = NEXT_PTR(netplay->read_ptr);
            netplay->read_frame_count++;
            return true;
         }

      case NETPLAY_CMD_FLIP_PLAYERS:
         if (cmd_size != sizeof(uint32_t))
         {
            RARCH_ERR("CMD_FLIP_PLAYERS received 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->read_frame_count)
         {
            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;

         /* Force a rewind to assure the flip happens: This just prevents us
          * from skipping other past the flip because our prediction was
          * correct */
         if (flip_frame < netplay->self_frame_count)
            netplay->force_rewind = true;

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

         return true;

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

      case NETPLAY_CMD_DISCONNECT:
         hangup(netplay);
         return true;

      case NETPLAY_CMD_CRC:
         {
            uint32_t buffer[2];
            size_t tmp_ptr = netplay->self_ptr;
            bool found = false;

            if (cmd_size != sizeof(buffer))
            {
               RARCH_ERR("NETPLAY_CMD_CRC received unexpected payload size.\n");
               return netplay_cmd_nak(netplay);
            }

            if (!socket_receive_all_blocking(netplay->fd, buffer, sizeof(buffer)))
            {
               RARCH_ERR("NETPLAY_CMD_CRC failed to receive payload.\n");
               return netplay_cmd_nak(netplay);
            }

            buffer[0] = ntohl(buffer[0]);
            buffer[1] = ntohl(buffer[1]);

            /* Received a CRC for some frame. If we still have it, check if it
             * matched. This approach could be improved with some quick modular
             * arithmetic. */
            do
            {
               if (     netplay->buffer[tmp_ptr].used 
                     && netplay->buffer[tmp_ptr].frame == buffer[0])
               {
                  found = true;
                  break;
               }

               tmp_ptr = PREV_PTR(tmp_ptr);
            } while (tmp_ptr != netplay->self_ptr);

            if (!found)
            {
               /* Oh well, we got rid of it! */
               return true;
            }

            if (buffer[0] <= netplay->other_frame_count)
            {
               /* We've already replayed up to this frame, so we can check it
                * directly */
               uint32_t local_crc = netplay_delta_frame_crc(
                     netplay, &netplay->buffer[tmp_ptr]);

               if (buffer[1] != local_crc)
               {
                  /* Problem! */
                  netplay_cmd_request_savestate(netplay);
               }
            }
            else
            {
               /* We'll have to check it when we catch up */
               netplay->buffer[tmp_ptr].crc = buffer[1];
            }

            return true;
         }

      case NETPLAY_CMD_REQUEST_SAVESTATE:
         /* Delay until next frame so we don't send the savestate after the
          * input */
         netplay->force_send_savestate = true;
         return true;

      case NETPLAY_CMD_LOAD_SAVESTATE:
         {
            uint32_t frame;

            /* Make sure we're ready for it */
            if (netplay->quirks & NETPLAY_QUIRK_INITIALIZATION)
            {
               if (!netplay->is_replay)
               {
                  netplay->is_replay = true;
                  netplay->replay_ptr = netplay->self_ptr;
                  netplay->replay_frame_count = netplay->self_frame_count;
                  netplay_wait_and_init_serialization(netplay);
                  netplay->is_replay = false;
               }
               else
               {
                  netplay_wait_and_init_serialization(netplay);
               }
            }

            /* There is a subtlty in whether the load comes before or after the
             * current frame:
             *
             * If it comes before the current frame, then we need to force a
             * rewind to that point.
             *
             * If it comes after the current frame, we need to jump ahead, then
             * (strangely) force a rewind to the frame we're already on, so it
             * gets loaded. This is just to avoid having reloading implemented in
             * too many places. */
            if (cmd_size > netplay->state_size + sizeof(uint32_t))
            {
               RARCH_ERR("CMD_LOAD_SAVESTATE received an unexpected save state size.\n");
               return netplay_cmd_nak(netplay);
            }

            if (!socket_receive_all_blocking(netplay->fd, &frame, sizeof(frame)))
            {
               RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive savestate frame.\n");
               return netplay_cmd_nak(netplay);
            }
            frame = ntohl(frame);

            if (frame != netplay->read_frame_count)
            {
               RARCH_ERR("CMD_LOAD_SAVESTATE loading a state out of order!\n");
               return netplay_cmd_nak(netplay);
            }

            if (!socket_receive_all_blocking(netplay->fd,
                     netplay->buffer[netplay->read_ptr].state,
                     cmd_size - sizeof(uint32_t)))
            {
               RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive savestate.\n");
               return netplay_cmd_nak(netplay);
            }

            /* Skip ahead if it's past where we are */
            if (frame > netplay->self_frame_count)
            {
               /* This is squirrely: We need to assure that when we advance the
                * frame in post_frame, THEN we're referring to the frame to
                * load into. If we refer directly to read_ptr, then we'll end
                * up never reading the input for read_frame_count itself, which
                * will make the other side unhappy. */
               netplay->self_ptr = PREV_PTR(netplay->read_ptr);
               netplay->self_frame_count = frame - 1;
            }

            /* And force rewind to it */
            netplay->force_rewind = true;
            netplay->savestate_request_outstanding = false;
            netplay->other_ptr = netplay->read_ptr;
            netplay->other_frame_count = frame;
            return true;
         }

      case NETPLAY_CMD_PAUSE:
         netplay->remote_paused = true;
         return true;

      case NETPLAY_CMD_RESUME:
         netplay->remote_paused = false;
         return true;

      default:
         break;
   }

   RARCH_ERR("Unknown netplay command received.\n");
   return netplay_cmd_nak(netplay);
}