Contiki 2.5
storage_coffee.c
Go to the documentation of this file.
1 /**
2  * \addtogroup bundle_storage
3  * @{
4  */
5 
6 /**
7  * \defgroup bundle_storage_coffee COFFEE-based persistent Storage
8  *
9  * @{
10  */
11 
12 /**
13  * \file
14  * \author Georg von Zengen <vonzeng@ibr.cs.tu-bs.de>
15  * \author Wolf-Bastian Poettner <poettner@ibr.cs.tu-bs.de>
16  */
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "contiki.h"
23 #include "netstack.h"
24 #include "cfs/cfs.h"
25 #include "mmem.h"
26 #include "memb.h"
27 #include "cfs-coffee.h"
28 #include "watchdog.h"
29 #include "list.h"
30 #include "logging.h"
31 
32 #include "bundle.h"
33 #include "sdnv.h"
34 #include "statusreport.h"
35 #include "agent.h"
36 #include "hash.h"
37 
38 #include "storage.h"
39 
40 /**
41  * How long can a filename possibly be?
42  */
43 #define STORAGE_FILE_NAME_LENGTH 15
44 
45 /**
46  * Internal representation of a bundle
47  *
48  * The layout is quite fixed - the next pointer and the bundle_num have to go first because this struct
49  * has to be compatible with the struct storage_entry_t in storage.h!
50  */
51 struct file_list_entry_t {
52  /** pointer to the next list element */
53  struct file_list_entry_t * next;
54 
55  uint32_t bundle_num;
56 
57  uint32_t rec_time;
58  uint32_t lifetime;
59  uint32_t bundle_flags;
60 
61  uint16_t file_size;
62 
63  /** Flags */
64  uint8_t flags;
65 };
66 
67 /**
68  * Flags for the storage
69  */
70 #define STORAGE_COFFEE_FLAGS_LOCKED 0x1
71 
72 // List and memory blocks for the bundles
73 LIST(bundle_list);
74 MEMB(bundle_mem, struct file_list_entry_t, BUNDLE_STORAGE_SIZE);
75 
76 // global, internal variables
77 /** Counts the number of bundles in storage */
78 static uint16_t bundles_in_storage;
79 
80 /** Is used to periodically traverse all bundles and delete those that are expired */
81 static struct ctimer g_store_timer;
82 
83 /** Flag to indicate whether the bundle list has changed since last writing the list file */
84 static uint8_t bundle_list_changed = 0;
85 
86 /**
87  * COFFEE is so slow, that we are loosing radio packets while using the flash. Unfortunately, the
88  * radio is sending LL ACKs for these packets, so the other side does not know.
89  * Therefore, we have to disable the radio while reading or writing COFFEE, to avoid sending
90  * ACKs for packets that we cannot read out of the buffer.
91  *
92  * FIXME: This HACK is *very* ugly and poor design.
93  */
94 #define RADIO_SAFE_STATE_ON() NETSTACK_MAC.off(0)
95 #define RADIO_SAFE_STATE_OFF() NETSTACK_MAC.on()
96 
97 /**
98  * "Internal" functions
99  */
100 void storage_coffee_prune();
101 uint16_t storage_coffee_delete_bundle(uint32_t bundle_number, uint8_t reason);
102 struct mmem * storage_coffee_read_bundle(uint32_t bundle_number);
104 
105 /**
106  * \brief called by agent at startup
107  */
109 {
110  // Initialize the bundle list
111  list_init(bundle_list);
112 
113  // Initialize the bundle memory block
114  memb_init(&bundle_mem);
115 
116  bundles_in_storage = 0;
117  bundle_list_changed = 0;
118 
119 #if BUNDLE_STORAGE_INIT
121 
122  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "Formatting flash");
124 
125  RADIO_SAFE_STATE_OFF();
126 #else
127  // Try to restore our bundle list from the file system
129 #endif
130 
131  // Set the timer to regularly prune expired bundles
132  ctimer_set(&g_store_timer, CLOCK_SECOND*5, storage_coffee_prune, NULL);
133 }
134 
135 /**
136  * \brief Restore bundles stored in CFS
137  */
139 {
140  int n;
141  struct file_list_entry_t * entry = NULL;
142  struct cfs_dir directory_iterator;
143  struct cfs_dirent directory_entry;
144  char * delimeter = NULL;
145  uint32_t bundle_number = 0;
146  struct mmem * bundleptr = NULL;
147  struct bundle_t * bundle = NULL;
148  uint8_t found = 0;
149 
151 
152  n = cfs_opendir(&directory_iterator, "/");
153  if( n == -1 ) {
154  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to list directory /");
155  RADIO_SAFE_STATE_OFF();
156  return;
157  }
158 
159  while( cfs_readdir(&directory_iterator, &directory_entry) != -1 ) {
160  /* Check if there is a . in the filename */
161  delimeter = strchr(directory_entry.name, '.');
162 
163  if( delimeter == NULL ) {
164  /* filename is invalid */
165  LOG(LOGD_DTN, LOG_STORE, LOGL_WRN, "filename %s is invalid, skipping", directory_entry.name);
166  continue;
167  }
168 
169  /* Check if the extension is b */
170  if( *(delimeter+1) != 'b' ) {
171  /* filename is invalid */
172  LOG(LOGD_DTN, LOG_STORE, LOGL_WRN, "filename %s is invalid, skipping", directory_entry.name);
173  continue;
174  }
175 
176  /* Get the bundle number from the filename */
177  delimeter = '\0';
178  bundle_number = strtoul(directory_entry.name, NULL, 10);
179 
180  /* Check if this bundle is in storage already */
181  found = 0;
182  for(entry = list_head(bundle_list);
183  entry != NULL;
184  entry = list_item_next(entry)) {
185 
186  if( entry->bundle_num == bundle_number ) {
187  found = 1;
188  break;
189  }
190  }
191 
192  if( found == 1 ) {
193  continue;
194  }
195 
196  /* Allocate a directory entry for the bundle */
197  entry = memb_alloc(&bundle_mem);
198  if( entry == NULL ) {
199  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to allocate struct, cannot restore bundle");
200  continue;
201  }
202 
203  /* Fill in the entry */
204  entry->bundle_num = bundle_number;
205  entry->file_size = directory_entry.size;
206 
207  /* Add bundle to the list */
208  list_add(bundle_list, entry);
209  bundles_in_storage ++;
210 
211  /* Now read bundle from storage to update the rest of the entry */
212  RADIO_SAFE_STATE_OFF();
213  bundleptr = storage_coffee_read_bundle(entry->bundle_num);
215 
216  if( bundleptr == NULL ) {
217  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to restore bundle %lu", entry->bundle_num);
218  list_remove(bundle_list, entry);
219  memb_free(&bundle_mem, entry);
220  bundles_in_storage--;
221  continue;
222  }
223 
224  /* Get bundle struct */
225  bundle = (struct bundle_t *) MMEM_PTR(bundleptr);
226 
227  /* Copy everything we need from the bundle */
228  entry->rec_time = bundle->rec_time;
229  entry->lifetime = bundle->lifetime;
230  entry->file_size = bundleptr->size;
231  entry->bundle_num = bundle->bundle_num;
232 
233  /* Deallocate memory */
234  bundle_decrement(bundleptr);
235  bundle = NULL;
236  bundleptr = NULL;
237  entry = NULL;
238  }
239 
240  /* Close directory handle */
241  cfs_closedir(&directory_iterator);
242 
243  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "Restored %u bundles from CFS", bundles_in_storage);
244 
245  RADIO_SAFE_STATE_OFF();
246 }
247 
248 /**
249  * \brief deletes expired bundles from storage
250  */
252 {
253  uint32_t elapsed_time;
254  struct file_list_entry_t * entry = NULL;
255 
256  // Delete expired bundles from storage
257  for(entry = list_head(bundle_list);
258  entry != NULL;
259  entry = list_item_next(entry)) {
260  elapsed_time = clock_seconds() - entry->rec_time;
261 
262  if( entry->lifetime < elapsed_time ) {
263  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "bundle lifetime expired of bundle %lu", entry->bundle_num);
264  storage_coffee_delete_bundle(entry->bundle_num, REASON_LIFETIME_EXPIRED);
265  }
266  }
267 
268  // Restart the timer
269  ctimer_restart(&g_store_timer);
270 }
271 
272 /**
273  * \brief Sets the storage to its initial state
274  */
276 {
277  // Remove all bundles from storage
278  while(bundles_in_storage > 0) {
279  struct file_list_entry_t * entry = list_head(bundle_list);
280 
281  if( entry == NULL ) {
282  // We do not have bundles in storage, stop deleting them
283  break;
284  }
285 
286  storage_coffee_delete_bundle(entry->bundle_num, REASON_DEPLETED_STORAGE);
287  }
288 
289  // And reset our counters
290  bundles_in_storage = 0;
291 }
292 
293 /**
294  * \brief This function delete as many bundles from the storage as necessary to have at least one slot free
295  * \param bundlemem Pointer to the MMEM struct containing the bundle
296  * \return 1 on success, 0 if no room could be made free
297  */
298 uint8_t storage_coffee_make_room(struct mmem * bundlemem)
299 {
300  /* Delete expired bundles first */
302 
303  /* If we do not have a pointer, we cannot compare - do nothing */
304  if( bundlemem == NULL ) {
305  return 0;
306  }
307 
308 #if BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DO_NOT_DELETE
309  /* We do not delete at all. If storage is used up, we sit there and wait */
310  if( bundles_in_storage >= BUNDLE_STORAGE_SIZE ) {
311  return 0;
312  }
313 #elif (BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_OLDEST || BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_YOUNGEST )
314  struct bundle_t * bundle = NULL;
315  struct file_list_entry_t * entry = NULL;
316 
317  /* Keep deleting bundles until we have enough slots */
318  while( bundles_in_storage >= BUNDLE_STORAGE_SIZE) {
319  unsigned long comparator = 0;
320  struct file_list_entry_t * deletor = NULL;
321 
322  for( entry = list_head(bundle_list);
323  entry != NULL;
324  entry = list_item_next(entry) ) {
325 
326  /* Never delete locked bundles */
327  if( entry->flags & STORAGE_COFFEE_FLAGS_LOCKED ) {
328  continue;
329  }
330 
331  /* Always keep bundles with higher priority */
332  if( (entry->bundle_flags & BUNDLE_PRIORITY_MASK) > (bundle->flags & BUNDLE_PRIORITY_MASK ) ) {
333  continue;
334  }
335 
336 #if BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_OLDEST
337  if( (clock_seconds() - entry->rec_time) > comparator || comparator == 0) {
338  comparator = clock_seconds() - entry->rec_time;
339  deletor = entry;
340  }
341 #elif BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_YOUNGEST
342  if( (clock_seconds() - entry->rec_time) < comparator || comparator == 0) {
343  comparator = clock_seconds() - entry->rec_time;
344  deletor = entry;
345  }
346 #endif
347  }
348 
349  /* Either the for loop did nothing or did not break */
350  if( entry == NULL ) {
351  /* We do not have deletable bundles in storage, stop deleting them */
352  return 0;
353  }
354 
355  /* Delete Bundle */
356  storage_coffee_delete_bundle(entry->bundle_num, REASON_DEPLETED_STORAGE);
357  }
358 #elif (BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_OLDER || BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_YOUNGER )
359  struct bundle_t * bundle = NULL;
360  struct file_list_entry_t * entry = NULL;
361 
362  /* Keep deleting bundles until we have enough slots */
363  while( bundles_in_storage >= BUNDLE_STORAGE_SIZE) {
364  /* Obtain the new pointer each time, since the address may change */
365  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
366 
367  /* We need this double-loop because otherwise we would be modifying the list
368  * while iterating through it
369  */
370  for( entry = list_head(bundle_list);
371  entry != NULL;
372  entry = list_item_next(entry) ) {
373  /* Never delete locked bundles */
374  if( entry->flags & STORAGE_COFFEE_FLAGS_LOCKED ) {
375  continue;
376  }
377 
378  /* Always keep bundles with higher priority */
379  if( (entry->bundle_flags & BUNDLE_PRIORITY_MASK) > (bundle->flags & BUNDLE_PRIORITY_MASK ) ) {
380  continue;
381  }
382 
383 #if BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_OLDER
384  /* If the new bundle has a longer lifetime than the bundle in our storage,
385  * delete the bundle from storage to make room
386  */
387  if( bundle->lifetime - (clock_seconds() - bundle->rec_time) >= entry->lifetime - (clock_seconds() - entry->rec_time) ) {
388  break;
389  }
390 #elif BUNDLE_STORAGE_BEHAVIOUR == BUNDLE_STORAGE_BEHAVIOUR_DELETE_YOUNGER
391  /* Delete youngest bundle in storage */
392  if( bundle->lifetime - (clock_seconds() - bundle->rec_time) >= entry->lifetime - (clock_seconds() - entry->rec_time) ) {
393  break;
394  }
395 #endif
396  }
397 
398  /* Either the for loop did nothing or did not break */
399  if( entry == NULL ) {
400  /* We do not have deletable bundles in storage, stop deleting them */
401  return 0;
402  }
403 
404  /* Delete Bundle */
405  storage_coffee_delete_bundle(entry->bundle_num, REASON_DEPLETED_STORAGE);
406  }
407 #else
408 #error No Bundle Deletion Strategy defined
409 #endif
410 
411  /* At least one slot is free now */
412  return 1;
413 }
414 
415 /**
416  * \brief saves a bundle in storage
417  * \param bundlemem pointer to the MMEM struct containing the bundle
418  * \param bundle_number_ptr The pointer to the bundle number will be stored here
419  * \return 1 on success, 0 otherwise
420  */
421 uint8_t storage_coffee_save_bundle(struct mmem * bundlemem, uint32_t ** bundle_number_ptr)
422 {
423  struct bundle_t * bundle = NULL;
424  struct file_list_entry_t * entry = NULL;
425  char bundle_filename[STORAGE_FILE_NAME_LENGTH];
426  int fd_write;
427  int n;
428 
429  if( bundlemem == NULL ) {
430  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "save_bundle with invalid pointer %p", bundlemem);
431  return 0;
432  }
433 
434  // Get the pointer to our bundle
435  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
436 
437  if( bundle == NULL ) {
438  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "save_bundle with invalid MMEM structure");
439  bundle_decrement(bundlemem);
440  return 0;
441  }
442 
443  // Look for duplicates in the storage
444  for(entry = list_head(bundle_list);
445  entry != NULL;
446  entry = list_item_next(entry)) {
447 
448  if( bundle->bundle_num == entry->bundle_num ) {
449  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "%lu is the same bundle", entry->bundle_num);
450  *bundle_number_ptr = &entry->bundle_num;
451  bundle_decrement(bundlemem);
452  return entry->bundle_num;
453  }
454  }
455 
456  if( !storage_coffee_make_room(bundlemem) ) {
457  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "Cannot store bundle, no room");
458 
459  /* Throw away bundle to not take up RAM */
460  bundle_decrement(bundlemem);
461 
462  return 0;
463  }
464 
465  /* Update the pointer to the bundle, address may have changed due to storage_coffee_make_room and MMEM reallocations */
466  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
467 
468  // Allocate some memory for our bundle
469  entry = memb_alloc(&bundle_mem);
470  if( entry == NULL ) {
471  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to allocate struct, cannot store bundle");
472  bundle_decrement(bundlemem);
473  return 0;
474  }
475 
476  // Clear the memory area
477  memset(entry, 0, sizeof(struct file_list_entry_t));
478 
479  // Copy necessary values from the bundle
480  entry->rec_time = bundle->rec_time;
481  entry->lifetime = bundle->lifetime;
482  entry->file_size = bundlemem->size;
483  entry->bundle_flags = bundle->flags;
484 
485  // Assign a unique bundle number
486  entry->bundle_num = bundle->bundle_num;
487 
488  // determine the filename
489  n = snprintf(bundle_filename, STORAGE_FILE_NAME_LENGTH, "%lu.b", entry->bundle_num);
490  if( n == STORAGE_FILE_NAME_LENGTH ) {
491  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "file name buffer is too short");
492  memb_free(&bundle_mem, entry);
493  bundle_decrement(bundlemem);
494  return 0;
495  }
496 
498 
499  // Store the bundle into the file
500  n = cfs_coffee_reserve(bundle_filename, bundlemem->size);
501  if( n < 0 ) {
502  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to reserve %u bytes for bundle", bundlemem->size);
503  memb_free(&bundle_mem, entry);
504  bundle_decrement(bundlemem);
505  RADIO_SAFE_STATE_OFF();
506  return 0;
507  }
508 
509  // Open the output file
510  fd_write = cfs_open(bundle_filename, CFS_WRITE);
511  if( fd_write == -1 ) {
512  // Unable to open file, abort here
513  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to open file %s, cannot save bundle", bundle_filename);
514  memb_free(&bundle_mem, entry);
515  bundle_decrement(bundlemem);
516  RADIO_SAFE_STATE_OFF();
517  return 0;
518  }
519 
520  // Write our complete bundle
521  n = cfs_write(fd_write, bundle, bundlemem->size);
522  if( n != bundlemem->size ) {
523  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to write %u bytes to file %s, aborting", bundlemem->size, bundle_filename);
524  cfs_close(fd_write);
525  cfs_remove(bundle_filename);
526  memb_free(&bundle_mem, entry);
527  bundle_decrement(bundlemem);
528  RADIO_SAFE_STATE_OFF();
529  return 0;
530  }
531 
532  // And close the file
533  cfs_close(fd_write);
534 
535  RADIO_SAFE_STATE_OFF();
536 
537  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "New Bundle %lu (%lu), Src %lu.%lu, Dest %lu.%lu, Seq %lu", bundle->bundle_num, entry->bundle_num, bundle->src_node, bundle->src_srv, bundle->dst_node, bundle->dst_srv, bundle->tstamp_seq);
538 
539  // Add bundle to the list
540  list_add(bundle_list, entry);
541 
542  // Mark the bundle list as changed
543  bundle_list_changed = 1;
544  bundles_in_storage++;
545 
546  // Now we have to free the incoming bundle slot
547  bundle_decrement(bundlemem);
548 
549  // Now copy over the STATIC pointer to the bundle number, so that
550  // the caller can stick it into an event
551  *bundle_number_ptr = &entry->bundle_num;
552 
553  return 1;
554 }
555 
556 /**
557  * \brief deletes a bundle form storage
558  * \param bundle_number bundle number to be deleted
559  * \param reason reason code
560  * \return 1 on success or 0 on error
561  */
562 uint16_t storage_coffee_delete_bundle(uint32_t bundle_number, uint8_t reason)
563 {
564  struct bundle_t * bundle = NULL;
565  struct file_list_entry_t * entry = NULL;
566  struct mmem * bundlemem = NULL;
567  char bundle_filename[STORAGE_FILE_NAME_LENGTH];
568  int n;
569 
570  LOG(LOGD_DTN, LOG_STORE, LOGL_INF, "Deleting Bundle %lu with reason %u", bundle_number, reason);
571 
572  // Look for the bundle we are talking about
573  for(entry = list_head(bundle_list);
574  entry != NULL;
575  entry = list_item_next(entry)) {
576 
577  if( entry->bundle_num == bundle_number ) {
578  break;
579  }
580  }
581 
582  if( entry == NULL ) {
583  LOG(LOGD_DTN, LOG_STORE, LOGL_WRN, "Could not find bundle %lu on del_bundle", bundle_number);
584  return 0;
585  }
586 
587  // Figure out the source to send status report
588  if( reason != REASON_DELIVERED ) {
589  if( (entry->bundle_flags & BUNDLE_FLAG_CUST_REQ ) || (entry->bundle_flags & BUNDLE_FLAG_REP_DELETE) ){
590  bundlemem = storage_coffee_read_bundle(bundle_number);
591  if( bundlemem == NULL ) {
592  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to read back bundle %lu", bundle_number);
593  return 0;
594  }
595 
596  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
597  bundle->del_reason = reason;
598 
599  if (bundle->src_node != dtn_node_id){
600  STATUSREPORT.send(bundlemem, 16, bundle->del_reason);
601  }
602  }
603 
604  bundle_decrement(bundlemem);
605  bundle = NULL;
606  }
607 
608  // Notified the agent, that a bundle has been deleted
609  agent_delete_bundle(bundle_number);
610 
611  // Remove the bundle from the list
612  list_remove(bundle_list, entry);
613 
614  // determine the filename and remove the file
615  n = snprintf(bundle_filename, STORAGE_FILE_NAME_LENGTH, "%lu.b", entry->bundle_num);
616  if( n == STORAGE_FILE_NAME_LENGTH ) {
617  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "file name buffer is too short");
618  return 0;
619  }
620 
622 
623  cfs_remove(bundle_filename);
624 
625  RADIO_SAFE_STATE_OFF();
626 
627  // Mark the bundle list as changed
628  bundle_list_changed = 1;
629  bundles_in_storage--;
630 
631  // Free the storage struct
632  memb_free(&bundle_mem, entry);
633 
634  return 1;
635 }
636 
637 /**
638  * \brief reads a bundle from storage
639  * \param bundle_number bundle number to read
640  * \return pointer to the MMEM struct containing the bundle (caller has to free)
641  */
643 {
644  struct bundle_t * bundle = NULL;
645  struct file_list_entry_t * entry = NULL;
646  struct mmem * bundlemem = NULL;
647  char bundle_filename[STORAGE_FILE_NAME_LENGTH];
648  int fd_read;
649  int n;
650 
651  LOG(LOGD_DTN, LOG_STORE, LOGL_DBG, "Reading Bundle %lu", bundle_number);
652 
653  // Look for the bundle we are talking about
654  for(entry = list_head(bundle_list);
655  entry != NULL;
656  entry = list_item_next(entry)) {
657 
658  if( entry->bundle_num == bundle_number ) {
659  break;
660  }
661  }
662 
663  if( entry == NULL ) {
664  LOG(LOGD_DTN, LOG_STORE, LOGL_WRN, "Could not find bundle %lu on read_bundle", bundle_number);
665  return NULL;
666  }
667 
668  bundlemem = bundle_create_bundle();
669  if( bundlemem == NULL ) {
670  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "cannot allocate memory for bundle %lu", bundle_number);
671  return NULL;
672  }
673 
674  n = mmem_realloc(bundlemem, entry->file_size);
675  if( !n ) {
676  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to realloc enough memory");
677  bundle_decrement(bundlemem);
678  return NULL;
679  }
680 
681  // determine the filename
682  n = snprintf(bundle_filename, STORAGE_FILE_NAME_LENGTH, "%lu.b", entry->bundle_num);
683  if( n == STORAGE_FILE_NAME_LENGTH ) {
684  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "file name buffer is too short");
685  bundle_decrement(bundlemem);
686  return NULL;
687  }
688 
690 
691  // Open the output file
692  fd_read = cfs_open(bundle_filename, CFS_READ);
693  if( fd_read == -1 ) {
694  // Unable to open file, abort here
695  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to open file %s, cannot read bundle", bundle_filename);
696  bundle_decrement(bundlemem);
697  return NULL;
698  }
699 
700  // Read our complete bundle
701  n = cfs_read(fd_read, MMEM_PTR(bundlemem), bundlemem->size);
702  if( n != bundlemem->size ) {
703  LOG(LOGD_DTN, LOG_STORE, LOGL_ERR, "unable to read %u bytes from file %s, aborting", bundlemem->size, bundle_filename);
704  bundle_decrement(bundlemem);
705  cfs_close(fd_read);
706  return NULL;
707  }
708 
709  // And close the file
710  cfs_close(fd_read);
711 
712  RADIO_SAFE_STATE_OFF();
713 
714  /* Get the bundle pointer */
715  bundle = (struct bundle_t *) MMEM_PTR(bundlemem);
716 
717  /* How long did this bundle rot in our storage? */
718  uint32_t elapsed_time = clock_seconds() - bundle->rec_time;
719 
720  /* Update lifetime of bundle */
721  if( bundle->lifetime < elapsed_time ) {
722  bundle->lifetime = 0;
723  bundle->rec_time = clock_seconds();
724  } else {
725  bundle->lifetime = bundle->lifetime - elapsed_time;
726  bundle->rec_time = clock_seconds();
727  }
728 
729  return bundlemem;
730 }
731 
732 /**
733  * \brief checks if there is space for a bundle
734  * \param bundlemem pointer to a bundle struct (not used here)
735  * \return number of free slots
736  */
737 uint16_t storage_coffee_get_free_space(struct mmem * bundlemem)
738 {
739  return BUNDLE_STORAGE_SIZE - bundles_in_storage;
740 }
741 
742 /**
743  * \brief Get the number of slots available in storage
744  * \returns the number of free slots
745  */
747  return bundles_in_storage;
748 }
749 
750 /**
751  * \brief Get the bundle list
752  * \returns pointer to first bundle list entry
753  */
755 {
756  return (struct storage_entry_t *) list_head(bundle_list);
757 }
758 
759 /**
760  * \brief Mark a bundle as locked so that it will not be deleted even if we are running out of space
761  *
762  * \param bundle_num Bundle number
763  * \return 1 on success or 0 on error
764  */
766 {
767  struct file_list_entry_t * entry = NULL;
768 
769  // Look for the bundle we are talking about
770  for(entry = list_head(bundle_list);
771  entry != NULL;
772  entry = list_item_next(entry)) {
773  if( entry->bundle_num == bundle_num ) {
774  break;
775  }
776  }
777 
778  if( entry == NULL ) {
779  return 0;
780  }
781 
782  entry->flags |= STORAGE_COFFEE_FLAGS_LOCKED;
783 
784  return 1;
785 }
786 
787 /**
788  * \brief Mark a bundle as unlocked after being locked previously
789  */
790 void storage_coffee_unlock_bundle(uint32_t bundle_num)
791 {
792  struct file_list_entry_t * entry = NULL;
793 
794  // Look for the bundle we are talking about
795  for(entry = list_head(bundle_list);
796  entry != NULL;
797  entry = list_item_next(entry)) {
798  if( entry->bundle_num == bundle_num ) {
799  break;
800  }
801  }
802 
803  if( entry == NULL ) {
804  return;
805  }
806 
807  entry->flags &= ~STORAGE_COFFEE_FLAGS_LOCKED;
808 }
809 
810 const struct storage_driver storage_coffee = {
811  "STORAGE_COFFEE",
822 };
823 /** @} */
824 /** @} */