Пример #1
0
/**
 * @brief Check that the decompression of the ROHC feedback-only packets is
 *        successful.
 *
 * @param argc The number of program arguments
 * @param argv The program arguments
 * @return     The unix return code:
 *              \li 0 in case of success,
 *              \li 1 in case of failure
 */
int main(int argc, char *argv[])
{
	/* a ROHC feedback-only packet */
	const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 };
	uint8_t rohc_feedback_data[] = { 0xf4, 0x20, 0x00, 0x11, 0xe9 };
	const size_t rohc_feedback_len = 5;
	const struct rohc_buf rohc_feedback =
		rohc_buf_init_full(rohc_feedback_data, rohc_feedback_len, arrival_time);

	int status = 1;

	/* parse program arguments, print the help message in case of failure */
	if(argc != 1)
	{
		usage();
		goto error;
	}

	/* test ROHC feedback-only decompression */
	status = test_decomp(rohc_feedback);

error:
	return status;
}


/**
 * @brief Print usage of the application
 */
static void usage(void)
{
	fprintf(stderr,
	        "Check that feedback-only packets are decompressed as expected\n"
	        "\n"
	        "usage: test_decompress_feedback_only [OPTIONS]\n"
	        "\n"
	        "options:\n"
	        "  -h           Print this usage and exit\n");
}
Пример #2
0
/**
 * @brief Test the robustness of the compression API
 *
 * @param argc  The number of command line arguments
 * @param argv  The command line arguments
 * @return      0 if test succeeds, non-zero if test fails
 */
