Contiki 2.5
dispatching.c
Go to the documentation of this file.
1 /**
2  * \addtogroup bprocess
3  * @{
4  */
5 
6 /**
7  * \file
8  * \author Georg von Zengen <vonzeng@ibr.cs.tu-bs.de>
9  * \author Daniel Willmann <daniel@totalueberwachung.de>
10  * \author Wolf-Bastian Poettner <poettner@ibr.cs.tu-bs.de>
11  */
12 
13 #include <stdint.h>
14 #include <string.h>
15 #include <stdlib.h>
16 
17 #include "lib/list.h"
18 #include "logging.h"
19 
20 #include "agent.h"
21 #include "bundle.h"
22 #include "registration.h"
23 #include "sdnv.h"
24 #include "administrative_record.h"
25 #include "custody.h"
26 #include "delivery.h"
27 #include "statusreport.h"
28 #include "storage.h"
29 #include "hash.h"
30 #include "redundancy.h"
31 
32 #include "dispatching.h"
33 
34 /**
35  * \brief This function checks, whether an incoming admin record is a bundle delivery report. If so, the corresponding bundle is deleted from storage
36  * \param bundlemem Pointer to the MMEM struct containing the bundle
37  * \return 1 on success, < 0 otherwise
38  */
39 int dispatching_check_report(struct mmem * bundlemem) {
40  struct bundle_t * bundle = NULL;
41  struct bundle_block_t * payload_block = NULL;
42  status_report_t report;
43  int ret = 0;
44  uint32_t bundle_number = 0;
45 
46  /* Get the bundle */
47  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
48 
49  /* Return on invalid pointer */
50  if( bundle == NULL ) {
51  return -1;
52  }
53 
54  /* Get the payload block pointer */
55  payload_block = bundle_get_payload_block(bundlemem);
56 
57  /* Check if the bundle has a payload block */
58  if( payload_block == NULL ) {
59  return -1;
60  }
61 
62  /* Check if the block contains a status report */
63  if( !(payload_block->payload[0] & TYPE_CODE_BUNDLE_STATUS_REPORT) ) {
64  return -1;
65  }
66 
67  /* Decode the status report */
68  ret = statusreport_decode(&report, payload_block->payload, payload_block->block_size);
69 
70  /* Do not continue on error */
71  if( ret < 0 ) {
72  return -1;
73  }
74 
75  /* Abort of no delivery report */
76  if( !(report.status_flags & NODE_DELIVERED_BUNDLE) ) {
77  return -1;
78  }
79 
80  /* Calculate bundle number */
81  bundle_number = HASH.hash_convenience(report.bundle_sequence_number, report.bundle_creation_timestamp, report.source_eid_node, report.fragment_offset, report.fragment_length);
82 
83  LOG(LOGD_DTN, LOG_AGENT, LOGL_INF, "Received delivery report for bundle %lu from ipn:%lu, deleting", bundle_number, bundle->src_node);
84 
85  /* And delete the bundle without sending additional reports */
86  BUNDLE_STORAGE.del_bundle(bundle_number, REASON_DELIVERED);
87 
88  return 1;
89 }
90 
91 int dispatching_dispatch_bundle(struct mmem *bundlemem) {
92  struct bundle_t *bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
93  uint32_t * bundle_number_ptr;
94  uint32_t bundle_number = 0;
95  int n;
96  uint8_t received_report = 0;
97 
98  /* If we receive a delivery report for a bundle, delete the corresponding bundle from storage */
99  if( bundle->flags & BUNDLE_FLAG_ADM_REC ) {
100  dispatching_check_report(bundlemem);
101  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
102  }
103 
104  if ((bundle->flags & BUNDLE_FLAG_ADM_REC) && (bundle->dst_node == dtn_node_id)) {
105  // The bundle is an ADMIN RECORD for our node, process it directly here without going into storage
106 
107  /* XXX FIXME: Administrative records are not supported yet
108  *
109  if(*(MMEM_PTR(bundle->block.type) & 32 ) {// is custody signal
110  PRINTF("DISPATCHING: received custody signal %u %u\n",bundle->offset_tab[DATA][OFFSET], bundle->mem.size);
111 #if DEBUG
112  uint8_t i=0;
113  for (i=0; i< bundle->mem.size-bundle->offset_tab[DATA][OFFSET]; i++){
114  PRINTF("%x:", *((uint8_t*)bundle->mem.ptr +i+ bundle->offset_tab[DATA][OFFSET]));
115  }
116  PRINTF("\n");
117 #endif
118  //call custody signal method
119  if (*((uint8_t*)bundle->mem.ptr + bundle->offset_tab[DATA][OFFSET]+1) & 128 ){
120  CUSTODY.release(bundle);
121  }else{
122  CUSTODY.retransmit(bundle);
123  }
124 
125  }else if( (*((uint8_t*)bundle->mem.ptr + bundle->offset_tab[DATA][OFFSET]) & 16) && (*((uint8_t*)bundle->mem.ptr + bundle->offset_tab[DATA][OFFSET]+1) & 2)) { // node accepted custody
126  //printf(" node acced\n");
127 #if DEBUG
128  uint8_t i=0;
129  for (i=0; i< bundle->mem.size; i++){
130  PRINTF("%x:", *((uint8_t*)bundle->mem.ptr +i));
131  }
132  PRINTF("\n");
133 #endif
134 
135 
136  CUSTODY.release(bundle);
137  }*/
138 
139  // Decrease the reference counter - this should deallocate the bundle
140  bundle_decrement(bundlemem);
141 
142  // Exit function, nothing else to do here
143  return 1;
144  }
145 
146  // Now pass on the bundle to storage
147  if (bundle->flags & BUNDLE_FLAG_CUST_REQ){
148  // bundle is custody
149  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "Handing over to custody");
150 
151  CUSTODY.decide(bundlemem, bundle_number_ptr);
152  return 1;
153  }
154 
155  // Calculate the bundle number
156  bundle_number = HASH.hash_convenience(bundle->tstamp_seq, bundle->tstamp, bundle->src_node, bundle->frag_offs, bundle->app_len);
157  bundle->bundle_num = bundle_number;
158 
159  // Check if the bundle has been delivered before
160  if( REDUNDANCE.check(bundle_number) ) {
161  bundle_decrement(bundlemem);
162 
163  // If the bundle is redundant we still have to report success to make the CL send an ACK
164  return 1;
165  }
166 
167  // Does the sender want a "received" status report?
168  if( bundle->flags & BUNDLE_FLAG_REP_RECV ) {
169  received_report = 1;
170  }
171 
172  // regular bundle, no custody
173  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "Handing over to storage");
174  n = BUNDLE_STORAGE.save_bundle(bundlemem, &bundle_number_ptr);
175  bundlemem = NULL;
176 
177  // Send out a "received" status report if requested
178  if( received_report ) {
179  // Read back from storage
180  bundlemem = BUNDLE_STORAGE.read_bundle(bundle_number);
181 
182  if( bundlemem != NULL) {
183  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "Sending out delivery report for bundle %lu", bundle_number);
184 
185  // Send out report
187 
188  // Free memory
189  bundle_decrement(bundlemem);
190  }
191  }
192 
193  if( n ) {
194  // Put the bundle into the list of already seen bundles
195  REDUNDANCE.set(bundle_number);
196 
197  // Now we have to send an event to our daemon
198  process_post(&agent_process, dtn_bundle_in_storage_event, bundle_number_ptr);
199 
200  return 1;
201  }
202 
203  return 0;
204 }
205 /** @} */