Exemplo n.º 1
0
int convergence_layer_send_bundle(struct transmit_ticket_t * ticket)
{
	struct bundle_t *bundle = NULL;
	uint16_t length = 0;
	uint8_t * buffer = NULL;
	uint8_t buffer_length = 0;
#if CONVERGENCE_LAYER_SEGMENTATION
	int ret;
	int segments;
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Sending bundle %lu to %u.%u with ticket %p", ticket->bundle_number, ticket->neighbour.u8[0], ticket->neighbour.u8[1], ticket);

	if( !(ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART) ) {
		/* Read the bundle from storage, if it is not in memory */
		if( ticket->bundle == NULL ) {
			ticket->bundle = BUNDLE_STORAGE.read_bundle(ticket->bundle_number);
			if( ticket->bundle == NULL ) {
				LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Unable to read bundle %lu", ticket->bundle_number);
				/* FIXME: Notify somebody */
				return -1;
			}
		}

		/* Get our bundle struct and check the pointer */
		bundle = (struct bundle_t *) MMEM_PTR(ticket->bundle);
		if( bundle == NULL ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Invalid bundle pointer for bundle %lu", ticket->bundle_number);
			bundle_decrement(ticket->bundle);
			ticket->bundle = NULL;
			return -1;
		}

		/* Check if bundle has expired */
		if( bundle_ageing_is_expired(ticket->bundle) ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_INF, "Bundle %lu has expired, not sending it", ticket->bundle_number);

			/* Bundle is expired */
			bundle_decrement(ticket->bundle);

			/* Tell storage to delete - it will take care of the rest */
			BUNDLE_STORAGE.del_bundle(ticket->bundle_number, REASON_LIFETIME_EXPIRED);

			return -1;
		}
	}

	/* Get the outgoing network buffer */
	buffer = dtn_network_get_buffer();
	if( buffer == NULL ) {
		bundle_decrement(ticket->bundle);
		ticket->bundle = NULL;
		return -1;
	}

	/* Get the buffer length */
	buffer_length = dtn_network_get_buffer_length();