int main(int argc, char *argv[])
{
	struct rohc_comp *comp;
	bool verbose; /* whether to run in verbose mode or not */
	int is_failure = 1; /* test fails by default */

	/* do we run in verbose mode ? */
	if(argc == 1)
	{
		/* no argument, run in silent mode */
		verbose = false;
	}
	else if(argc == 2 && strcmp(argv[1], "verbose") == 0)
	{
		/* run in verbose mode */
		verbose = true;
	}
	else
	{
		/* invalid usage */
		printf("test the robustness of the compression API\n");
		printf("usage: %s [verbose]\n", argv[0]);
		goto error;
	}

	/* rohc_comp_new2() */
	CHECK(rohc_comp_new2(-1, ROHC_SMALL_CID_MAX, random_cb, NULL) == NULL);
	CHECK(rohc_comp_new2(ROHC_SMALL_CID + 1, ROHC_SMALL_CID_MAX,
	                     random_cb, NULL) == NULL);
	comp = rohc_comp_new2(ROHC_SMALL_CID, 0, random_cb, NULL);
	CHECK(comp != NULL);
	rohc_comp_free(comp);
	comp = rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX,
	                      random_cb, NULL);
	CHECK(comp != NULL);
	rohc_comp_free(comp);
	CHECK(rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX + 1,
	                     random_cb, NULL) == NULL);
	comp = rohc_comp_new2(ROHC_LARGE_CID, 0, random_cb, NULL);
	CHECK(comp != NULL);
	rohc_comp_free(comp);
	comp = rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX,
	                      random_cb, NULL);
	CHECK(comp != NULL);
	rohc_comp_free(comp);
	CHECK(rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX + 1,
	                     random_cb, NULL) == NULL);
	CHECK(rohc_comp_new2(ROHC_LARGE_CID, ROHC_LARGE_CID_MAX,
	                     NULL, NULL) == NULL);
	comp = rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX,
	                      random_cb, NULL);
	CHECK(comp != NULL);

	/* rohc_comp_set_traces_cb2() */
	{
		rohc_trace_callback2_t fct = (rohc_trace_callback2_t) NULL;
		CHECK(rohc_comp_set_traces_cb2(NULL, fct, NULL) == false);
		CHECK(rohc_comp_set_traces_cb2(comp, fct, NULL) == true);
		CHECK(rohc_comp_set_traces_cb2(comp, fct, comp) == true);
	}

	/* rohc_comp_profile_enabled() */
	CHECK(rohc_comp_profile_enabled(NULL, ROHC_PROFILE_IP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_GENERAL) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UNCOMPRESSED) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_RTP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_ESP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_IP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_TCP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDPLITE) == false);

	/* rohc_comp_enable_profile() */
	CHECK(rohc_comp_enable_profile(NULL, ROHC_PROFILE_IP) == false);
	CHECK(rohc_comp_enable_profile(comp, ROHC_PROFILE_GENERAL) == false);
	CHECK(rohc_comp_enable_profile(comp, ROHC_PROFILE_IP) == true);

	/* rohc_comp_disable_profile() */
	CHECK(rohc_comp_disable_profile(NULL, ROHC_PROFILE_IP) == false);
	CHECK(rohc_comp_disable_profile(comp, ROHC_PROFILE_GENERAL) == false);
	CHECK(rohc_comp_disable_profile(comp, ROHC_PROFILE_IP) == true);

	/* rohc_comp_enable_profiles() */
	CHECK(rohc_comp_enable_profiles(NULL, ROHC_PROFILE_IP, -1) == false);
	CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_GENERAL, -1) == false);
	CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_IP, -1) == true);
	CHECK(rohc_comp_enable_profiles(comp, ROHC_PROFILE_IP, ROHC_PROFILE_UDP,
	                                ROHC_PROFILE_RTP, -1) == true);

	/* rohc_comp_disable_profiles() */
	CHECK(rohc_comp_disable_profiles(NULL, ROHC_PROFILE_IP, -1) == false);
	CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_GENERAL, -1) == false);
	CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_UDP, -1) == true);
	CHECK(rohc_comp_disable_profiles(comp, ROHC_PROFILE_UDP,
	                                 ROHC_PROFILE_RTP, -1) == true);

	/* rohc_comp_profile_enabled() */
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UNCOMPRESSED) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_RTP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_ESP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_IP) == true);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_TCP) == false);
	CHECK(rohc_comp_profile_enabled(comp, ROHC_PROFILE_UDPLITE) == false);

	/* rohc_comp_get_segment2() */
	{
		unsigned char buf1[1];
		struct rohc_buf pkt1 = rohc_buf_init_empty(buf1, 1);
		CHECK(rohc_comp_get_segment2(NULL, &pkt1) == ROHC_STATUS_ERROR);
		CHECK(rohc_comp_get_segment2(comp, NULL) == ROHC_STATUS_ERROR);
		pkt1.max_len = 0;
		pkt1.offset = 0;
		pkt1.len = 0;
		CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR);
		pkt1.max_len = 1;
		pkt1.offset = 0;
		pkt1.len = 0;
		CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR);
		pkt1.max_len = 2;
		pkt1.offset = 0;
		pkt1.len = 0;
		CHECK(rohc_comp_get_segment2(comp, &pkt1) == ROHC_STATUS_ERROR);
	}

	/* rohc_comp_force_contexts_reinit() */
	CHECK(rohc_comp_force_contexts_reinit(NULL) == false);
	CHECK(rohc_comp_force_contexts_reinit(comp) == true);

	/* rohc_comp_set_wlsb_window_width() */
	CHECK(rohc_comp_set_wlsb_window_width(NULL, 16) == false);
	CHECK(rohc_comp_set_wlsb_window_width(comp, 0) == false);
	CHECK(rohc_comp_set_wlsb_window_width(comp, 15) == false);
	CHECK(rohc_comp_set_wlsb_window_width(comp, 16) == true);

	/* rohc_comp_set_periodic_refreshes() */
	CHECK(rohc_comp_set_periodic_refreshes(NULL, 1700, 700) == false);
	CHECK(rohc_comp_set_periodic_refreshes(comp, 0, 700) == false);
	CHECK(rohc_comp_set_periodic_refreshes(comp, 1700, 0) == false);
	CHECK(rohc_comp_set_periodic_refreshes(comp, 5, 10) == false);
	CHECK(rohc_comp_set_periodic_refreshes(comp, 10, 5) == true);

	/* rohc_comp_set_list_trans_nr() */
	CHECK(rohc_comp_set_list_trans_nr(NULL, 5) == false);
	CHECK(rohc_comp_set_list_trans_nr(comp, 0) == false);
	CHECK(rohc_comp_set_list_trans_nr(comp, 1) == true);
	CHECK(rohc_comp_set_list_trans_nr(comp, 5) == true);

	/* rohc_comp_set_rtp_detection_cb() */
	{
		rohc_rtp_detection_callback_t fct =
			(rohc_rtp_detection_callback_t) NULL;
		CHECK(rohc_comp_set_rtp_detection_cb(NULL, fct, NULL) == false);
		CHECK(rohc_comp_set_rtp_detection_cb(comp, fct, NULL) == true);
	}

	/* rohc_comp_set_mrru() */
	CHECK(rohc_comp_set_mrru(NULL, 10) == false);
	CHECK(rohc_comp_set_mrru(comp, 65535 + 1) == false);
	CHECK(rohc_comp_set_mrru(comp, 0) == true);
	CHECK(rohc_comp_set_mrru(comp, 65535) == true);

	/* rohc_comp_get_mrru() */
	{
		size_t mrru;
		CHECK(rohc_comp_get_mrru(NULL, &mrru) == false);
		CHECK(rohc_comp_get_mrru(comp, NULL) == false);
		CHECK(rohc_comp_get_mrru(comp, &mrru) == true);
		CHECK(mrru == 65535);
	}
	/* disable MRRU for next tests */
	CHECK(rohc_comp_set_mrru(comp, 0) == true);

	/* rohc_comp_get_max_cid() */
	{
		size_t max_cid;
		CHECK(rohc_comp_get_max_cid(NULL, &max_cid) == false);
		CHECK(rohc_comp_get_max_cid(comp, NULL) == false);
		CHECK(rohc_comp_get_max_cid(comp, &max_cid) == true);
		CHECK(max_cid == ROHC_SMALL_CID_MAX);
	}

	/* rohc_comp_get_cid_type() */
	{
		rohc_cid_type_t cid_type;
		CHECK(rohc_comp_get_cid_type(NULL, &cid_type) == false);
		CHECK(rohc_comp_get_cid_type(comp, NULL) == false);
		CHECK(rohc_comp_get_cid_type(comp, &cid_type) == true);
		CHECK(cid_type == ROHC_SMALL_CID);
	}

	/* rohc_comp_get_last_packet_info2() before any compressed packet */
	{
		rohc_comp_last_packet_info2_t info;
		memset(&info, 0, sizeof(rohc_comp_last_packet_info2_t));
		info.version_major = 0;
		info.version_minor = 0;
		CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false);
	}

	/* rohc_compress4() */
	{
		const struct rohc_ts ts = { .sec = 0, .nsec = 0 };
		unsigned char buf1[1] = { 0x00 };
		struct rohc_buf pkt1 = rohc_buf_init_full(buf1, 1, ts);
		unsigned char buf2[100];
		struct rohc_buf pkt2 = rohc_buf_init_empty(buf2, 100);
		unsigned char buf[] =
		{
			0x45, 0x00, 0x00, 0x54,  0x00, 0x00, 0x40, 0x00,
			0x40, 0x01, 0x93, 0x52,  0xc0, 0xa8, 0x13, 0x01,
			0xc0, 0xa8, 0x13, 0x05,  0x08, 0x00, 0xe9, 0xc2,
			0x9b, 0x42, 0x00, 0x01,  0x66, 0x15, 0xa6, 0x45,
			0x77, 0x9b, 0x04, 0x00,  0x08, 0x09, 0x0a, 0x0b,
			0x0c, 0x0d, 0x0e, 0x0f,  0x10, 0x11, 0x12, 0x13,
			0x14, 0x15, 0x16, 0x17,  0x18, 0x19, 0x1a, 0x1b,
			0x1c, 0x1d, 0x1e, 0x1f,  0x20, 0x21, 0x22, 0x23,
			0x24, 0x25, 0x26, 0x27,  0x28, 0x29, 0x2a, 0x2b,
			0x2c, 0x2d, 0x2e, 0x2f,  0x30, 0x31, 0x32, 0x33,
			0x34, 0x35, 0x36, 0x37
		};
		struct rohc_buf pkt = rohc_buf_init_full(buf, sizeof(buf), ts);
		CHECK(rohc_compress4(NULL, pkt1, &pkt2) == ROHC_STATUS_ERROR);
		pkt1.len = 0;
		CHECK(rohc_compress4(comp, pkt1, &pkt2) == ROHC_STATUS_ERROR);
		pkt1.len = 1;
		CHECK(rohc_compress4(comp, pkt1, NULL) == ROHC_STATUS_ERROR);
		pkt2.max_len = 0;
		pkt2.offset = 0;
		pkt2.len = 0;
		CHECK(rohc_compress4(comp, pkt1, &pkt2) == ROHC_STATUS_ERROR);
		for(size_t i = 0; i <= pkt.len; i++)
		{
			pkt2.max_len = i;
			pkt2.offset = 0;
			pkt2.len = 0;
			CHECK(rohc_compress4(comp, pkt, &pkt2) == ROHC_STATUS_ERROR);
		}
		pkt2.max_len = pkt.len + 1;
		pkt2.offset = 0;
		pkt2.len = 0;
		CHECK(rohc_compress4(comp, pkt, &pkt2) == ROHC_STATUS_OK);
	}

	/* rohc_comp_get_last_packet_info2() */
	{
		rohc_comp_last_packet_info2_t info;
		memset(&info, 0, sizeof(rohc_comp_last_packet_info2_t));
		CHECK(rohc_comp_get_last_packet_info2(NULL, &info) == false);
		CHECK(rohc_comp_get_last_packet_info2(comp, NULL) == false);
		info.version_major = 0xffff;
		CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false);
		info.version_major = 0;
		info.version_minor = 0xffff;
		CHECK(rohc_comp_get_last_packet_info2(comp, &info) == false);
		info.version_minor = 0;
		CHECK(rohc_comp_get_last_packet_info2(comp, &info) == true);
	}

	/* rohc_comp_get_general_info() */
	{
		rohc_comp_general_info_t info;
		memset(&info, 0, sizeof(rohc_comp_general_info_t));
		CHECK(rohc_comp_get_general_info(NULL, &info) == false);
		CHECK(rohc_comp_get_general_info(comp, NULL) == false);
		info.version_major = 0xffff;
		CHECK(rohc_comp_get_general_info(comp, &info) == false);
		info.version_major = 0;
		info.version_minor = 0xffff;
		CHECK(rohc_comp_get_general_info(comp, &info) == false);
		info.version_minor = 0;
		CHECK(rohc_comp_get_general_info(comp, &info) == true);
	}

	/* rohc_comp_get_state_descr() */
	CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_IR), "IR") == 0);
	CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_FO), "FO") == 0);
	CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_SO), "SO") == 0);
	CHECK(strcmp(rohc_comp_get_state_descr(ROHC_COMP_STATE_SO + 1), "no description") == 0);

	/* rohc_comp_force_contexts_reinit() with some contexts init'ed */
	CHECK(rohc_comp_force_contexts_reinit(comp) == true);

	/* rohc_comp_set_features */
	CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_COMPAT_1_6_x) == false);
	CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_NO_IP_CHECKSUMS) == true);
	CHECK(rohc_comp_set_features(comp, ROHC_COMP_FEATURE_NONE) == true);

	/* rohc_comp_deliver_feedback2() */
	{
		const struct rohc_ts ts = { .sec = 0, .nsec = 0 };
		uint8_t buf[] = { 0xf4, 0x20, 0x01, 0x11, 0x39 };
		struct rohc_buf pkt = rohc_buf_init_full(buf, 5, ts);

		CHECK(rohc_comp_deliver_feedback2(NULL, pkt) == false);
		pkt.len = 0; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == true);
		pkt.len = 1; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false);
		pkt.len = 2; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false);
		pkt.len = 3; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false);
		pkt.len = 4; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == false);
		pkt.len = 5; CHECK(rohc_comp_deliver_feedback2(comp, pkt) == true);
	}

	/* several functions with some packets already compressed */
	{
		rohc_trace_callback2_t fct = (rohc_trace_callback2_t) NULL;
		CHECK(rohc_comp_set_traces_cb2(comp, fct, comp) == false);

		CHECK(rohc_comp_set_wlsb_window_width(comp, 16) == false);

		CHECK(rohc_comp_set_periodic_refreshes(comp, 10, 5) == false);

		CHECK(rohc_comp_set_list_trans_nr(comp, 5) == false);
	}

	/* rohc_comp_free() */
	rohc_comp_free(NULL);
	rohc_comp_free(comp);

	/* test succeeds */
	trace(verbose, "all tests are successful\n");
	is_failure = 0;

