Пример #1
0
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  int64_t paint_time = get_nanoseconds();
  switch(msg) {
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  case WM_MOUSEWHEEL:
    scrolls++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_KEYDOWN:
    if (wParam == VK_ESCAPE) {
      esc_presses++;
    }
    key_downs++;
    InvalidateRect(hwnd, NULL, false);
    break;
  case WM_PAINT:
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    wglMakeCurrent(ps.hdc, context);
    draw_pattern_with_opengl(pattern, scrolls, key_downs, esc_presses);
    SwapBuffers(ps.hdc);
    EndPaint(hwnd, &ps);
    break;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;
}
Пример #2
0
/**
 * repad_net_analyze_packet_before_put_buffer - Get some information from
 * received packet before put it in the buffer
 *
 * @param skb	The received packet
 */
static void repad_net_analyze_packet_before_put_in_buffer(struct sk_buff *skb) {
	/* Monitors viewed prefixes */
	if (!SKB_REPA_HEADER(skb)->flag_hide) {
		repad_add_new_node(ntohl(SKB_REPA_HEADER_V2(skb)->prefix_src),
				get_nanoseconds()); // Keep prefix information about nodes on network
	}
}
Пример #3
0
static screenshot *take_screenshot_with_gdi(uint32_t x, uint32_t y,
    uint32_t width, uint32_t height) {
  HRESULT hr;
  int ir;
  BOOL r;
  // DWM causes screenshotting with GDI to be very slow. The only fix is to
  // disable DWM during the test. DWM will automatically be re-enabled when the
  // process exits. This API stops working on Windows 8 (though it returns
  // success regardless).
  if (!composition_disabled) {
    // HACK: DwmEnableComposition fails unless GetDC(NULL) has been called
    // first. Who knows why.
    HDC workaround = GetDC(NULL);
    int ir = ReleaseDC(NULL, workaround);
    assert(ir);
    hr = DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);
    assert(hr == S_OK);
    // DWM takes a little while to repain the screen after being disabled.
    Sleep(1000);
    composition_disabled = true;
  }
  int virtual_x = ((int)x) - GetSystemMetrics(SM_XVIRTUALSCREEN);
  int virtual_y = ((int)y) - GetSystemMetrics(SM_YVIRTUALSCREEN);
  width = min(width, (uint32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN));
  height = min(height, (uint32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));
  HDC screen_dc = GetDC(NULL);
  assert(screen_dc);
  HDC memory_dc = CreateCompatibleDC(screen_dc);
  assert(memory_dc);
  BITMAPINFO bitmap_info;
  memset(&bitmap_info, 0, sizeof(BITMAPINFO));
  bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bitmap_info.bmiHeader.biWidth = width;
  bitmap_info.bmiHeader.biHeight = -(int)height;
  bitmap_info.bmiHeader.biPlanes = 1;
  bitmap_info.bmiHeader.biBitCount = 32;
  bitmap_info.bmiHeader.biCompression = BI_RGB;
  uint8_t *pixels = NULL;
  HBITMAP hbitmap = CreateDIBSection(screen_dc, &bitmap_info, DIB_RGB_COLORS,
      (void **)&pixels, NULL, 0);
  assert(hbitmap);
  SelectObject(memory_dc, hbitmap);
  r = BitBlt(memory_dc, 0, 0, width, height, screen_dc, virtual_x, virtual_y,
      SRCCOPY);
  assert(r);
  ir = ReleaseDC(NULL, screen_dc);
  assert(ir);
  r = DeleteObject(memory_dc);
  assert(r);
  screenshot *shot = (screenshot *)malloc(sizeof(screenshot));
  shot->pixels = pixels;
  shot->width = width;
  shot->height = height;
  shot->stride = width * 4;
  shot->platform_specific_data = hbitmap;
  shot->time_nanoseconds = get_nanoseconds();
  return shot;
}
Пример #4
0
void calc_send(repa_sock_t *sock, const char* interest, size_t packet_size,
		const int wait_time, const int64_t total_bytes) {
	long long int start_time, end_time, diff_time;
	int64_t total_bytes_sent = 0;

	{
		size_t max_packet_size = LIBREPA_MAX_DATA_LEN(strlen(interest));
		packet_size = (packet_size > max_packet_size ? max_packet_size : packet_size);
	}

	char data[packet_size];

	/* initialize random seed: */
	srand (time(NULL));

	printf("Starting sending %"PRId64" [%zd]...\n", total_bytes, sizeof(int64_t));
	repa_send(sock, interest, &total_bytes, sizeof(int64_t), 0);
	start_time = get_nanoseconds();
	while (true) {
		if (repa_send(sock, interest, data, packet_size, 0) > 0) {
			total_bytes_sent += packet_size;
			if (total_bytes_sent >= total_bytes) {
				// Finalizando o envio
				break;
			}
		} else {
			// Erro ao tentar enviar pacote
			break;
		}

		if (wait_time == 1) usleep((rand()%8000)+2500);

		//printf("\rSent %jd bytes...[%jd%%]", total_bytes_sent,
		///		(total_bytes_sent*100)/total_bytes);
	//	fflush(stdout);
	}
	end_time = get_nanoseconds();
	diff_time = end_time - start_time;

	double kbps = (((double)total_bytes_sent)/((double)diff_time))*((double)NSEC_PER_SEC/(double)1024);

	printf("\rSent %ju*%zd=%jd bytes in %llds %lldns -> %.2fKB/s\n",
			total_bytes_sent/packet_size, packet_size, total_bytes_sent,
			(diff_time/NSEC_PER_SEC), (diff_time%NSEC_PER_SEC), kbps);
}
Пример #5
0
void calc_recv(repa_sock_t *sock) {
	prefix_addr_t src_address = 0;
	int64_t num_packets = 0, bytes_recv = 0, total_bytes_recv = 0, total_bytes = INT64_MAX;
	long long int start_time, end_time, diff_time;
	char interest[LIBREPA_MAX_INTEREST_LEN], data[LIBREPA_MAX_DATA_LEN(0)];

	printf("Waiting to start...\n");
	bytes_recv = (int64_t)repa_recv(sock, interest, data, LIBREPA_MAX_DATA_LEN(0), &src_address, NULL);
	if (bytes_recv == sizeof(int64_t)) {
		memcpy(&total_bytes, data, sizeof(int64_t));
	}
	printf("Receiving...\n");
	start_time = get_nanoseconds();
	while (true) {
		if ((bytes_recv = repa_timed_recv(sock, interest, data, LIBREPA_MAX_DATA_LEN(0),
				&src_address, NULL, 1*USEC_PER_SEC)) > 0) {
			num_packets++;
			total_bytes_recv += bytes_recv;
		} else {
			// Nenhum byte recebido no intervalo de tempo de 1seg
			// indica o fim do recebimento
			break;
		}
		//printf("\rReceive %jd bytes...[%jd%%]", total_bytes_recv,
	//			(total_bytes_recv*100)/total_bytes);
	//	fflush(stdout);
	}
	end_time = get_nanoseconds();
	diff_time = end_time - start_time;

	// Retira 1 segundo de espera caso não tenha recebido
	// o byte de finalização do fluxo
	diff_time -= 1*NSEC_PER_SEC;

	double kbps = (((double)total_bytes_recv)/((double)diff_time))*((double)NSEC_PER_SEC/(double)1024);

	num_packets = (num_packets == 0 ? INT64_MAX : num_packets);
	total_bytes = (total_bytes == 0 ? INT64_MAX : total_bytes);
	printf("\rReceived %jd*%jd=%jd/%jd bytes in %llds %lldns -> %.2fKB/s - %jd%% loss\n",
			num_packets, total_bytes_recv/num_packets, total_bytes_recv,
			total_bytes, (diff_time/NSEC_PER_SEC), (diff_time%NSEC_PER_SEC), kbps,
			100-((total_bytes_recv*100)/total_bytes));
}
Пример #6
0
// Updates the given pattern with the given event data, then draws the pattern
// to the current OpenGL context.
void draw_pattern_with_opengl(uint8_t pattern[], int scroll_events,
                              int keydown_events, int esc_presses) {
  int64_t time = get_nanoseconds();
  if (last_draw_time > 0) {
    if (time - last_draw_time > biggest_draw_time_gap) {
      biggest_draw_time_gap = time - last_draw_time;
      debug_log("New biggest draw time gap: %f ms.",
          biggest_draw_time_gap / (double)nanoseconds_per_millisecond);
    }
  }
  last_draw_time = time;
  if (esc_presses == 0) {
    pattern[4 * 4 + 2] = TEST_MODE_JAVASCRIPT_LATENCY;
  } else {
    pattern[4 * 4 + 2] = TEST_MODE_ABORT;
  }
  // Update the pattern with the number of scroll events mod 255.
  pattern[4 * 5] = pattern[4 * 5 + 1] = pattern[4 * 5 + 2] = scroll_events;
  // Update the pattern with the number of keydown events mod 255.
  pattern[4 * 4 + 1] = keydown_events;
  // Increment the "JavaScript frames" counter.
  pattern[4 * 4 + 0]++;
  // Increment the "CSS animation frames" counter.
  pattern[4 * 6 + 0]++;
  pattern[4 * 6 + 1]++;
  pattern[4 * 6 + 2]++;
  GLint viewport[4];
  glGetIntegerv(GL_VIEWPORT, viewport);
  GLint height = viewport[3];
  glDisable(GL_SCISSOR_TEST);
  // Alternate background each frame to make tearing easy to spot.
  float background = 1;
  if (pattern[4 * 4 + 0] % 2 == 1)
    background = 0.8;
  glClearColor(background, background, background, 1);
  glClear(GL_COLOR_BUFFER_BIT);
  glEnable(GL_SCISSOR_TEST);
  for (int i = 0; i < pattern_bytes; i += 4) {
    glClearColor(pattern[i + 2] / 255.0,
                 pattern[i + 1] / 255.0,
                 pattern[i] / 255.0, 1);
    glScissor(i / 4, height - 1, 1, 1);
    glClear(GL_COLOR_BUFFER_BIT);
  }
}
Пример #7
0
// Main test function. Locates the given magic pixel pattern on the screen, then
// runs one full latency test, sending input events and recording responses. On
// success, the results of the test are reported in the output parameters, and
// true is returned. If the test fails, the error parameter is filled in with
// an error message and false is returned.
bool measure_latency(
    const uint8_t magic_pattern[],
    double *out_key_down_latency_ms,
    double *out_scroll_latency_ms,
    double *out_max_js_pause_time_ms,
    double *out_max_css_pause_time_ms,
    double *out_max_scroll_pause_time_ms,
    char **error) {
  screenshot *screenshot = take_screenshot(0, 0, UINT32_MAX, UINT32_MAX);
  if (!screenshot) {
    *error = "Failed to take screenshot.";
    return false;
  }
  assert(screenshot->width > 0 && screenshot->height > 0);

  size_t x, y;
  bool found_pattern = find_pattern(magic_pattern, screenshot, &x, &y);
  free_screenshot(screenshot);
  if (!found_pattern) {
    *error = "Failed to find test pattern on screen.";
    return false;
  }
  uint8_t full_pattern[pattern_bytes];
  for (int i = 0; i < pattern_magic_bytes; i++) {
    full_pattern[i] = magic_pattern[i];
  }
  measurement_t measurement;
  measurement_t previous_measurement;
  memset(&measurement, 0, sizeof(measurement_t));
  memset(&previous_measurement, 0, sizeof(measurement_t));
  int screenshots = 0;
  bool first_screenshot_successful = read_data_from_screen((uint32_t)x,
      (uint32_t) y, magic_pattern, &measurement);
  if (!first_screenshot_successful) {
    *error = "Failed to read data from test pattern.";
    return false;
  }
  if (measurement.test_mode == TEST_MODE_NATIVE_REFERENCE) {
    uint8_t *test_pattern = (uint8_t *)malloc(pattern_bytes);
    memset(test_pattern, 0, pattern_bytes);
    for (int i = 0; i < pattern_magic_bytes; i++) {
      test_pattern[i] = rand();
    }
    if (!open_native_reference_window(test_pattern)) {
      *error = "Failed to open native reference window.";
      return false;
    }
    bool return_value = measure_latency(test_pattern, out_key_down_latency_ms, out_scroll_latency_ms, out_max_js_pause_time_ms, out_max_css_pause_time_ms, out_max_scroll_pause_time_ms, error);
    if (!close_native_reference_window()) {
      debug_log("Failed to close native reference window.");
    };
    return return_value;
  }
  int64_t start_time = measurement.screenshot_time;
  previous_measurement = measurement;
  statistic javascript_frames;
  statistic css_frames;
  statistic key_down_events;
  statistic scroll_stats;
  init_statistic("javascript_frames", &javascript_frames,
      measurement.javascript_frames, start_time);
  init_statistic("key_down_events", &key_down_events,
      measurement.key_down_events, start_time);
  init_statistic("css_frames", &css_frames, measurement.css_frames, start_time);
  init_statistic("scroll", &scroll_stats, measurement.scroll_position,
      start_time);
  int sent_events = 0;
  int scroll_x = x + 40;
  int scroll_y = y + 40;
  int64_t last_scroll_sent = start_time;
  if (measurement.test_mode == TEST_MODE_SCROLL_LATENCY) {
    send_scroll_down(scroll_x, scroll_y);
    scroll_stats.previous_change_time = get_nanoseconds();
  }
  while(true) {
    bool screenshot_successful = read_data_from_screen((uint32_t)x,
        (uint32_t) y, magic_pattern, &measurement);
    if (!screenshot_successful) {
      *error = "Test window moved during test. The test window must remain "
          "stationary and focused during the entire test.";
      return false;
    }
    if (measurement.test_mode == TEST_MODE_ABORT) {
      *error = "Test aborted.";
      return false;
    }
    screenshots++;
    int64_t screenshot_time = measurement.screenshot_time;
    int64_t previous_screenshot_time = previous_measurement.screenshot_time;
    debug_log("screenshot time %f",
        (screenshot_time - previous_screenshot_time) /
            (double)nanoseconds_per_millisecond);
    update_statistic(&javascript_frames, measurement.javascript_frames,
        screenshot_time, previous_screenshot_time);
    update_statistic(&key_down_events, measurement.key_down_events,
        screenshot_time, previous_screenshot_time);
    update_statistic(&css_frames, measurement.css_frames, screenshot_time,
        previous_screenshot_time);
    bool scroll_updated = update_statistic(&scroll_stats,
        measurement.scroll_position, screenshot_time, previous_screenshot_time);

    if (measurement.test_mode == TEST_MODE_JAVASCRIPT_LATENCY) {
      if (key_down_events.measurements >= latency_measurements_to_take) {
        break;
      }
      if (key_down_events.value_delta > sent_events) {
        *error = "More events received than sent! This is probably a bug in "
            "the test.";
        return false;
      }
      if (screenshot_time - key_down_events.previous_change_time >
          event_response_timeout_ms * nanoseconds_per_millisecond) {
        *error = "Browser did not respond to keyboard input. Make sure the "
            "test page remains focused for the entire test.";
        return false;
      }
      if (key_down_events.value_delta == sent_events) {
        // We want to avoid sending input events at a predictable time relative
        // to frames, so introduce a random delay of up to 1 frame (16.67 ms)
        // before sending the next event.
        usleep((rand() % 17) * 1000);
        if (!send_keystroke_z()) {
          *error = "Failed to send keystroke for \"Z\" key to test window.";
          return false;
        }
        key_down_events.previous_change_time = get_nanoseconds();
        sent_events++;
      }
    } else if (measurement.test_mode == TEST_MODE_SCROLL_LATENCY) {
        if (scroll_stats.measurements >= latency_measurements_to_take) {
          break;
        }
        if (screenshot_time - scroll_stats.previous_change_time >
            event_response_timeout_ms * nanoseconds_per_millisecond) {
          *error = "Browser did not respond to scroll events. Make sure the "
              "test page remains focused for the entire test.";
          return false;
        }
        if (scroll_updated) {
          // We saw the start of a scroll. Wait for the scroll animation to
          // finish before continuing. We assume the animation is finished if
          // it's been 100 milliseconds since we last saw the scroll position
          // change.
          int64_t scroll_update_time = screenshot_time;
          int64_t scroll_wait_start_time = screenshot_time;
          while (screenshot_time - scroll_update_time <
                 100 * nanoseconds_per_millisecond) {
            screenshot_successful = read_data_from_screen((uint32_t)x,
                (uint32_t) y, magic_pattern, &measurement);
            if (!screenshot_successful) {
              *error = "Test window moved during test. The test window must "
                  "remain stationary and focused during the entire test.";
              return false;
            }
            screenshot_time = measurement.screenshot_time;
            if (screenshot_time - scroll_wait_start_time >
                nanoseconds_per_second) {
              *error = "Browser kept scrolling for more than 1 second after a "
                  "single scrollwheel event.";
              return false;
            }
            if (measurement.scroll_position != scroll_stats.value) {
              scroll_stats.value = measurement.scroll_position;
              scroll_update_time = screenshot_time;
            }
          }
          // We want to avoid sending input events at a predictable time
          // relative to frames, so introduce a random delay of up to 1 frame
          // (16.67 ms) before sending the next event.
          usleep((rand() % 17) * 1000);
          send_scroll_down(scroll_x, scroll_y);
          scroll_stats.previous_change_time = get_nanoseconds();
        }
    } else if (measurement.test_mode == TEST_MODE_PAUSE_TIME) {
      // For the pause time test we want the browser to scroll continuously.
      // Send a scroll event every frame.
      if (screenshot_time - last_scroll_sent >
          17 * nanoseconds_per_millisecond) {
        send_scroll_down(scroll_x, scroll_y);
        last_scroll_sent = get_nanoseconds();
      }
    } else if (measurement.test_mode == TEST_MODE_PAUSE_TIME_TEST_FINISHED) {
      break;
    } else {
      *error = "Invalid test type. This is a bug in the test.";
      return false;
    }

    if (screenshot_time - start_time >
        test_timeout_ms * nanoseconds_per_millisecond) {
      *error = "Timeout.";
      return false;
    }
    previous_measurement = measurement;
    usleep(0);
  }
  // The latency we report is the midpoint of the interval given by the average
  // upper and lower bounds we've computed.
  *out_key_down_latency_ms =
      (upper_bound_ms(&key_down_events) + lower_bound_ms(&key_down_events)) / 2;
  *out_scroll_latency_ms =
      (upper_bound_ms(&scroll_stats) + lower_bound_ms(&scroll_stats) / 2);
  *out_max_js_pause_time_ms =
      javascript_frames.max_lower_bound / (double) nanoseconds_per_millisecond;
  *out_max_css_pause_time_ms =
      css_frames.max_lower_bound / (double) nanoseconds_per_millisecond;
  *out_max_scroll_pause_time_ms =
      scroll_stats.max_lower_bound / (double) nanoseconds_per_millisecond;
  debug_log("out_key_down_latency_ms: %f out_scroll_latency_ms: %f "
      "out_max_js_pause_time_ms: %f out_max_css_pause_time: %f\n "
      "out_max_scroll_pause_time_ms: %f",
      *out_key_down_latency_ms,
      *out_scroll_latency_ms,
      *out_max_js_pause_time_ms,
      *out_max_css_pause_time_ms,
      *out_max_scroll_pause_time_ms);
  return true;
}
Пример #8
0
/**
 * repad_net_handle_msg - Handle a new packet received with repa version 2
 *
 * @param skb	The new packet received to be handle
 */