#if CONVERGENCE_LAYER_SEGMENTATION
	/* We have to use a heuristic to estimate if the bundle will be a multipart bundle */
	if( ticket->bundle->size > CONVERGENCE_LAYER_MAX_LENGTH && !(ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART) ) {
		/* This is a bundle for multiple segments and we have our first look at it */
		ticket->flags |= CONVERGENCE_LAYER_QUEUE_MULTIPART;

		LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Encoding multipart bundle %lu", ticket->bundle_number);

		/* Now allocate a buffer to serialize the bundle
		 * The size is a rough estimation here and will be reallocated later on */
		ret = mmem_alloc(&ticket->buffer, ticket->bundle->size);

		if( ret < 1 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, not enough memory for %u bytes", ticket->bundle_number, ticket->bundle->size);
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* Encode the bundle into our temporary buffer */
		length = bundle_encode_bundle(ticket->bundle, (uint8_t *) MMEM_PTR(&ticket->buffer), ticket->buffer.size);

		if( length < 0 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, error occured", ticket->bundle_number);
			mmem_free(&ticket->buffer);
			ticket->buffer.ptr = NULL;
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* Decrease memory size to what is actually needed */
		ret = mmem_realloc(&ticket->buffer, length);

		if( ret < 1 ) {
			LOG(LOGD_DTN, LOG_CL, LOGL_ERR, "Multipart bundle %lu could not be encoded, realloc failed", ticket->bundle_number);
			mmem_free(&ticket->buffer);
			ticket->buffer.ptr = NULL;
			ticket->flags &= ~CONVERGENCE_LAYER_QUEUE_MULTIPART;
			return -1;
		}

		/* We do not need the original bundle anymore */
		bundle_decrement(ticket->bundle);
		ticket->bundle = NULL;

		/* Initialize the state for this bundle */
		ticket->offset_sent = 0;
		ticket->offset_acked = 0;
		ticket->sequence_number = outgoing_sequence_number;

		/* Calculate the number of segments we will need */
		segments = (length + 0.5 * CONVERGENCE_LAYER_MAX_LENGTH) / CONVERGENCE_LAYER_MAX_LENGTH;

		/* And reserve the sequence number space for this bundle to allow for consequtive numbers */
		outgoing_sequence_number = (outgoing_sequence_number + segments) % 4;
	}

	/* Initialize the header field */
	buffer[0] = CONVERGENCE_LAYER_TYPE_DATA & CONVERGENCE_LAYER_MASK_TYPE;

	/* Check if this is a multipart bundle */
	if( ticket->flags & CONVERGENCE_LAYER_QUEUE_MULTIPART ) {
		/* Calculate the remaining length */
		length = ticket->buffer.size - ticket->offset_acked;

		/* Is it possible, that we send a single-part bundle here because the heuristic
		 * from above failed. So be it.
		 */
		if( length <= CONVERGENCE_LAYER_MAX_LENGTH && ticket->offset_acked == 0 ) {
			/* One bundle per segment, standard flags */
			buffer[0] |= (CONVERGENCE_LAYER_FLAGS_FIRST | CONVERGENCE_LAYER_FLAGS_LAST) & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( ticket->offset_acked == 0 ) {
			/* First segment of a bundle */
			buffer[0] |= CONVERGENCE_LAYER_FLAGS_FIRST & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( length <= CONVERGENCE_LAYER_MAX_LENGTH ) {
			/* Last segment of a bundle */
			buffer[0] |= CONVERGENCE_LAYER_FLAGS_LAST & CONVERGENCE_LAYER_MASK_FLAGS;
		} else if( length > CONVERGENCE_LAYER_MAX_LENGTH) {
			/* A segment in the middle of a bundle */
			buffer[0] &= ~CONVERGENCE_LAYER_MASK_FLAGS;
		}

		/* one byte for the CL header */
		length += 1;

		if( length > CONVERGENCE_LAYER_MAX_LENGTH ) {
			length = CONVERGENCE_LAYER_MAX_LENGTH;
		}

		if( length > buffer_length ) {
			length = buffer_length;
		}

		/* Copy the subset of the bundle into the buffer */
		memcpy(buffer + 1, ((uint8_t *) MMEM_PTR(&ticket->buffer)) + ticket->offset_acked, length - 1);

		/* Every segment so far has been acked */
		if( ticket->offset_sent == ticket->offset_acked ) {
			/* It is the first time that we are sending this segment */
			ticket->offset_sent += length - 1;

			/* Increment the sequence number for the new segment, except for the first segment */
			if( ticket->offset_sent != 0 ) {
				ticket->sequence_number = (ticket->sequence_number + 1) % 4;
			}
		}
	} else {
#endif /* CONVERGENCE_LAYER_SEGMENTATION */
		/* one byte for the CL header */
		length = 1;

		/* Initialize the header field */
		buffer[0] = CONVERGENCE_LAYER_TYPE_DATA & CONVERGENCE_LAYER_MASK_TYPE;

		/* One bundle per segment, standard flags */
		buffer[0] |= (CONVERGENCE_LAYER_FLAGS_FIRST | CONVERGENCE_LAYER_FLAGS_LAST) & CONVERGENCE_LAYER_MASK_FLAGS;

		/* Encode the bundle into the buffer */
		length += bundle_encode_bundle(ticket->bundle, buffer + 1, buffer_length - 1);

		/* Initialize the sequence number */
		ticket->sequence_number = outgoing_sequence_number;
		outgoing_sequence_number = (outgoing_sequence_number + 1) % 4;
#if CONVERGENCE_LAYER_SEGMENTATION
	}
#endif /* CONVERGENCE_LAYER_SEGMENTATION */

	/* Put the sequence number for this bundle into the outgoing header */
	buffer[0] |= (ticket->sequence_number << 2) & CONVERGENCE_LAYER_MASK_SEQNO;

	/* Flag the bundle as being in transit now */
	ticket->flags |= CONVERGENCE_LAYER_QUEUE_IN_TRANSIT;

	/* Now we are transmitting */
	convergence_layer_transmitting = 1;

	/* This neighbour is blocked, until we have received the App Layer ACK or NACK */
	convergence_layer_set_blocked(&ticket->neighbour);

	/* And send it out */
	dtn_network_send(&ticket->neighbour, length, (void *) ticket);

	return 1;
}
Exemplo n.º 2
0
PROCESS_THREAD(test_process, ev, data)
{
    static int n;
    static int i;
    static int errors = 0;
    static struct etimer timer;
    static uint32_t time_start, time_stop;
    uint8_t buffer[128];
    int bundle_length;
    struct mmem * bundle_original = NULL;
    struct mmem * bundle_restored = NULL;
    struct mmem * bundle_spare = NULL;
    uint32_t bundle_number;
    uint32_t bundle_number_spare;

    PROCESS_BEGIN();

    PROCESS_PAUSE();

    profiling_init();
    profiling_start();

    // Wait again
    etimer_set(&timer, CLOCK_SECOND);
    PROCESS_WAIT_UNTIL(etimer_expired(&timer));

    /* Profile initialization separately */
    profiling_stop();
    watchdog_stop();
    profiling_report("init", 0);
    watchdog_start();
    printf("Init done, starting test using %s storage\n", BUNDLE_STORAGE.name);

    profiling_init();
    profiling_start();

    // Measure the current time
    time_start = test_precise_timestamp();

    for(i=0; i<=1; i++) {
        struct mmem bla;
        if( i > 0 ) {
            mmem_alloc(&bla, 1);
        }

        printf("Serializing and deserializing bundle...\n");
        if( my_create_bundle(0, &bundle_number, 3600) ) {
            printf("\tBundle created successfully \n");
        } else {
            printf("\tBundle could not be created \n");
            errors ++;
        }

        printf("Serializing and deserializing bundle...\n");
        if( my_create_bundle(1, &bundle_number_spare, 3600) ) {
            printf("\tSpare Bundle created successfully \n");
        } else {
            printf("\tSpare Bundle could not be created \n");
            errors ++;
        }

        bundle_original = BUNDLE_STORAGE.read_bundle(bundle_number);
        if( bundle_original == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        bundle_spare = BUNDLE_STORAGE.read_bundle(bundle_number_spare);
        if( bundle_spare == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        // Fake timing information in the bundle to make verify successful
        struct bundle_t * bundle_original_bundle = (struct bundle_t *) MMEM_PTR(bundle_original);
        bundle_original_bundle->aeb_value_ms = 54;
        bundle_original_bundle->rec_time = clock_time();

        // Serialize the bundle
        memset(buffer, 0, 128);
        bundle_length = bundle_encode_bundle(bundle_original, buffer, 128);
        if( bundle_length < 0 ) {
            printf("SERIALIZE: fail\n");
            errors ++;
        }

        n = my_static_compare(buffer, bundle_length);
        if( n > 0 ) {
            printf("COMPARE: fail\n");
            errors += n;
        }

        // Deserialize it
        bundle_restored = bundle_recover_bundle(buffer, bundle_length);
        if( bundle_restored == NULL ) {
            printf("DESERIALIZE: unable to recover\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_restored);
        if( n == 0 ) {
            printf("\tBundle serialized and deserialized successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        // Dellocate memory
        bundle_decrement(bundle_restored);
        bundle_restored = NULL;

        bundle_decrement(bundle_original);
        bundle_original = NULL;

        bundle_decrement(bundle_spare);
        bundle_spare = NULL;

        memset(buffer, 0, 128);

        // Delete bundle from storage
        n = BUNDLE_STORAGE.del_bundle(bundle_number, REASON_DELIVERED);
        if( n ) {
            printf("\tBundle deleted successfully\n");
        } else {
            printf("\tBundle could not be deleted\n");
            errors++;
        }


        printf("Comparing static bundle...\n");
        if( my_create_bundle(0, &bundle_number, 3600) ) {
            printf("\tReference Bundle created successfully \n");
        } else {
            printf("\ttReference Bundle could not be created \n");
            errors ++;
        }

        bundle_original = BUNDLE_STORAGE.read_bundle(bundle_number);
        if( bundle_original == NULL ) {
            printf("VERIFY: MMEM ptr is invalid\n");
            errors ++;
        }

        // Deserialize it
        bundle_restored = bundle_recover_bundle(static_compare_bundle, sizeof(static_compare_bundle));
        if( bundle_restored == NULL ) {
            printf("DESERIALIZE: unable to recover static bundle\n");
            errors ++;
        }

        // Deserialize it one more time
        bundle_spare = bundle_recover_bundle(static_compare_bundle, sizeof(static_compare_bundle));
        if( bundle_spare == NULL ) {
            printf("DESERIALIZE: unable to recover static bundle\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_restored);
        if( n == 0 ) {
            printf("\tStatic Bundle verified successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        n = my_compare_bundles(bundle_original, bundle_spare);
        if( n == 0 ) {
            printf("\tStatic Bundle verified successfully\n");
        } else {
            printf("COMPARE: differences\n");
            errors ++;
        }

        // Dellocate memory
        bundle_decrement(bundle_restored);
        bundle_restored = NULL;

        bundle_decrement(bundle_original);
        bundle_original = NULL;

        bundle_decrement(bundle_spare);
        bundle_spare = NULL;
    }

    time_stop = test_precise_timestamp();

    watchdog_stop();
    profiling_report("serializer", 0);

    TEST_REPORT("No of errors", errors, 1, "errors");
    TEST_REPORT("Duration", time_stop-time_start, CLOCK_SECOND, "s");

    if( errors > 0 ) {
        TEST_FAIL("More than 0 errors occured");
    } else {
        TEST_PASS();
    }

    PROCESS_END();
}