error:
	return is_failure;
}


/**
 * @brief Fake random callback: always send 0
 *
 * @param comp          The compressor
 * @param user_context  Private data
 * @return              Always 0
 */
static int random_cb(const struct rohc_comp *const comp __attribute__((unused)),
                     void *const user_context __attribute__((unused)))
{
	return 0; /* fake */
}
Пример #3
0
/**
 * @brief Test the ROHC library with a flow of ROHC packets
 *
 * @param filename       The name of the PCAP file that contains the ROHC packets
 * @param failure_start  The first packet that shall fail to be decompressed
 * @return               0 in case of success,
 *                       1 in case of failure
 */
static int test_decomp(const char *const filename,
                       const size_t failure_start)
{
	char errbuf[PCAP_ERRBUF_SIZE];
	pcap_t *handle;
	int link_layer_type;
	int link_len;
	struct pcap_pkthdr header;
	unsigned char *packet;
	struct rohc_decomp *decomp;
	unsigned int counter;
	int is_failure = 1;

	/* open the source dump file */
	handle = pcap_open_offline(filename, errbuf);
	if(handle == NULL)
	{
		fprintf(stderr, "failed to open the source pcap file: %s\n", errbuf);
		goto error;
	}

	/* link layer in the source dump must be Ethernet */
	link_layer_type = pcap_datalink(handle);
	if(link_layer_type != DLT_EN10MB &&
	   link_layer_type != DLT_LINUX_SLL &&
	   link_layer_type != DLT_RAW)
	{
		fprintf(stderr, "link layer type %d not supported in source dump (supported = "
		       "%d, %d, %d)\n", link_layer_type, DLT_EN10MB, DLT_LINUX_SLL,
		       DLT_RAW);
		goto close_input;
	}

	if(link_layer_type == DLT_EN10MB)
	{
		link_len = ETHER_HDR_LEN;
	}
	else if(link_layer_type == DLT_LINUX_SLL)
	{
		link_len = LINUX_COOKED_HDR_LEN;
	}
	else /* DLT_RAW */
	{
		link_len = 0;
	}

	/* create the decompressor */
	decomp = rohc_decomp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX, ROHC_O_MODE);
	if(decomp == NULL)
	{
		fprintf(stderr, "cannot create the decompressor\n");
		goto close_input;
	}

	/* set the callback for traces */
	if(!rohc_decomp_set_traces_cb2(decomp, print_rohc_traces, NULL))
	{
		fprintf(stderr, "failed to set trace callback\n");
		goto destroy_decomp;
	}

	/* enable decompression profiles */
	if(!rohc_decomp_enable_profiles(decomp, ROHC_PROFILE_UNCOMPRESSED,
	                                ROHC_PROFILE_UDP, ROHC_PROFILE_IP,
	                                ROHC_PROFILE_UDPLITE, ROHC_PROFILE_RTP,
	                                ROHC_PROFILE_ESP, ROHC_PROFILE_TCP, -1))
	{
		fprintf(stderr, "failed to enable the decompression profiles\n");
		goto destroy_decomp;
	}

	/* for each packet in the dump */
	counter = 0;
	while((packet = (unsigned char *) pcap_next(handle, &header)) != NULL)
	{
		const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 };
		struct rohc_buf rohc_packet =
			rohc_buf_init_full(packet, header.caplen, arrival_time);
		uint8_t ip_buffer[MAX_ROHC_SIZE];
		struct rohc_buf ip_packet =
			rohc_buf_init_empty(ip_buffer, MAX_ROHC_SIZE);
		uint8_t rcvd_feedback_buf[6];
		struct rohc_buf rcvd_feedback = rohc_buf_init_empty(rcvd_feedback_buf, 6);
		uint8_t send_feedback_buf[6];
		struct rohc_buf send_feedback = rohc_buf_init_empty(send_feedback_buf, 6);
		rohc_status_t status;

		counter++;

		/* check Ethernet frame length */
		if(header.len < link_len || header.len != header.caplen)
		{
			fprintf(stderr, "bad PCAP packet (len = %d, caplen = %d)\n",
			       header.len, header.caplen);
			goto destroy_decomp;
		}

		/* skip the link layer header */
		rohc_buf_pull(&rohc_packet, link_len);

		fprintf(stderr, "decompress malformed packet #%u:\n", counter);

		/* decompress the ROHC packet */
		status = rohc_decompress3(decomp, rohc_packet, &ip_packet, &rcvd_feedback,
		                          &send_feedback);
		fprintf(stderr, "\tdecompression status: %s\n", rohc_strerror(status));
		if(status == ROHC_STATUS_OK)
		{
			if(counter >= failure_start)
			{
				fprintf(stderr, "\tunexpected successful decompression\n");
				goto destroy_decomp;
			}
			else
			{
				fprintf(stderr, "\texpected successful decompression\n");
			}
		}
		else
		{
			if(counter >= failure_start)
			{
				fprintf(stderr, "\texpected decompression failure\n");
			}
			else
			{
				fprintf(stderr, "\tunexpected decompression failure\n");
				goto destroy_decomp;
			}
		}

		/* be ready to get the next feedback to send */
		rohc_buf_reset(&send_feedback);
	}

	is_failure = 0;