void repad_net_handle_msg_v2(struct sk_buff *skb) {
	int64_t last_timestamp = 0, now = get_nanoseconds();
	prefix_addr_t prefix_src = ntohl(SKB_REPA_HEADER_V2(skb)->prefix_src);
	prefix_addr_t prefix_dst = ntohl(SKB_REPA_HEADER_V2(skb)->prefix_dst);

	{
		char prefix[64];
		repad_print_prefix(prefix_src, prefix);
		repad_printf(LOG_INFO, "HANDLE_V2: Just arrive a packet from %s!\n", prefix);
	}

	/* Just for statistics, increase total messages received */
	repad_attr.statistics.qtyMessageTotalReceived++;

	/* Verify the destination of packet */
	repad_printf(LOG_INFO, "HANDLE_V2: Verify destination prefix of packet!\n");
	if (!((prefix_dst == 0) /* Group communication */ ||
			(prefix_dst == repad_attr.pref_node_address))) { /* Addressed to me */
		repad_printf(LOG_INFO, "HANDLE_V2: Packet dropped because it is not for me!\n");
		goto exit;
	}

	/* Verify memory */
	repad_printf(LOG_INFO, "HANDLE_V2: Search packet in the node memory!\n");
	if ((last_timestamp = repad_verify_memory(skb)) > 0L) {
		/* If received packet will be discarded, calculate RTT */
		if ((0 < last_timestamp) && (last_timestamp < INT64_MAX)) {
			int64_t diff = now - last_timestamp;
			if (diff > 0) { // Valid diff (now > last_timestamp)
				rtt_mean_estimator_measurement(repad_attr.rtt_estimator, diff);
			}
		}

		/* Statistics and drop packet by memory */
		repad_attr.statistics.qtyMessageDroppedMemory++; // Statistics
		repad_printf(LOG_INFO, "HANDLE_V2: Packet dropped by memory!\n");
		goto exit; // End.
	}

	// Verify extension headers
	repad_printf(LOG_INFO, "HANDLE_V2: Evaluate extension headers!\n");
	intptr_t header_position = sizeof(struct repahdr_v2);
	uint8_t next_header = SKB_REPA_HEADER_V2(skb)->next_header;
	while(next_header != REPAHDR_EH_NO_NEXT) {
		switch (next_header) {
		case REPAHDR_EH_INTEREST: // A Interest Packet
			/* Evaluate Prefixes for matching and HTL */
			repad_net_evaluate_prefix_htl(skb, prefix_src);

			// Handle interest packet and return the next header
			next_header = repad_net_handle_eh_interest(skb, &header_position);
			break;
		case REPAHDR_CONTROL: // A Control Packet
			next_header = repad_net_handle_control_messages(skb, &header_position);
			break;
		case REPAHDR_EH_HASH: // Not defined yet
		case REPAHDR_EH_SECURITY: // Not defined yet
		default:
			// TODO: create another header extension
			next_header = REPAHDR_EH_NO_NEXT; // No next extension header
			break;
		}
	}

exit:
	/* Free the sk_buffer */
	skb_release(skb);
}
Пример #9
0
/**
 * repad_net_handle_eh_interest - Handle the interest extension header
 *
 * @param skb	The sk_buff with packet received
 * @param header_position	The interest header position after others extension headers
 *
 * @return		The code of next extension header
 */
