Contiki 3.x
rudolph2.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Rudolph2: a simple block data flooding protocol
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 /**
41  * \addtogroup rudolph2
42  * @{
43  */
44 
45 /* XXX todo: add timeout so that hops_from_sink is reset to MAX
46  after a while. */
47 
48 /* XXX todo: use a ctimer to drive peridodic transmission: the current
49  way does not work if a queuebuf cannot be allocated. */
50 
51 #include <stdio.h>
52 #include <stddef.h> /* for offsetof */
53 
54 #include "net/rime/rime.h"
55 #include "net/rime/polite.h"
56 #include "net/rime/rudolph2.h"
57 #include "cfs/cfs.h"
58 
59 #define SEND_INTERVAL CLOCK_SECOND / 2
60 #define STEADY_INTERVAL CLOCK_SECOND * 16
61 #define RESEND_INTERVAL SEND_INTERVAL * 4
62 #define NACK_TIMEOUT CLOCK_SECOND / 4
63 
64 struct rudolph2_hdr {
65  uint8_t type;
66  uint8_t hops_from_base;
67  uint16_t version;
68  uint16_t chunk;
69 };
70 
71 #define POLITE_HEADER 1
72 
73 #define HOPS_MAX 64
74 
75 enum {
76  TYPE_DATA,
77  TYPE_NACK,
78 };
79 
80 #define FLAG_LAST_SENT 0x01
81 #define FLAG_LAST_RECEIVED 0x02
82 #define FLAG_IS_STOPPED 0x04
83 
84 #define DEBUG 0
85 #if DEBUG
86 #include <stdio.h>
87 #define PRINTF(...) printf(__VA_ARGS__)
88 #else
89 #define PRINTF(...)
90 #endif
91 
92 #define LT(a, b) ((signed short)((a) - (b)) < 0)
93 
94 /*---------------------------------------------------------------------------*/
95 static int
96 read_data(struct rudolph2_conn *c, uint8_t *dataptr, int chunk)
97 {
98  int len = 0;
99 
100  if(c->cb->read_chunk) {
101  len = c->cb->read_chunk(c, chunk * RUDOLPH2_DATASIZE,
102  dataptr, RUDOLPH2_DATASIZE);
103  }
104  return len;
105 }
106 /*---------------------------------------------------------------------------*/
107 static int
108 format_data(struct rudolph2_conn *c, int chunk)
109 {
110  struct rudolph2_hdr *hdr;
111  int len;
112 
113  packetbuf_clear();
114  hdr = packetbuf_dataptr();
115  hdr->type = TYPE_DATA;
116  hdr->hops_from_base = c->hops_from_base;
117  hdr->version = c->version;
118  hdr->chunk = chunk;
119  len = read_data(c, (uint8_t *)hdr + sizeof(struct rudolph2_hdr), chunk);
120  packetbuf_set_datalen(sizeof(struct rudolph2_hdr) + len);
121 
122  return len;
123 }
124 /*---------------------------------------------------------------------------*/
125 static void
126 write_data(struct rudolph2_conn *c, int chunk, uint8_t *data, int datalen)
127 {
128  /* xxx Don't write any data if the application has been stopped. */
129  if(c->flags & FLAG_IS_STOPPED) {
130  return;
131  }
132 
133  if(chunk == 0) {
134  c->cb->write_chunk(c, 0, RUDOLPH2_FLAG_NEWFILE, data, 0);
135  }
136 
137  PRINTF("%d.%d: get %d bytes\n",
139  datalen);
140 
141 
142  if(datalen < RUDOLPH2_DATASIZE) {
143  PRINTF("%d.%d: get %d bytes, file complete\n",
145  datalen);
146  c->cb->write_chunk(c, chunk * RUDOLPH2_DATASIZE,
147  RUDOLPH2_FLAG_LASTCHUNK, data, datalen);
148  } else {
149  c->cb->write_chunk(c, chunk * RUDOLPH2_DATASIZE,
150  RUDOLPH2_FLAG_NONE, data, datalen);
151  }
152 }
153 /*---------------------------------------------------------------------------*/
154 static int
155 send_data(struct rudolph2_conn *c, clock_time_t interval)
156 {
157  int len;
158 
159  len = format_data(c, c->snd_nxt);
160  polite_send(&c->c, interval, POLITE_HEADER);
161  PRINTF("%d.%d: send_data chunk %d, rcv_nxt %d\n",
163  c->snd_nxt, c->rcv_nxt);
164 
165  return len;
166 }
167 /*---------------------------------------------------------------------------*/
168 static void
169 send_nack(struct rudolph2_conn *c)
170 {
171  struct rudolph2_hdr *hdr;
172  packetbuf_clear();
173  packetbuf_hdralloc(sizeof(struct rudolph2_hdr));
174  hdr = packetbuf_hdrptr();
175 
176  hdr->hops_from_base = c->hops_from_base;
177  hdr->type = TYPE_NACK;
178  hdr->version = c->version;
179  hdr->chunk = c->rcv_nxt;
180 
181  PRINTF("%d.%d: Sending nack for %d\n",
183  hdr->chunk);
184  polite_send(&c->c, NACK_TIMEOUT, POLITE_HEADER);
185 }
186 /*---------------------------------------------------------------------------*/
187 #if 0 /* Function below not currently used in the code */
188 static void
189 send_next(struct rudolph2_conn *c)
190 {
191  int len;
192  clock_time_t interval;
193 
194  if(c->flags & FLAG_LAST_SENT) {
195  interval = STEADY_INTERVAL;
196  } else {
197  interval = SEND_INTERVAL;
198  }
199 
200  len = send_data(c, interval);
201 
202  if(len < RUDOLPH2_DATASIZE) {
203  c->flags |= FLAG_LAST_SENT;
204  } else {
205  c->flags &= ~FLAG_LAST_SENT;
206  }
207 
208  if(c->nacks == 0 &&
209  len == RUDOLPH2_DATASIZE &&
210  c->snd_nxt + 1 < c->rcv_nxt) {
211  c->snd_nxt++;
212  }
213  c->nacks = 0;
214 }
215 #endif /* 0 */
216 /*---------------------------------------------------------------------------*/
217 static void
218 sent(struct polite_conn *polite)
219 {
220  /* struct rudolph2_conn *c = (struct rudolph2_conn *)polite;
221 
222  if((c->flags & FLAG_IS_STOPPED) == 0 &&
223  (c->flags & FLAG_LAST_RECEIVED)) {
224  if(c->snd_nxt < c->rcv_nxt) {
225  send_next(c);
226  } else {
227  send_data(c, STEADY_INTERVAL);
228  }
229  }*/
230 
231 }
232 /*---------------------------------------------------------------------------*/
233 static void
234 dropped(struct polite_conn *polite)
235 {
236  /* struct rudolph2_conn *c = (struct rudolph2_conn *)polite;
237  if((c->flags & FLAG_IS_STOPPED) == 0 &&
238  (c->flags & FLAG_LAST_RECEIVED)) {
239  if(c->snd_nxt + 1 < c->rcv_nxt) {
240  send_data(c, SEND_INTERVAL);
241  } else {
242  send_data(c, STEADY_INTERVAL);
243  }
244  }*/
245 }
246 /*---------------------------------------------------------------------------*/
247 static void
248 timed_send(void *ptr)
249 {
250  struct rudolph2_conn *c = (struct rudolph2_conn *)ptr;
251  clock_time_t interval;
252  int len;
253 
254  if((c->flags & FLAG_IS_STOPPED) == 0 &&
255  (c->flags & FLAG_LAST_RECEIVED)) {
256  /* if(c->snd_nxt + 1 < c->rcv_nxt) {
257  interval = SEND_INTERVAL;
258  } else {
259  interval = STEADY_INTERVAL;
260  }*/
261  /* send_data(c, interval);*/
262 
263  if(c->flags & FLAG_LAST_SENT) {
264  interval = STEADY_INTERVAL;
265  } else {
266  interval = SEND_INTERVAL;
267  }
268 
269 
270  len = send_data(c, interval);
271 
272  if(len < RUDOLPH2_DATASIZE) {
273  c->flags |= FLAG_LAST_SENT;
274  } else {
275  c->flags &= ~FLAG_LAST_SENT;
276  }
277 
278  if(c->nacks == 0 &&
279  len == RUDOLPH2_DATASIZE &&
280  c->snd_nxt + 1 < c->rcv_nxt) {
281  c->snd_nxt++;
282  }
283  c->nacks = 0;
284  ctimer_set(&c->t, interval, timed_send, c);
285  }
286 }
287 /*---------------------------------------------------------------------------*/
288 static void
289 recv(struct polite_conn *polite)
290 {
291  struct rudolph2_conn *c = (struct rudolph2_conn *)polite;
292  struct rudolph2_hdr *hdr = packetbuf_dataptr();
293 
294  /* Only accept NACKs from nodes that are farther away from the base
295  than us. */
296 
297  if(hdr->type == TYPE_NACK && hdr->hops_from_base > c->hops_from_base) {
298  c->nacks++;
299  PRINTF("%d.%d: Got NACK for %d:%d (%d:%d)\n",
301  hdr->version, hdr->chunk,
302  c->version, c->rcv_nxt);
303  if(hdr->version == c->version) {
304  if(hdr->chunk < c->rcv_nxt) {
305  c->snd_nxt = hdr->chunk;
306  send_data(c, SEND_INTERVAL);
307  }
308  } else if(LT(hdr->version, c->version)) {
309  c->snd_nxt = 0;
310  send_data(c, SEND_INTERVAL);
311  }
312  } else if(hdr->type == TYPE_DATA) {
313  if(hdr->hops_from_base < c->hops_from_base) {
314  /* Only accept data from nodes that are closer to the base than
315  us. */
316  c->hops_from_base = hdr->hops_from_base + 1;
317  if(LT(c->version, hdr->version)) {
318  PRINTF("%d.%d: rudolph2 new version %d, chunk %d\n",
320  hdr->version, hdr->chunk);
321  c->version = hdr->version;
322  c->snd_nxt = c->rcv_nxt = 0;
323  c->flags &= ~FLAG_LAST_RECEIVED;
324  c->flags &= ~FLAG_LAST_SENT;
325  if(hdr->chunk != 0) {
326  send_nack(c);
327  } else {
328  packetbuf_hdrreduce(sizeof(struct rudolph2_hdr));
329  write_data(c, 0, packetbuf_dataptr(), packetbuf_totlen());
330  }
331  } else if(hdr->version == c->version) {
332  PRINTF("%d.%d: got chunk %d snd_nxt %d rcv_nxt %d\n",
334  hdr->chunk, c->snd_nxt, c->rcv_nxt);
335 
336  if(hdr->chunk == c->rcv_nxt) {
337  int len;
338  packetbuf_hdrreduce(sizeof(struct rudolph2_hdr));
339  PRINTF("%d.%d: received chunk %d len %d\n",
341  hdr->chunk, packetbuf_totlen());
342  len = packetbuf_totlen();
343  write_data(c, hdr->chunk, packetbuf_dataptr(), packetbuf_totlen());
344  c->rcv_nxt++;
345  if(len < RUDOLPH2_DATASIZE) {
346  c->flags |= FLAG_LAST_RECEIVED;
347  send_data(c, RESEND_INTERVAL);
348  ctimer_set(&c->t, RESEND_INTERVAL, timed_send, c);
349  }
350  } else if(hdr->chunk > c->rcv_nxt) {
351  PRINTF("%d.%d: received chunk %d > %d, sending NACK\n",
353  hdr->chunk, c->rcv_nxt);
354  send_nack(c);
355  } else if(hdr->chunk < c->rcv_nxt) {
356  /* Ignore packets with a lower chunk number */
357  }
358  }
359  }
360  }
361 }
362 /*---------------------------------------------------------------------------*/
363 static const struct polite_callbacks polite = { recv, sent, dropped };
364 /*---------------------------------------------------------------------------*/
365 void
366 rudolph2_open(struct rudolph2_conn *c, uint16_t channel,
367  const struct rudolph2_callbacks *cb)
368 {
369  polite_open(&c->c, channel, &polite);
370  c->cb = cb;
371  c->version = 0;
372  c->hops_from_base = HOPS_MAX;
373 }
374 /*---------------------------------------------------------------------------*/
375 void
376 rudolph2_close(struct rudolph2_conn *c)
377 {
378  polite_close(&c->c);
379 }
380 /*---------------------------------------------------------------------------*/
381 void
382 rudolph2_send(struct rudolph2_conn *c, clock_time_t send_interval)
383 {
384  int len;
385 
386  c->hops_from_base = 0;
387  c->version++;
388  c->snd_nxt = 0;
389  len = RUDOLPH2_DATASIZE;
390  packetbuf_clear();
391  for(c->rcv_nxt = 0; len == RUDOLPH2_DATASIZE; c->rcv_nxt++) {
392  len = read_data(c, packetbuf_dataptr(), c->rcv_nxt);
393  }
394  c->flags = FLAG_LAST_RECEIVED;
395  /* printf("Highest chunk %d\n", c->rcv_nxt);*/
396  send_data(c, SEND_INTERVAL);
397  ctimer_set(&c->t, SEND_INTERVAL, timed_send, c);
398 }
399 /*---------------------------------------------------------------------------*/
400 void
401 rudolph2_stop(struct rudolph2_conn *c)
402 {
403  polite_cancel(&c->c);
404  c->flags |= FLAG_IS_STOPPED;
405 }
406 /*---------------------------------------------------------------------------*/
407 /** @} */
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition: packetbuf.c:172
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
int polite_send(struct polite_conn *c, clock_time_t interval, uint8_t hdrsize)
Send a packet on a polite connection.
Definition: polite.c:127
Header file for the single-hop reliable bulk data transfer module
void(* dropped)(struct polite_conn *c)
Called when a packet is dropped because a packet was heard from a neighbor.
Definition: polite.h:127
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:200
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:260
Header file for the Rime stack
Header file for Polite Anonymous best effort local Broadcast (polite)
void polite_open(struct polite_conn *c, uint16_t channel, const struct polite_callbacks *cb)
Open a polite connection.
Definition: polite.c:108
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:213
void(* sent)(struct polite_conn *c)
Called when a packet is sent on the connection.
Definition: polite.h:121
An opaque structure with no user-visible elements that holds the state of a polite connection...
Definition: polite.h:134
void polite_cancel(struct polite_conn *c)
Cancel a pending packet.
Definition: polite.c:143
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:77
void polite_close(struct polite_conn *c)
Close a polite connection.
Definition: polite.c:116
void(* recv)(struct polite_conn *c)
Called when a packet is received on the connection.
Definition: polite.h:116
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
A structure with callback functions for a polite connection.
Definition: polite.h:112
int packetbuf_hdrreduce(int size)
Reduce the header in the packetbuf, for incoming packets.
Definition: packetbuf.c:188
CFS header file.