destroy_decomp:
	rohc_decomp_free(decomp);
close_input:
	pcap_close(handle);
error:
	return is_failure;
}


/**
 * @brief Callback to print traces of the ROHC library
 *
 * @param priv_ctxt  An optional private context, may be NULL
 * @param level      The priority level of the trace
 * @param entity     The entity that emitted the trace among:
 *                    \li ROHC_TRACE_COMP
 *                    \li ROHC_TRACE_DECOMP
 * @param profile    The ID of the ROHC compression/decompression profile
 *                   the trace is related to
 * @param format     The format string of the trace
 */
static void print_rohc_traces(void *const priv_ctxt,
                              const rohc_trace_level_t level,
                              const rohc_trace_entity_t entity,
                              const int profile,
                              const char *const format,
                              ...)
{
	const char *level_descrs[] =
	{
		[ROHC_TRACE_DEBUG]   = "DEBUG",
		[ROHC_TRACE_INFO]    = "INFO",
		[ROHC_TRACE_WARNING] = "WARNING",
		[ROHC_TRACE_ERROR]   = "ERROR"
	};

	if(level >= ROHC_TRACE_WARNING || is_verbose)
	{
		va_list args;
		fprintf(stdout, "[%s] ", level_descrs[level]);
		va_start(args, format);
		vfprintf(stdout, format, args);
		va_end(args);
	}
}
Пример #4
0
/**
 * @brief Decompress one ROHC packet and compare the result with a reference
 *
 * @param decomp           The decompressor to use to decompress the ROHC packet
 * @param num_packet       A number affected to the IP packet to compress/decompress
 * @param header           The PCAP header for the packet
 * @param packet           The packet to compress/decompress (link layer included)
 * @param link_len_src     The length of the link layer header before IP data
 * @param cmp_packet       The ROHC packet for comparison purpose
 * @param cmp_size         The size of the ROHC packet used for comparison
 *                         purpose
 * @param link_len_cmp     The length of the link layer header before ROHC data
 * @return                 0 if the process is successful
 *                         -1 if ROHC packet is malformed
 *                         -2 if decompression fails
 *                         -3 if the decompressed packet doesn't match the
 *                            reference
 */
