Contiki 2.5
discovery_basic.c
Go to the documentation of this file.
1 /**
2  * \addtogroup discovery
3  * @{
4  */
5 
6 /**
7  * \defgroup discovery_basic Basic discovery module
8  *
9  * @{
10  */
11 
12 /**
13  * \file
14  * \brief Basic discovery module
15  *
16  * \author Georg von Zengen <vonzeng@ibr.cs.tu-bs.de>
17  */
18 
19 #include <string.h> // for memset
20 
21 #include "clock.h"
22 #include "net/netstack.h"
23 #include "net/packetbuf.h"
24 #include "net/rime/rimeaddr.h"
25 #include "logging.h"
26 
27 #include "dtn_network.h"
28 #include "agent.h"
29 
30 #include "discovery.h"
31 
32 void discovery_basic_neighbour_found(rimeaddr_t * neighbour);
33 void discovery_basic_refresh_neighbour(rimeaddr_t * neighbour);
34 void discovery_basic_save_neighbour(rimeaddr_t * neighbour);
36 
37 #define DISCOVERY_NEIGHBOUR_CACHE 3
38 #define DISCOVERY_NEIGHBOUR_TIMEOUT 5
39 #define DISCOVERY_CYCLE 0.2
40 #define DISCOVERY_TRIES 5
41 
42 /**
43  * This "internal" struct extends the discovery_neighbour_list_entry struct with
44  * more attributes for internal use
45  */
46 struct discovery_basic_neighbour_list_entry {
47  struct discovery_basic_neighbour_list_entry *next;
48  rimeaddr_t neighbour;
49  clock_time_t timestamp;
50  uint8_t active;
51 };
52 
53 PROCESS(discovery_process, "DISCOVERY process");
54 
55 /**
56  * List and memory blocks to save information about neighbours
57  */
58 LIST(neighbour_list);
59 MEMB(neighbour_mem, struct discovery_basic_neighbour_list_entry, DISCOVERY_NEIGHBOUR_CACHE);
60 
61 uint8_t discovery_status = 0;
62 uint8_t discovery_pending = 0;
63 uint8_t discovery_pending_start = 0;
64 static struct etimer discovery_timeout_timer;
65 static struct etimer discovery_pending_timer;
66 
67 /**
68  * \brief Initialize basic discovery module
69  */
71 {
72  // Enable discovery module
73  discovery_status = 1;
74 
75  // Initialize the neighbour list
76  list_init(neighbour_list);
77 
78  // Initialize the neighbour memory block
79  memb_init(&neighbour_mem);
80 
81  // Start discovery process
82  process_start(&discovery_process, NULL);
83 }
84 
85 /**
86  * \brief Is the provided address currently listed as neighbour?
87  * \param dest Address of the potential neighbour
88  * \return 1 if neighbour, 0 otherwise
89  */
90 uint8_t discovery_basic_is_neighbour(rimeaddr_t * dest)
91 {
92  struct discovery_basic_neighbour_list_entry * entry;
93 
94  for(entry = list_head(neighbour_list);
95  entry != NULL;
96  entry = entry->next) {
97  if( entry->active &&
98  rimeaddr_cmp(&(entry->neighbour), dest) ) {
99  return 1;
100  }
101  }
102 
103  return 0;
104 }
105 
106 /**
107  * \brief Send out discovery to provided address
108  * \param destination Address to send the discovery to
109  */
110 void discovery_basic_send_discovery(rimeaddr_t * destination)
111 {
112  if( discovery_status == 0 ) {
113  return;
114  }
115 
116  rimeaddr_t dest={{0,0}};
117  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "dtn_send_discover");
118 
119  convergence_layer_send_discovery((uint8_t *) "DTN_DISCOVERY", 13, &dest);
120 }
121 
122 /**
123  * \brief checks if incoming message is an answer to a discovery message
124  * \param msg pointer to the received message
125  * \return 1 if msg is an answer or 0 if not
126  */
127 uint8_t discovery_basic_is_beacon(uint8_t * msg)
128 {
129  uint8_t test[8]="DTN_HERE";
130  uint8_t i;
131  for (i=sizeof(test); i>0 ; i--){
132  if(test[i-1]!=msg[i-1]){
133  return 0;
134  }
135  }
136  return 1;
137 }
138 
139 /**
140  * \brief checks if incoming message is a discovery message
141  * \param msg pointer to the received message
142  * \param dest Node the discovery was received from
143  * \return 1 if msg is a discovery message or 0 if not
144  */
145 uint8_t discovery_basic_is_discovery(uint8_t * msg, rimeaddr_t * dest)
146 {
147  uint8_t test[13]="DTN_DISCOVERY";
148  uint8_t i;
149  for (i=sizeof(test); i>0; i--) {
150  if(test[i-1]!=msg[i-1]) {
151  return 0;
152  }
153  }
154 
155  if( discovery_status == 0 ) {
156  return 1;
157  }
158 
159  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "DTN DISCOVERY");
160  convergence_layer_send_discovery((uint8_t *) "DTN_HERE", 8, dest);
161 
162  return 1;
163 }
164 
165 /**
166  * \brief Enable discovery functionality
167  */
169 {
170  discovery_status = 1;
171 }
172 
173 /**
174  * \brief Disable discovery functionality
175  * Prevents outgoing packets from being sent
176  */
178 {
179  discovery_status = 0;
180 }
181 
182 /**
183  * \brief DTN Network has received an incoming discovery packet
184  * \param source Source address of the packet
185  * \param payload Payload pointer of the packet
186  * \param length Length of the payload
187  */
188 void discovery_basic_receive(rimeaddr_t * source, uint8_t * payload, uint8_t length)
189 {
190  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "received from %u:%u", source->u8[1], source->u8[0]);
191 
192  // Save all peer from which we receive packets to the active neighbours list
194 
195  // Either somebody wants to discover ourselves
196  if( discovery_basic_is_discovery(payload, source) ) {
197  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "is_discover");
198  return;
199  }
200 
201  // Or we have received a reply to our query
202  if( discovery_basic_is_beacon(payload) ) {
203  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "is_beacon");
205  }
206 }
207 
208 /**
209  * \brief We have found a new neighbour, now go and notify the agent
210  * \param neighbour Address of the newly found neighbour
211  */
212 void discovery_basic_neighbour_found(rimeaddr_t * neighbour)
213 {
214  struct discovery_basic_neighbour_list_entry * entry;
215 
216  for(entry = list_head(neighbour_list);
217  entry != NULL;
218  entry = entry->next) {
219  if( entry->active &&
220  rimeaddr_cmp(&(entry->neighbour), neighbour) ) {
221  break;
222  }
223  }
224 
225  if( entry == NULL ) {
226  // Apparently previously unknown neighbour
227  } else {
228  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "sending DTN BEACON Event for %u.%u", neighbour->u8[0], neighbour->u8[1]);
229  process_post(&agent_process, dtn_beacon_event, &entry->neighbour);
230  }
231 
232  // Once we have found a new neighbour, we will stop discovering other nodes
234 }
235 
236 /**
237  * \brief Checks if ''neighbours'' is already known
238  * Yes: refresh timestamp
239  * No: Create entry
240  *
241  * \param neighbour Address of the neighbour that should be refreshed
242  */
243 void discovery_basic_refresh_neighbour(rimeaddr_t * neighbour)
244 {
245  struct discovery_basic_neighbour_list_entry * entry;
246 
247  for(entry = list_head(neighbour_list);
248  entry != NULL;
249  entry = entry->next) {
250  if( entry->active &&
251  rimeaddr_cmp(&(entry->neighbour), neighbour) ) {
252  entry->timestamp = clock_time();
253  return;
254  }
255  }
256 
258 }
259 
260 /**
261  * \brief Save neighbour to local cache
262  * \param neighbour Address of the neighbour
263  */
264 void discovery_basic_save_neighbour(rimeaddr_t * neighbour)
265 {
266  // If we know that neighbour already, no need to re-add it
267  if( discovery_basic_is_neighbour(neighbour) ) {
268  return;
269  }
270 
271  struct discovery_basic_neighbour_list_entry * entry;
272  entry = memb_alloc(&neighbour_mem);
273 
274  if( entry == NULL ) {
275  // Now we have to delete an existing entry - which one to choose?
276  struct discovery_basic_neighbour_list_entry * delete = list_head(neighbour_list);
277  clock_time_t age = 0;
278 
279  // We select the entry with the hightest age
280  for(entry = list_head(neighbour_list);
281  entry != NULL;
282  entry = entry->next) {
283  if( entry->active && (clock_time() - entry->timestamp) > age ) {
284  age = clock_time() - entry->timestamp;
285  delete = entry;
286  }
287  }
288 
289  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_INF, "Removing neighbour %u.%u to make room", delete->neighbour.u8[0], delete->neighbour.u8[1]);
290 
291  // And remove if from the list and free the memory
292  memb_free(&neighbour_mem, delete);
293  list_remove(neighbour_list, delete);
294 
295  // Now we can allocate memory again - has to work, no need to check return value
296  entry = memb_alloc(&neighbour_mem);
297  }
298 
299  // Clean the entry struct, so that "active" becomes zero
300  memset(entry, 0, sizeof(struct discovery_basic_neighbour_list_entry));
301 
302  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "DISCOVERY: Saving neighbour %u.%u", neighbour->u8[0], neighbour->u8[1]);
303  entry->active = 1;
304  rimeaddr_copy(&(entry->neighbour), neighbour);
305  entry->timestamp = clock_time();
306 
307  list_add(neighbour_list, entry);
308 }
309 
310 
311 /**
312  * \brief Start to discover a neighbour
313  *
314  * \param dest Address of the neighbour
315  * \return 1 if neighbour is already known in (likely) in range, 0 otherwise
316  */
317 uint8_t discovery_basic_discover(rimeaddr_t * dest)
318 {
319  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "agent asks to discover %u.%u", dest->u8[0], dest->u8[1]);
320 
321  // Check, if we already know this neighbour
322  if(discovery_basic_is_neighbour(dest)) {
323  return 1;
324  }
325 
326  // Memorize, that we still have a discovery pending
327  discovery_pending_start = 1;
328  process_poll(&discovery_process);
329 
330  // Otherwise, send out a discovery beacon
332 
333  return 0;
334 }
335 
336 /**
337  * \brief Returns the list of currently known neighbours
338  * \return Pointer to list with neighbours
339  */
340 struct discovery_neighbour_list_entry * discovery_basic_list_neighbours()
341 {
342  return list_head(neighbour_list);
343 }
344 
345 /**
346  * \brief Stops pending discoveries
347  */
349 {
350  discovery_pending = 0;
351  etimer_stop(&discovery_pending_timer);
352 }
353 
354 /**
355  * \brief Starts a periodic rediscovery
356  */
358 {
359  discovery_pending = 1;
360  etimer_set(&discovery_pending_timer, DISCOVERY_CYCLE * CLOCK_SECOND);
361 }
362 
363 /**
364  * \brief Basic Discovery Persistent Process
365  */
366 PROCESS_THREAD(discovery_process, ev, data)
367 {
368  PROCESS_BEGIN();
369 
370  etimer_set(&discovery_timeout_timer, DISCOVERY_NEIGHBOUR_TIMEOUT * CLOCK_SECOND);
371  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_DBG, "Basic Discovery process running");
372 
373  while(1) {
375 
376  if( etimer_expired(&discovery_timeout_timer) ) {
377  struct discovery_basic_neighbour_list_entry * entry;
378 
379  for(entry = list_head(neighbour_list);
380  entry != NULL;
381  entry = entry->next) {
382  if( entry->active && (clock_time() - entry->timestamp) > (DISCOVERY_NEIGHBOUR_TIMEOUT * CLOCK_SECOND) ) {
383  LOG(LOGD_DTN, LOG_DISCOVERY, LOGL_INF, "Neighbour %u.%u timed out: %lu vs. %lu = %lu", entry->neighbour.u8[0], entry->neighbour.u8[1], clock_time(), entry->timestamp, clock_time() - entry->timestamp);
384 
385  // Tell the CL that this neighbour has disappeared
386  convergence_layer_neighbour_down(&entry->neighbour);
387 
388  memb_free(&neighbour_mem, entry);
389  list_remove(neighbour_list, entry);
390  }
391  }
392 
393  etimer_restart(&discovery_timeout_timer);
394  }
395 
396  /**
397  * If we have a discovery pending, resend the beacon multiple times
398  */
399  if( discovery_pending && etimer_expired(&discovery_pending_timer) ) {
401  discovery_pending ++;
402 
403  if( discovery_pending > (DISCOVERY_TRIES + 1)) {
405  } else {
406  etimer_restart(&discovery_pending_timer);
407  }
408  }
409 
410  /**
411  * In case we should start the periodic discovery, do it here and now
412  */
413  if( discovery_pending_start ) {
415  discovery_pending_start = 0;
416  }
417  }
418 
419  PROCESS_END();
420 }
421 
422 const struct discovery_driver discovery_basic = {
423  .name = "B_DISCOVERY",
424  .init = discovery_basic_init,
425  .is_neighbour = discovery_basic_is_neighbour,
426  .enable = discovery_basic_enable,
427  .disable = discovery_basic_disable,
428  .receive = discovery_basic_receive,
430  .dead = NULL,
431  .discover = discovery_basic_discover,
432  .neighbours = discovery_basic_list_neighbours,
433  .stop_pending = discovery_basic_stop_pending,
434 };
435 /** @} */
436 /** @} */