static uint8_t repad_net_handle_eh_interest(struct sk_buff *skb, intptr_t *header_position) {
	/* Get the Repa header */
	struct repahdr_v2 *hdr = SKB_REPA_HEADER_V2(skb);
	/* Get the Next Header and handle like Interest extension header */
	struct repahdr_v2_eh_interest *hdr_eh_interest = (struct repahdr_v2_eh_interest*)
					((intptr_t)hdr + (*header_position));

	// Update the header position
	(*header_position) += offsetof(struct repahdr_v2_eh_interest,interest) + hdr_eh_interest->interest_len;

	/* Create a temporary interest */
	char *interest_temp = repad_strclone(hdr_eh_interest->interest, (size_t)hdr_eh_interest->interest_len);

	uint64_t pkt_timestamp = ntohll(hdr->timestamp);

	lib_repa_proto_interest_t meta_interest = {
			.flags = hdr_eh_interest->flags,
			.interest_len = hdr_eh_interest->interest_len,
			.split_interest_char = hdr_eh_interest->split_interest_char
	};

	repad_unix_delivery(NULL, skb, &meta_interest, interest_temp, pkt_timestamp);

	/* Free temporary interest. No one MUST get this reference */
	free(interest_temp);

	return hdr_eh_interest->next_header;
}


