Contiki 2.5
statusreport_basic.c
Go to the documentation of this file.
1 /**
2  * \addtogroup bundle_status
3  * @{
4  */
5 
6 /**
7  * \defgroup bundle_status_basic Basic status report module
8  * @{
9  */
10 
11 /**
12  * \file
13  * \author Georg von Zengen <vonzeng@ibr.cs.tu-bs.de>
14  * \author Wolf-Bastian Pšttner <poettner@ibr.cs.tu-bs.de>
15  */
16 
17 #include <string.h>
18 
19 #include "mmem.h"
20 #include "logging.h"
21 
22 #include "bundle.h"
23 #include "agent.h"
24 #include "storage.h"
25 #include "sdnv.h"
26 #include "api.h"
27 #include "administrative_record.h"
28 #include "eid.h"
29 
30 #include "statusreport.h"
31 
32 #define BUFFER_LENGTH 100
33 
34 /**
35  * \brief Encode a bundle status report from the struct to a flat buffer
36  */
37 int statusreport_encode(status_report_t * report, uint8_t * buffer, uint8_t length)
38 {
39  uint8_t offset = 0;
40  int ret = 0;
41 
42  // Encode that we have an status record
43  buffer[offset++] = TYPE_CODE_BUNDLE_STATUS_REPORT;
44 
45  // Store the 8 bit fields for status flags and reason code
46  buffer[offset++] = report->status_flags;
47  buffer[offset++] = report->reason_code;
48 
49  /* For responses to fragments */
50  if( report->fragment ) {
51  // Set the header flag
52  buffer[0] |= ADMIN_FLAGS_IS_FOR_FRAGMENT;
53 
54  /* Fragment offset */
55  ret = sdnv_encode(report->dtn_time_seconds, &buffer[offset], length - offset);
56  if (ret < 0)
57  return -1;
58  offset += ret;
59 
60  /* Fragment length */
61  ret = sdnv_encode(report->dtn_time_seconds, &buffer[offset], length - offset);
62  if (ret < 0)
63  return -1;
64  offset += ret;
65  }
66 
67  /**
68  * TODO: We assume here, that all status reports have a timestamp. This is true in
69  * the latest version of RFC5050 but is not necessarily true in the future
70  */
71 
72  /* DTN Time Seconds */
73  ret = sdnv_encode(report->dtn_time_seconds, &buffer[offset], length - offset);
74  if (ret < 0)
75  return -1;
76  offset += ret;
77 
78  /* DTN Time Nanoseconds */
79  ret = sdnv_encode(report->dtn_time_nanoseconds, &buffer[offset], length - offset);
80  if (ret < 0)
81  return -1;
82  offset += ret;
83 
84  /* Now we need the creation timestamp of the original bundle */
85  ret = sdnv_encode(report->bundle_creation_timestamp, &buffer[offset], length - offset);
86  if (ret < 0)
87  return -1;
88  offset += ret;
89 
90  /* And the sequence number of the original bundle */
91  ret = sdnv_encode(report->bundle_sequence_number, &buffer[offset], length - offset);
92  if (ret < 0)
93  return -1;
94  offset += ret;
95 
96  /* Now encode the original source EID in string format */
97  offset += eid_create_full_length(report->source_eid_node, report->source_eid_service, &buffer[offset], length - offset);
98 
99  return offset;
100 }
101 
102 int statusreport_decode(status_report_t * report, uint8_t * buffer, uint8_t length)
103 {
104  int offset = 0;
105  int ret;
106 
107  // Check for the proper type
108  if( !(buffer[offset] & TYPE_CODE_BUNDLE_STATUS_REPORT) ) {
109  LOG(LOGD_DTN, LOG_AGENT, LOGL_WRN, "Status Report Format mismatch");
110  return -1;
111  }
112 
113  if( buffer[offset++] & ADMIN_FLAGS_IS_FOR_FRAGMENT ) {
114  report->fragment = 1;
115  }
116 
117  // Set report struct to 0
118  memset(report, 0, sizeof(status_report_t));
119 
120  // Recover status flags and reason code
121  report->status_flags = buffer[offset++];
122  report->reason_code = buffer[offset++];
123 
124  // Recover fragment offset and length (if present)
125  if( report->fragment ) {
126  /* Fragment offset */
127  ret = sdnv_decode(&buffer[offset], length - offset, &report->dtn_time_seconds);
128  if( ret < 0 )
129  return -1;
130  offset += ret;
131 
132  /* Fragment length */
133  ret = sdnv_decode(&buffer[offset], length - offset, &report->dtn_time_seconds);
134  if( ret < 0 )
135  return -1;
136  offset += ret;
137  }
138 
139  // FIXME: seconds and nanoseconds could be present 0 - n times. We assume here 1
140  /* Recover dtn_time seconds */
141  ret = sdnv_decode(&buffer[offset], length - offset, &report->dtn_time_seconds);
142  if( ret < 0 )
143  return -1;
144  offset += ret;
145 
146  /* Recover dtn_time nanoseconds */
147  ret = sdnv_decode(&buffer[offset], length - offset, &report->dtn_time_nanoseconds);
148  if( ret < 0 )
149  return -1;
150  offset += ret;
151 
152  /* Recover timestamp */
153  ret = sdnv_decode(&buffer[offset], length - offset, &report->bundle_creation_timestamp);
154  if( ret < 0 )
155  return -1;
156  offset += ret;
157 
158  /* Recover timestamp sequence number */
159  ret = sdnv_decode(&buffer[offset], length - offset, &report->bundle_sequence_number);
160  if( ret < 0 )
161  return -1;
162  offset += ret;
163 
164  /* Recover the EID */
165  ret = eid_parse_full_length(&buffer[offset], length - offset, &report->source_eid_node, &report->source_eid_service);
166  if( ret < 0 )
167  return -1;
168 
169  return 1;
170 }
171 
172 /**
173  * \brief sends a status report for a bundle to the "report-to"-node
174  * \param bundle pointer to bundle
175  * \param status status code for the bundle
176  * \param reason reason code for the status
177  */
178 uint8_t statusreport_basic_send(struct mmem * bundlemem, uint8_t status, uint8_t reason)
179 {
180  uint32_t bundle_flags;
181  uint32_t report_node_id;
182  uint32_t report_service_id;
183  uint32_t flags;
184  uint32_t lifetime;
185  struct mmem * report_bundle = NULL;
186  struct bundle_t * bundle = NULL;
187  status_report_t report;
188  uint8_t buffer[BUFFER_LENGTH];
189  int ret;
190 
191  // Check if we really should send a report
192  bundle_get_attr(bundlemem, FLAGS, &bundle_flags);
193  if( !(bundle_flags & BUNDLE_FLAG_REPORT) ) {
194  return 0;
195  }
196 
197  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "Sending out status report for status %u and reason %u", status, reason);
198 
199  // Fill out the statusreport struct
200  memset(&report, 0, sizeof(status_report_t));
201  report.status_flags = status;
202  report.reason_code = reason;
203 
204  // FIXME: the time stored here is badly broken but we do not have any better solution ATM
205  report.dtn_time_seconds = clock_seconds();
206  report.dtn_time_nanoseconds = 0;
207 
208  // Collect all necessary information to fill out the report
209  bundle_get_attr(bundlemem, SRC_NODE, &report.source_eid_node);
210  bundle_get_attr(bundlemem, SRC_SERV, &report.source_eid_service);
211  bundle_get_attr(bundlemem, TIME_STAMP, &report.bundle_creation_timestamp);
212  bundle_get_attr(bundlemem, TIME_STAMP_SEQ_NR, &report.bundle_sequence_number);
213 
214  // Collect all necessary information to create report bundle
215  bundle_get_attr(bundlemem, REP_NODE, &report_node_id);
216  bundle_get_attr(bundlemem, REP_SERV, &report_service_id);
217 
218  // Check for a proper destination node
219  if( report_node_id == 0 ) {
220  LOG(LOGD_DTN, LOG_AGENT, LOGL_WRN, "Cannot send status report, destination node is %lu", report_node_id);
221  return 0;
222  }
223 
224  // Allocate memory for our bundle
225  report_bundle = bundle_create_bundle();
226 
227  if( report_bundle == NULL ) {
228  LOG(LOGD_DTN, LOG_AGENT, LOGL_ERR, "Unable to allocate report bundle, storage has %u bundles left", BUNDLE_STORAGE.free_space(NULL));
229  return 0;
230  }
231 
232  // "Fake" the source of the bundle to be the agent
233  // Otherwise we cannot send bundles, because we do not have an endpoint registration
234  bundle = (struct bundle_t *) MMEM_PTR(report_bundle);
235  bundle->source_process = &agent_process;
236 
237  // Set destination addresses for the outgoing bundle
238  bundle_set_attr(report_bundle, DEST_NODE, &report_node_id);
239  bundle_set_attr(report_bundle, DEST_SERV, &report_service_id);
240 
241  // Copy timestamp from incoming bundle
242  bundle_set_attr(report_bundle, TIME_STAMP, &report.bundle_creation_timestamp);
243 
244  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "Report goes to %lu.%lu", report_node_id, report_service_id);
245 
246  // Set lifetime
247  lifetime = 3600;
248  bundle_set_attr(report_bundle, LIFE_TIME, &lifetime);
249 
250  // Make the outgoing bundle an admin record
251  flags = BUNDLE_FLAG_ADM_REC;
252  bundle_set_attr(report_bundle, FLAGS, &flags);
253 
254  // Encode status report
255  ret = statusreport_encode(&report, buffer, BUFFER_LENGTH);
256  if( ret < 0 ) {
257  // Free memory
258  bundle_decrement(report_bundle);
259  return 0;
260  }
261 
262  // Add status report to bundle
263  ret = bundle_add_block(report_bundle, BUNDLE_BLOCK_TYPE_PAYLOAD, BUNDLE_BLOCK_FLAG_NULL, buffer, ret);
264  if( ret < 0 ) {
265  // Free memory
266  bundle_decrement(report_bundle);
267  return 0;
268  }
269 
270  // Send out the report
271  process_post(&agent_process, dtn_send_bundle_event, report_bundle);
272 
273  return 1;
274 }
275 
276 const struct status_report_driver statusreport_basic = {
277  "STATUSREPORT_BASIC",
279 };
280 /** @} */
281 /** @} */