Contiki 3.x
servreg-hack.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, 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  * Implementation of the servreg-hack application
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 /** \addtogroup servreghack
41  * @{ */
42 
43 #include "contiki.h"
44 #include "contiki-lib.h"
45 #include "contiki-net.h"
46 
47 #include "net/ip/uip.h"
48 
49 #include "net/ipv6/uip-ds6.h"
50 
51 #include "servreg-hack.h"
52 
53 #include <stdio.h>
54 
55 struct servreg_hack_registration {
56  struct servreg_hack_registration *next;
57 
58  struct timer timer;
59  uip_ipaddr_t addr;
60  servreg_hack_id_t id;
61  uint8_t seqno;
62 };
63 
64 
65 #define MAX_REGISTRATIONS 16
66 
67 LIST(others_services);
68 LIST(own_services);
69 
70 MEMB(registrations, struct servreg_hack_registration, MAX_REGISTRATIONS);
71 
72 PROCESS(servreg_hack_process, "Service regstry hack");
73 
74 #define PERIOD_TIME 120 * CLOCK_SECOND
75 
76 #define NEW_REG_TIME 10 * CLOCK_SECOND
77 
78 #define MAX_BUFSIZE 2 + 80
79 
80 #define UDP_PORT 61616
81 
82 #define LIFETIME 10 * 60 * CLOCK_SECOND
83 
84 #define SEQNO_LT(a, b) ((signed char)((a) - (b)) < 0)
85 
86 static struct etimer sendtimer;
87 
88 static uint8_t started = 0;
89 
90 /*---------------------------------------------------------------------------*/
91 /* Go through the list of registrations and remove those that are too
92  old. */
93 static void
94 purge_registrations(void)
95 {
96  struct servreg_hack_registration *t;
97 
98  for(t = list_head(own_services);
99  t != NULL;
100  t = list_item_next(t)) {
101  if(timer_expired(&t->timer)) {
102  t->seqno++;
103  timer_set(&t->timer, LIFETIME / 2);
104  }
105  }
106 
107  for(t = list_head(others_services);
108  t != NULL;
109  t = list_item_next(t)) {
110  if(timer_expired(&t->timer)) {
111  list_remove(others_services, t);
112  memb_free(&registrations, t);
113  t = list_head(others_services);
114  }
115  }
116 }
117 /*---------------------------------------------------------------------------*/
118 void
120 {
121  if(started == 0) {
122  list_init(others_services);
123  list_init(own_services);
124  memb_init(&registrations);
125 
126  process_start(&servreg_hack_process, NULL);
127  started = 1;
128  }
129 }
130 /*---------------------------------------------------------------------------*/
131 void
132 servreg_hack_register(servreg_hack_id_t id, const uip_ipaddr_t *addr)
133 {
134  servreg_hack_item_t *t;
135  struct servreg_hack_registration *r;
136  /* Walk through list, see if we already have a service ID
137  registered. If not, allocate a new registration and put it on our
138  list. If we cannot allocate a service registration, we reuse one
139  from the service registrations made by others. */
140 
142 
143  for(t = list_head(own_services);
144  t != NULL;
145  t = list_item_next(t)) {
146  if(servreg_hack_item_id(t) == id) {
147  return;
148  }
149  }
150 
151  r = memb_alloc(&registrations);
152  if(r == NULL) {
153  printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
154  return;
155  }
156  r->id = id;
157  r->seqno = 1;
158  uip_ipaddr_copy(&r->addr, addr);
159  timer_set(&r->timer, LIFETIME / 2);
160  list_push(own_services, r);
161 
162 
163  PROCESS_CONTEXT_BEGIN(&servreg_hack_process);
164  etimer_set(&sendtimer, random_rand() % (NEW_REG_TIME));
165  PROCESS_CONTEXT_END(&servreg_hack_process);
166 
167 }
168 /*---------------------------------------------------------------------------*/
169 servreg_hack_item_t *
171 {
172  purge_registrations();
173  return list_head(others_services);
174 }
175 /*---------------------------------------------------------------------------*/
176 servreg_hack_id_t
177 servreg_hack_item_id(servreg_hack_item_t *item)
178 {
179  return ((struct servreg_hack_registration *)item)->id;
180 }
181 /*---------------------------------------------------------------------------*/
182 uip_ipaddr_t *
183 servreg_hack_item_address(servreg_hack_item_t *item)
184 {
185  return &((struct servreg_hack_registration *)item)->addr;
186 }
187 /*---------------------------------------------------------------------------*/
188 uip_ipaddr_t *
189 servreg_hack_lookup(servreg_hack_id_t id)
190 {
191  servreg_hack_item_t *t;
192 
194 
195  purge_registrations();
196 
197  for(t = servreg_hack_list_head(); t != NULL; t = list_item_next(t)) {
198  if(servreg_hack_item_id(t) == id) {
199  return servreg_hack_item_address(t);
200  }
201  }
202  return NULL;
203 }
204 /*---------------------------------------------------------------------------*/
205 static void
206 handle_incoming_reg(const uip_ipaddr_t *owner, servreg_hack_id_t id, uint8_t seqno)
207 {
208  servreg_hack_item_t *t;
209  struct servreg_hack_registration *r;
210 
211  /* Walk through list, see if we already have a service ID
212  registered. If so, we do different things depending on the seqno
213  of the update: if the seqno is older than what we have, we
214  discard the incoming registration. If the seqno is newer than
215  what we have, we reset the lifetime timer of the current
216  registration.
217 
218  If we did not have the service registered already, we allocate a
219  new registration and put it on our list. If we cannot allocate a
220  service registration, we discard the incoming registration (for
221  now - we might later choose to discard the oldest registration
222  that we have). */
223 
224  for(t = servreg_hack_list_head();
225  t != NULL;
226  t = list_item_next(t)) {
227  if(servreg_hack_item_id(t) == id) {
228  r = t;
229  if(SEQNO_LT(r->seqno, seqno)) {
230  r->seqno = seqno;
231  timer_set(&r->timer, LIFETIME);
232 
233  /* Put item first on list, so that subsequent lookups will
234  find this one. */
235  list_remove(others_services, r);
236  list_push(others_services, r);
237  }
238  return;
239  }
240  }
241 
242  r = memb_alloc(&registrations);
243  if(r == NULL) {
244  printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
245  return;
246  }
247  r->id = id;
248  r->seqno = 1;
249  uip_ipaddr_copy(&r->addr, owner);
250  timer_set(&r->timer, LIFETIME);
251  list_add(others_services, r);
252 }
253 /*---------------------------------------------------------------------------*/
254 /*
255  * The structure of UDP messages:
256  *
257  * +-------------------+-------------------+
258  * | Numregs (1 byte) | Flags (1 byte) |
259  * +-------------------+-------------------+-------------------+
260  * | IP addr (16 bytes)| 3 regs (3 bytes) | Seqno (1 byte) |
261  * +-------------------+-------------------+-------------------+
262  * | IP addr (16 bytes)| 3 regs (3 bytes) | Seqno (1 byte) |
263  * +-------------------+-------------------+-------------------+
264  * | ... | ... | ... |
265  * +-------------------+-------------------+-------------------+
266  */
267 
268 #define MSG_NUMREGS_OFFSET 0
269 #define MSG_FLAGS_OFFSET 1
270 #define MSG_ADDRS_OFFSET 2
271 
272 #define MSG_IPADDR_SUBOFFSET 0
273 #define MSG_REGS_SUBOFFSET 16
274 #define MSG_SEQNO_SUBOFFSET 19
275 
276 #define MSG_ADDRS_LEN 20
277 
278 /*---------------------------------------------------------------------------*/
279 static void
280 send_udp_packet(struct uip_udp_conn *conn)
281 {
282  int numregs;
283  uint8_t buf[MAX_BUFSIZE];
284  int bufptr;
285  servreg_hack_item_t *t;
286 
287  buf[MSG_FLAGS_OFFSET] = 0;
288 
289  numregs = 0;
290  bufptr = MSG_ADDRS_OFFSET;
291 
292  for(t = list_head(own_services);
293  (bufptr + MSG_ADDRS_LEN <= MAX_BUFSIZE) && t != NULL;
294  t = list_item_next(t)) {
295 
296  uip_ipaddr_copy((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
298  buf[bufptr + MSG_REGS_SUBOFFSET] =
300  buf[bufptr + MSG_REGS_SUBOFFSET + 1] =
301  buf[bufptr + MSG_REGS_SUBOFFSET + 2] = 0;
302  buf[bufptr + MSG_SEQNO_SUBOFFSET] = ((struct servreg_hack_registration *)t)->seqno;
303 
304  bufptr += MSG_ADDRS_LEN;
305  ++numregs;
306  }
307 
308  for(t = servreg_hack_list_head();
309  (bufptr + MSG_ADDRS_LEN <= MAX_BUFSIZE) && t != NULL;
310  t = list_item_next(t)) {
311  uip_ipaddr_copy((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
313  buf[bufptr + MSG_REGS_SUBOFFSET] =
315  buf[bufptr + MSG_REGS_SUBOFFSET + 1] =
316  buf[bufptr + MSG_REGS_SUBOFFSET + 2] = 0;
317  buf[bufptr + MSG_SEQNO_SUBOFFSET] = ((struct servreg_hack_registration *)t)->seqno;
318 
319  bufptr += MSG_ADDRS_LEN;
320  ++numregs;
321  }
322  /* printf("send_udp_packet numregs %d\n", numregs);*/
323  buf[MSG_NUMREGS_OFFSET] = numregs;
324 
325  if(numregs > 0) {
326  /* printf("Sending buffer len %d\n", bufptr);*/
327  uip_udp_packet_send(conn, buf, bufptr);
328  }
329 }
330 /*---------------------------------------------------------------------------*/
331 static void
332 parse_incoming_packet(const uint8_t *buf, int len)
333 {
334  int numregs;
335  int flags;
336  int i;
337  int bufptr;
338 
339  numregs = buf[MSG_NUMREGS_OFFSET];
340  flags = buf[MSG_FLAGS_OFFSET];
341 
342  /* printf("parse_incoming_packet Numregs %d flags %d\n", numregs, flags);*/
343 
344  bufptr = MSG_ADDRS_OFFSET;
345  for(i = 0; i < numregs; ++i) {
346  handle_incoming_reg((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
347  buf[bufptr + MSG_REGS_SUBOFFSET],
348  buf[bufptr + MSG_SEQNO_SUBOFFSET]);
349  }
350 }
351 /*---------------------------------------------------------------------------*/
352 PROCESS_THREAD(servreg_hack_process, ev, data)
353 {
354  static struct etimer periodic;
355  static struct uip_udp_conn *outconn, *inconn;
356  PROCESS_BEGIN();
357 
358  /* Create outbound UDP connection. */
359  outconn = udp_broadcast_new(UIP_HTONS(UDP_PORT), NULL);
360  udp_bind(outconn, UIP_HTONS(UDP_PORT));
361 
362  /* Create inbound UDP connection. */
363  inconn = udp_new(NULL, UIP_HTONS(UDP_PORT), NULL);
364  udp_bind(inconn, UIP_HTONS(UDP_PORT));
365 
366  etimer_set(&periodic, PERIOD_TIME);
367  etimer_set(&sendtimer, random_rand() % (PERIOD_TIME));
368  while(1) {
370  if(ev == PROCESS_EVENT_TIMER && data == &periodic) {
371  etimer_reset(&periodic);
372  etimer_set(&sendtimer, random_rand() % (PERIOD_TIME));
373  } else if(ev == PROCESS_EVENT_TIMER && data == &sendtimer) {
374  send_udp_packet(outconn);
375  } else if(ev == tcpip_event) {
376  parse_incoming_packet(uip_appdata, uip_datalen());
377  }
378  }
379  PROCESS_END();
380 }
381 /*---------------------------------------------------------------------------*/
uip_ipaddr_t * servreg_hack_lookup(servreg_hack_id_t id)
Get the IP address of a node offering a service.
Definition: servreg-hack.c:189
A timer.
Definition: timer.h:86
void memb_init(struct memb *m)
Initialize a memory block that was declared with MEMB().
Definition: memb.c:52
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:165
void servreg_hack_init(void)
Initialize and start the servreg-hack application.
Definition: servreg-hack.c:119
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the uIP TCP/IP stack.
CCIF struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
Network interface and stateless autoconfiguration (RFC 4862)
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
servreg_hack_id_t servreg_hack_item_id(servreg_hack_item_t *item)
Get the service ID for a list item.
Definition: servreg-hack.c:177
void timer_set(struct timer *t, clock_time_t interval)
Set a timer.
Definition: timer.c:64
char memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
Definition: memb.c:79
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define NULL
The null pointer.
#define UIP_HTONS(n)
Convert 16-bit quantity from host byte order to network byte order.
Definition: uip.h:1238
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
struct uip_udp_conn * udp_broadcast_new(uint16_t port, void *appstate)
Create a new UDP broadcast connection.
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
servreg_hack_item_t * servreg_hack_list_head(void)
Obtain the list of services provided by neighbors.
Definition: servreg-hack.c:170
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define LIST(name)
Declare a linked list.
Definition: list.h:86
uip_ipaddr_t * servreg_hack_item_address(servreg_hack_item_t *item)
Get the IP address for a list item.
Definition: servreg-hack.c:183
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:184
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
Definition: uip.h:651
process_event_t tcpip_event
The uIP event.
Definition: tcpip.c:75
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
Header file for the servreg-hack application
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
#define udp_bind(conn, port)
Bind a UDP connection to a local port.
Definition: tcpip.h:262
#define PROCESS_CONTEXT_BEGIN(p)
Switch context to another process.
Definition: process.h:426
Representation of a uIP UDP connection.
Definition: uip.h:1394
int timer_expired(struct timer *t)
Check if a timer has expired.
Definition: timer.c:121
A timer.
Definition: etimer.h:76
void servreg_hack_register(servreg_hack_id_t id, const uip_ipaddr_t *addr)
Register that this node provides a service.
Definition: servreg-hack.c:132
unsigned short random_rand(void)
Generate the next state and return the upper part of it.
Definition: random.c:47
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74
#define PROCESS_CONTEXT_END(p)
End a context switch.
Definition: process.h:440