/**
 * repad_net_evaluate_prefix_htl - function used to evaluate the prefix and htl
 * for received packets. The algorithm avoid isolation was implemented here too.
 *
 * @param skb			The new packet received to be handle
 * @param prefix_src	The source prefix of received packet
 */
static void repad_net_evaluate_prefix_htl(struct sk_buff *skb, prefix_addr_t prefix_src) {
	repad_printf(LOG_INFO, "HANDLE_V2: Evaluate prefix match and HTL!\n");

	if (!repad_net_match_prefix_at_least(prefix_src)) {
		/*  Evaluate the Avoid Isolation algorithm */
		if (repad_attr.bl_avoid_isolation_enable) {
			if (SKB_REPA_HEADER_V2(skb)->htl > 0) {
				SKB_REPA_HEADER_V2(skb)->htl--; // Decrease HTL
				repad_printf(LOG_INFO, "AVOID_ISOLATION: Keep packet for a while!\n");

				/* Verify if this packet is already scheduled to send later */
				pwm_packet_without_match_t *pwm = pwm_create(skb);
				if (pwm != NULL) {
					int64_t time_to_sent = get_nanoseconds() +

							/************************************************
							 * TODO: Change time to wait before sent a packet
							 ************************************************/

							repad_attr.dbl_ai_rtt_factor*rtt_mean_estimator_get_curr_estimate(repad_attr.rtt_estimator) +
							rand()%500000; // Get a rand time between [0,500]us

					/* If not found, schedule to send later */
					if (tt_timer_schedule(repad_attr.tt_timer_task,
							pwm->__scheduled_task, time_to_sent, 0) == 0) {
						if (dll_append(repad_attr.list_pkt_without_match, pwm) == NULL) {
							/* If was not possible insert in list, release an instance */
//							pwm_release(pwm);
							repad_printf(LOG_ERR, "AVOID_ISOLATION: ERROR: Cannot add new pwm in list_pkt_without_match!\n");
						}
					} else {
						/* If timer does not schedule the task, destroy pwm */
						pwm_destroy(pwm);
					}
				}
			}
		} else {
			/* Drop packet right now */
			repad_printf(LOG_INFO, "HANDLE_V2: Packet dropped by Prefix!\n");
			repad_attr.statistics.qtyMessageDroppedPrefixP++; // Statistics: dropped by prefix
		}
	} else if (SKB_REPA_HEADER_V2(skb)->flag_foward) { // If has match and is to forward, forward
		if (SKB_REPA_HEADER_V2(skb)->htl > 0) {
			SKB_REPA_HEADER_V2(skb)->htl--; // Decrease HTL
			/* Evaluate the Reduce Message algorithm */
			if (repad_attr.bl_reduce_messages_enable) {
				repad_printf(LOG_INFO, "REDUCE_MESSAGE: Probability for "
						"forwarding is %0.2f!\n",
						mc_get_mean(repad_attr.sent_probability));

				double sent_prob = (rand()/(float)RAND_MAX);
				if (sent_prob <= mc_get_mean(repad_attr.sent_probability)) {
					// Statistics: packet forwarded
					repad_attr.statistics.qtyMessageSent++;

					/* Forward packet right now */
					repad_printf(LOG_INFO, "REDUCE_MESSAGE: Packet will be forward!\n");
					repad_net_forward_packet(skb);
				}
			} else {
				// Statistics: packet forwarded
				repad_attr.statistics.qtyMessageSent++;

				/* Forward packet right now */
				repad_printf(LOG_INFO, "HANDLE_V2: Packet will be forward!\n");
				repad_net_forward_packet(skb);
			}
		} else {
			repad_printf(LOG_INFO, "HANDLE_V2: Packet dropped by HTL!\n");
			repad_attr.statistics.qtyMessageDroppedMaxHTL++; // Statistics: dropped by HTL limit
		}
	}

	// Statistics: Unique packet
	repad_attr.statistics.qtyMessageUniqueReceive++;
}