static int test_decomp_one(struct rohc_decomp *const decomp,
                           const size_t num_packet,
                           const struct pcap_pkthdr header,
                           const unsigned char *const packet,
                           const size_t link_len_src,
                           const unsigned char *const cmp_packet,
                           const size_t cmp_size,
                           const size_t link_len_cmp)
{
	const struct rohc_ts arrival_time = { .sec = 0, .nsec = 0 };
	struct rohc_buf rohc_packet =
		rohc_buf_init_full((uint8_t *) packet, header.caplen, arrival_time);
	uint8_t uncomp_buffer[MAX_ROHC_SIZE];
	struct rohc_buf uncomp_packet =
		rohc_buf_init_empty(uncomp_buffer, MAX_ROHC_SIZE);
	rohc_status_t status;

	printf("=== decompressor packet #%zu:\n", num_packet);

	/* check Ethernet frame length */
	if(header.len <= link_len_src || header.len != header.caplen)
	{
		fprintf(stderr, "bad PCAP packet (len = %u, caplen = %u)\n",
		        header.len, header.caplen);
		goto error_fmt;
	}
	if(cmp_packet != NULL && cmp_size <= link_len_cmp)
	{
		fprintf(stderr, "bad comparison packet: too small for link header\n");
		goto error_fmt;
	}

	/* skip the link layer header */
	rohc_buf_pull(&rohc_packet, link_len_src);

	/* decompress the ROHC packet */
	printf("=== ROHC decompression: start\n");
	status = rohc_decompress3(decomp, rohc_packet, &uncomp_packet, NULL, NULL);
	if(status != ROHC_STATUS_OK)
	{
		size_t i;

		printf("=== ROHC decompression: failure\n");
		printf("=== original %zu-byte compressed packet:\n", rohc_packet.len);
		for(i = 0; i < rohc_packet.len; i++)
		{
			if(i > 0 && (i % 16) == 0)
			{
				printf("\n");
			}
			else if(i > 0 && (i % 8) == 0)
			{
				printf("  ");
			}
			printf("%02x ", rohc_buf_byte_at(rohc_packet, i));
		}
		printf("\n\n");
		goto error_decomp;
	}
	printf("=== ROHC decompression: success\n");

	/* compare the decompressed packet with the original one */
	printf("=== uncompressed packet comparison: start\n");
	if(cmp_packet && !compare_packets(rohc_buf_data(uncomp_packet),
	                                  uncomp_packet.len,
	                                  cmp_packet + link_len_cmp,
	                                  cmp_size - link_len_cmp))
	{
		printf("=== uncompressed packet comparison: failure\n");
		printf("\n");
		goto error_cmp;
	}
	printf("=== uncompressed packet comparison: success\n");

	printf("\n");
	return 0;

error_fmt:
	return -1;
error_decomp:
	return -2;
error_cmp:
	return -3;
}


