int convergence_layer_free_transmit_ticket(struct transmit_ticket_t * ticket) { /* Remove our reference to the bundle */ if( ticket->bundle != NULL ) { bundle_decrement(ticket->bundle); ticket->bundle = NULL; } #if CONVERGENCE_LAYER_SEGMENTATION /* Also free MMEM if it was allocate to serialize the bundle */ if( ticket->buffer.ptr != NULL ) { mmem_free(&ticket->buffer); ticket->buffer.ptr = NULL; } #endif /* CONVERGENCE_LAYER_SEGMENTATION */ LOG(LOGD_DTN, LOG_CL, LOGL_DBG, "Freeing ticket %p", ticket); /* Only dequeue bundles that have been in the queue */ if( (ticket->flags & CONVERGENCE_LAYER_QUEUE_ACTIVE) || (ticket->flags & CONVERGENCE_LAYER_QUEUE_DONE) || (ticket->flags & CONVERGENCE_LAYER_QUEUE_FAIL) ) { convergence_layer_queue--; } /* Count the used slots */ convergence_layer_slots--; /* Remove ticket from list and free memory */ list_remove(transmission_ticket_list, ticket); memset(ticket, 0, sizeof(struct transmit_ticket_t)); memb_free(&transmission_ticket_mem, ticket); return 1; }
void mem_heap_free(mem_ptr_t *mem_ptr) { if (mem_ptr) { mmem_free(&mem_ptr->mmem_ptr); mem_ptr->alloc = false; } }
/** * \brief deletes bundle from list * \param bundle_number bundle number of the bundle */ void routing_chain_delete_bundle(uint32_t bundle_number) { struct routing_list_entry_t * n = NULL; struct routing_entry_t * entry = NULL; LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "flood_del_bundle for bundle %lu", bundle_number); // Find the bundle in our internal storage for( n = list_head(routing_list); n != NULL; n = list_item_next(n) ) { entry = (struct routing_entry_t *) MMEM_PTR(&n->entry); if( entry->bundle_number == bundle_number ) { break; } } if( n == NULL ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "flood_del_bundle for bundle %lu that we do not know", bundle_number); return; } memset(MMEM_PTR(&n->entry), 0, sizeof(struct routing_entry_t)); // Free up the memory for the struct mmem_free(&n->entry); list_remove(routing_list, n); memset(n, 0, sizeof(struct routing_list_entry_t)); // And also free the memory for the list entry memb_free(&routing_mem, n); }
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; }
/** * \brief Adds a new bundle to the list of bundles * \param bundle_number bundle number of the bundle * \return >0 on success, <0 on error */ int routing_chain_new_bundle(uint32_t * bundle_number) { struct routing_list_entry_t * n = NULL; struct routing_entry_t * entry = NULL; struct mmem * bundlemem = NULL; struct bundle_t * bundle = NULL; LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "agent announces bundle %lu", *bundle_number); // Let us see, if we know this bundle already for( n = list_head(routing_list); n != NULL; n = list_item_next(n) ) { entry = (struct routing_entry_t *) MMEM_PTR(&n->entry); if( entry->bundle_number == *bundle_number ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "agent announces bundle %lu that is already known", *bundle_number); return -1; } } // Notify statistics statistics_bundle_incoming(1); // Now allocate new memory for the list entry n = memb_alloc(&routing_mem); if( n == NULL ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "cannot allocate list entry for bundle, please increase BUNDLE_STORAGE_SIZE"); return -1; } memset(n, 0, sizeof(struct routing_list_entry_t)); // Now allocate new MMEM memory for the struct in the list if( !mmem_alloc(&n->entry, sizeof(struct routing_entry_t)) ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "cannot allocate routing struct for bundle, MMEM is full"); memb_free(&routing_mem, n); return -1; } // Now go and request the bundle from storage bundlemem = BUNDLE_STORAGE.read_bundle(*bundle_number); if( bundlemem == NULL ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "unable to read bundle %lu", *bundle_number); mmem_free(&n->entry); memb_free(&routing_mem, n); return -1; } // Get our bundle struct and check the pointer bundle = (struct bundle_t *) MMEM_PTR(bundlemem); if( bundle == NULL ) { LOG(LOGD_DTN, LOG_ROUTE, LOGL_ERR, "invalid bundle pointer for bundle %lu", *bundle_number); mmem_free(&n->entry); memb_free(&routing_mem, n); bundle_decrement(bundlemem); return -1; } // Now we have our entry // We have to get the pointer AFTER getting the bundle from storage, because accessing the // storage may change the MMEM structure and thus the pointers! entry = (struct routing_entry_t *) MMEM_PTR(&n->entry); memset(entry, 0, sizeof(struct routing_entry_t)); // Nothing can go wrong anymore, add the (surrounding) struct to the list list_add(routing_list, n); /* Here we decide if a bundle is to be delivered locally and/or forwarded */ if( bundle->dst_node == dtn_node_id ) { /* This bundle is for our node_id, deliver locally */ LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for local"); entry->flags |= ROUTING_FLAG_LOCAL; } else { /* This bundle is not (directly) for us and will be forwarded */ LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for forward"); entry->flags |= ROUTING_FLAG_FORWARD; } if( !(bundle->flags & BUNDLE_FLAG_SINGLETON) ) { /* Bundle is not Singleton, so forward it in any case */ LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for forward"); entry->flags |= ROUTING_FLAG_FORWARD; } if( registration_is_local(bundle->dst_srv, bundle->dst_node) && bundle->dst_node != dtn_node_id) { /* Bundle is for a local registration, so deliver it locally */ LOG(LOGD_DTN, LOG_ROUTE, LOGL_DBG, "bundle is for local and forward"); entry->flags |= ROUTING_FLAG_LOCAL; entry->flags |= ROUTING_FLAG_FORWARD; } // Now copy the necessary attributes from the bundle entry->bundle_number = *bundle_number; bundle_get_attr(bundlemem, DEST_NODE, &entry->destination_node); bundle_get_attr(bundlemem, SRC_NODE, &entry->source_node); linkaddr_copy(&entry->received_from_node, &bundle->msrc); // Now that we have the bundle, we do not need the allocated memory anymore bundle_decrement(bundlemem); bundlemem = NULL; bundle = NULL; // Schedule to deliver and forward the bundle routing_chain_schedule_resubmission(); // We do not have a failure here, so it must be a success return 1; }