/**
 * @brief Test the ROHC library decompression with a flow of ROHC packets
 *        generated by another ROHC implementation
 *
 * @param cid_type             The type of CIDs the compressor shall use
 * @param wlsb_width           The width of the WLSB window to use
 * @param max_contexts         The maximum number of ROHC contexts to use
 * @param src_filename         The name of the PCAP file that contains the
 *                             ROHC packets to decompress
 * @param cmp_filename         The name of the PCAP file that contains the
 *                             uncompressed packets used for comparison
 * @return                     0 in case of success,
 *                             1 in case of failure,
 *                             77 if test is skipped
 */
static int test_decomp_all(const rohc_cid_type_t cid_type,
                           const size_t wlsb_width,
                           const size_t max_contexts,
                           const char *const src_filename,
                           const char *const cmp_filename)
{
	char errbuf[PCAP_ERRBUF_SIZE];

	pcap_t *handle;
	struct pcap_pkthdr header;
	int link_layer_type_src;
	size_t link_len_src;
	unsigned char *packet;

	pcap_t *cmp_handle;
	struct pcap_pkthdr cmp_header;
	int link_layer_type_cmp;
	size_t link_len_cmp = 0;
	unsigned char *cmp_packet;

	size_t counter;

	struct rohc_decomp *decomp;

	size_t nb_bad = 0;
	size_t nb_ok = 0;
	size_t err_decomp = 0;
	size_t nb_ref = 0;

	int status = 1;
	int ret;

	printf("=== initialization:\n");

	/* open the source dump file */
	handle = pcap_open_offline(src_filename, errbuf);
	if(handle == NULL)
	{
		printf("failed to open the source pcap file: %s\n", errbuf);
		goto error;
	}

	/* link layer in the source dump must be Ethernet */
	link_layer_type_src = pcap_datalink(handle);
	if(link_layer_type_src != DLT_EN10MB &&
	   link_layer_type_src != DLT_LINUX_SLL &&
	   link_layer_type_src != DLT_RAW &&
	   link_layer_type_src != DLT_NULL)
	{
		printf("link layer type %d not supported in source dump (supported = "
		       "%d, %d, %d, %d)\n", link_layer_type_src, DLT_EN10MB,
		       DLT_LINUX_SLL, DLT_RAW, DLT_NULL);
		status = 77; /* skip test */
		goto close_input;
	}

	if(link_layer_type_src == DLT_EN10MB)
	{
		link_len_src = ETHER_HDR_LEN;
	}
	else if(link_layer_type_src == DLT_LINUX_SLL)
	{
		link_len_src = LINUX_COOKED_HDR_LEN;
	}
	else if(link_layer_type_src == DLT_NULL)
	{
		link_len_src = BSD_LOOPBACK_HDR_LEN;
	}
	else /* DLT_RAW */
	{
		link_len_src = 0;
	}

	/* open the uncompressed comparison dump file if asked */
	if(cmp_filename != NULL)
	{
		cmp_handle = pcap_open_offline(cmp_filename, errbuf);
		if(cmp_handle == NULL)
		{
			printf("failed to open the comparison pcap file: %s\n", errbuf);
			goto close_input;
		}

		/* link layer in the rohc_comparison dump must be Ethernet */
		link_layer_type_cmp = pcap_datalink(cmp_handle);
		if(link_layer_type_cmp != DLT_EN10MB &&
		   link_layer_type_cmp != DLT_LINUX_SLL &&
		   link_layer_type_cmp != DLT_RAW &&
		   link_layer_type_cmp != DLT_NULL)
		{
			printf("link layer type %d not supported in comparision dump "
			       "(supported = %d, %d, %d, %d)\n", link_layer_type_cmp,
			       DLT_EN10MB, DLT_LINUX_SLL, DLT_RAW, DLT_NULL);
			status = 77; /* skip test */
			goto close_comparison;
		}

		if(link_layer_type_cmp == DLT_EN10MB)
		{
			link_len_cmp = ETHER_HDR_LEN;
		}
		else if(link_layer_type_cmp == DLT_LINUX_SLL)
		{
			link_len_cmp = LINUX_COOKED_HDR_LEN;
		}
		else if(link_layer_type_cmp == DLT_NULL)
		{
			link_len_cmp = BSD_LOOPBACK_HDR_LEN;
		}
		else /* DLT_RAW */
		{
			link_len_cmp = 0;
		}
	}
	else
	{
		cmp_handle = NULL;
	}

	/* create the decompressor */
	decomp = create_decompressor(cid_type, max_contexts);
	if(decomp == NULL)
	{
		printf("failed to create the decompressor 1\n");
		goto close_comparison;
	}

	printf("\n");

	/* for each ROHC packet in the dump */
	counter = 0;
	while((packet = (unsigned char *) pcap_next(handle, &header)) != NULL)
	{
		counter++;

		/* get next uncompressed packet from the comparison dump file if asked */
		if(cmp_handle != NULL)
		{
			cmp_packet = (unsigned char *) pcap_next(cmp_handle, &cmp_header);
		}
		else
		{
			cmp_packet = NULL;
			cmp_header.caplen = 0;
		}

		/* decompress one packet of the flow and compare it with the given
		 * reference */
		ret = test_decomp_one(decomp, counter,
		                      header, packet, link_len_src,
		                      cmp_packet, cmp_header.caplen, link_len_cmp);
		if(ret == 0)
		{
			nb_ok++;
		}
		else if(ret == -2)
		{
			err_decomp++;
		}
		else if(ret != -3)
		{
			nb_ref++;
		}
		else
		{
			nb_bad++;
		}
	}

	/* show the compression/decompression results */
	printf("=== summary:\n");
	printf("===\tpackets_processed:    %zu\n", counter);
	printf("===\tmalformed:            %zu\n", nb_bad);
	printf("===\tdecompression_failed: %zu\n", err_decomp);
	printf("===\tmatches:              %zu\n", nb_ok);
	printf("\n");

	/* show some info/stats about the decompressor */
	if(!show_rohc_decomp_stats(decomp))
	{
		fprintf(stderr, "failed to dump ROHC decompressor stats\n");
		goto free_decomp;
	}
	printf("\n");

	/* destroy the compressors and decompressors */
	printf("=== shutdown:\n");
	if(err_decomp == 0 && nb_bad == 0 && nb_ref == 0 && nb_ok == counter)
	{
		/* test is successful */
		status = 0;
	}

free_decomp:
	rohc_decomp_free(decomp);
close_comparison:
	if(cmp_handle != NULL)
	{
		pcap_close(cmp_handle);
	}
close_input:
	pcap_close(handle);
error:
	return status;
}