Add missing includes
[contiki-2.x.git] / apps / servreg-hack / servreg-hack.c
blob25cfc8695159b4e83306d951abd0d2ef73173513
1 /** \addtogroup servreghack
2 * @{ */
4 /*
5 * Copyright (c) 2010, Swedish Institute of Computer Science.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the Institute nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * This file is part of the Contiki operating system.
34 * $Id: servreg-hack.c,v 1.3 2010/10/19 18:29:03 adamdunkels Exp $
37 /**
38 * \file
39 * Implementation of the servreg-hack application
40 * \author
41 * Adam Dunkels <adam@sics.se>
44 #include "contiki.h"
45 #include "contiki-lib.h"
46 #include "contiki-net.h"
48 #include "net/uip.h"
50 #include "net/uip-ds6.h"
52 #include "servreg-hack.h"
54 #include <stdio.h>
56 struct servreg_hack_registration {
57 struct servreg_hack_registration *next;
59 struct timer timer;
60 uip_ipaddr_t addr;
61 servreg_hack_id_t id;
62 uint8_t seqno;
66 #define MAX_REGISTRATIONS 16
68 LIST(others_services);
69 LIST(own_services);
71 MEMB(registrations, struct servreg_hack_registration, MAX_REGISTRATIONS);
73 PROCESS(servreg_hack_process, "Service regstry hack");
75 #define PERIOD_TIME 120 * CLOCK_SECOND
77 #define NEW_REG_TIME 10 * CLOCK_SECOND
79 #define MAX_BUFSIZE 2 + 80
81 #define UDP_PORT 61616
83 #define LIFETIME 10 * 60 * CLOCK_SECOND
85 #define SEQNO_LT(a, b) ((signed char)((a) - (b)) < 0)
87 static struct etimer sendtimer;
89 /*---------------------------------------------------------------------------*/
90 /* Go through the list of registrations and remove those that are too
91 old. */
92 static void
93 purge_registrations(void)
95 struct servreg_hack_registration *t;
97 for(t = list_head(own_services);
98 t != NULL;
99 t = list_item_next(t)) {
100 if(timer_expired(&t->timer)) {
101 t->seqno++;
102 timer_set(&t->timer, LIFETIME / 2);
106 for(t = list_head(others_services);
107 t != NULL;
108 t = list_item_next(t)) {
109 if(timer_expired(&t->timer)) {
110 list_remove(others_services, t);
111 memb_free(&registrations, t);
112 t = list_head(others_services);
116 /*---------------------------------------------------------------------------*/
117 void
118 servreg_hack_init(void)
120 list_init(others_services);
121 list_init(own_services);
122 memb_init(&registrations);
124 process_start(&servreg_hack_process, NULL);
126 /*---------------------------------------------------------------------------*/
127 void
128 servreg_hack_register(servreg_hack_id_t id)
130 servreg_hack_item_t *t;
131 struct servreg_hack_registration *r;
132 /* Walk through list, see if we already have a service ID
133 registered. If not, allocate a new registration and put it on our
134 list. If we cannot allocate a service registration, we reuse one
135 from the service registrations made by others. */
137 for(t = list_head(own_services);
138 t != NULL;
139 t = list_item_next(t)) {
140 if(servreg_hack_item_id(t) == id) {
141 return;
145 r = memb_alloc(&registrations);
146 if(r == NULL) {
147 printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
148 return;
150 r->id = id;
151 r->seqno = 1;
152 timer_set(&r->timer, LIFETIME / 2);
153 list_push(own_services, r);
156 PROCESS_CONTEXT_BEGIN(&servreg_hack_process);
157 etimer_set(&sendtimer, random_rand() % (NEW_REG_TIME));
158 PROCESS_CONTEXT_END(&servreg_hack_process);
161 /*---------------------------------------------------------------------------*/
162 servreg_hack_item_t *
163 servreg_hack_list_head(void)
165 purge_registrations();
166 return list_head(others_services);
168 /*---------------------------------------------------------------------------*/
169 servreg_hack_id_t
170 servreg_hack_item_id(servreg_hack_item_t *item)
172 return ((struct servreg_hack_registration *)item)->id;
174 /*---------------------------------------------------------------------------*/
175 uip_ipaddr_t *
176 servreg_hack_item_address(servreg_hack_item_t *item)
178 return &((struct servreg_hack_registration *)item)->addr;
180 /*---------------------------------------------------------------------------*/
181 uip_ipaddr_t *
182 servreg_hack_lookup(servreg_hack_id_t id)
184 servreg_hack_item_t *t;
186 purge_registrations();
188 for(t = servreg_hack_list_head(); t != NULL; t = list_item_next(t)) {
189 if(servreg_hack_item_id(t) == id) {
190 return servreg_hack_item_address(t);
193 return NULL;
195 /*---------------------------------------------------------------------------*/
196 static void
197 handle_incoming_reg(const uip_ipaddr_t *owner, servreg_hack_id_t id, uint8_t seqno)
199 servreg_hack_item_t *t;
200 struct servreg_hack_registration *r;
202 /* Walk through list, see if we already have a service ID
203 registered. If so, we do different things depending on the seqno
204 of the update: if the seqno is older than what we have, we
205 discard the incoming registration. If the seqno is newer than
206 what we have, we reset the lifetime timer of the current
207 registration.
209 If we did not have the service registered already, we allocate a
210 new registration and put it on our list. If we cannot allocate a
211 service registration, we discard the incoming registration (for
212 now - we might later choose to discard the oldest registration
213 that we have). */
215 /* printf("Handle incoming reg id %d seqno %d\n", id, seqno);*/
217 for(t = servreg_hack_list_head();
218 t != NULL;
219 t = list_item_next(t)) {
220 if(servreg_hack_item_id(t) == id) {
221 r = t;
222 if(SEQNO_LT(r->seqno, seqno)) {
223 r->seqno = seqno;
224 timer_set(&r->timer, LIFETIME);
226 /* Put item first on list, so that subsequent lookups will
227 find this one. */
228 list_remove(others_services, r);
229 list_push(others_services, r);
231 return;
235 r = memb_alloc(&registrations);
236 if(r == NULL) {
237 printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
238 return;
240 r->id = id;
241 r->seqno = 1;
242 uip_ipaddr_copy(&r->addr, owner);
243 timer_set(&r->timer, LIFETIME);
244 list_add(others_services, r);
246 /*---------------------------------------------------------------------------*/
248 * The structure of UDP messages:
250 * +-------------------+-------------------+
251 * | Numregs (1 byte) | Flags (1 byte) |
252 * +-------------------+-------------------+-------------------+
253 * | IP addr (16 bytes)| 3 regs (3 bytes) | Seqno (1 byte) |
254 * +-------------------+-------------------+-------------------+
255 * | IP addr (16 bytes)| 3 regs (3 bytes) | Seqno (1 byte) |
256 * +-------------------+-------------------+-------------------+
257 * | ... | ... | ... |
258 * +-------------------+-------------------+-------------------+
261 #define MSG_NUMREGS_OFFSET 0
262 #define MSG_FLAGS_OFFSET 1
263 #define MSG_ADDRS_OFFSET 2
265 #define MSG_IPADDR_SUBOFFSET 0
266 #define MSG_REGS_SUBOFFSET 16
267 #define MSG_SEQNO_SUBOFFSET 19
269 #define MSG_ADDRS_LEN 20
271 /*---------------------------------------------------------------------------*/
272 static void
273 send_udp_packet(struct uip_udp_conn *conn)
275 int numregs;
276 uint8_t buf[MAX_BUFSIZE];
277 int bufptr;
278 servreg_hack_item_t *t;
279 uip_ds6_addr_t *addr;
281 addr = uip_ds6_get_global(-1);
283 buf[MSG_FLAGS_OFFSET] = 0;
285 numregs = 0;
286 bufptr = MSG_ADDRS_OFFSET;
289 if(addr != NULL) {
290 for(t = list_head(own_services);
291 (bufptr + MSG_ADDRS_LEN <= MAX_BUFSIZE) && t != NULL;
292 t = list_item_next(t)) {
294 uip_ipaddr_copy((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
295 &addr->ipaddr);
296 buf[bufptr + MSG_REGS_SUBOFFSET] =
297 servreg_hack_item_id(t);
298 buf[bufptr + MSG_REGS_SUBOFFSET + 1] =
299 buf[bufptr + MSG_REGS_SUBOFFSET + 2] = 0;
300 buf[bufptr + MSG_SEQNO_SUBOFFSET] = ((struct servreg_hack_registration *)t)->seqno;
302 bufptr += MSG_ADDRS_LEN;
303 ++numregs;
307 for(t = servreg_hack_list_head();
308 (bufptr + MSG_ADDRS_LEN <= MAX_BUFSIZE) && t != NULL;
309 t = list_item_next(t)) {
310 uip_ipaddr_copy((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
311 servreg_hack_item_address(t));
312 buf[bufptr + MSG_REGS_SUBOFFSET] =
313 servreg_hack_item_id(t);
314 buf[bufptr + MSG_REGS_SUBOFFSET + 1] =
315 buf[bufptr + MSG_REGS_SUBOFFSET + 2] = 0;
316 buf[bufptr + MSG_SEQNO_SUBOFFSET] = ((struct servreg_hack_registration *)t)->seqno;
318 bufptr += MSG_ADDRS_LEN;
319 ++numregs;
321 /* printf("send_udp_packet numregs %d\n", numregs);*/
322 buf[MSG_NUMREGS_OFFSET] = numregs;
324 if(numregs > 0) {
325 /* printf("Sending buffer len %d\n", bufptr);*/
326 uip_udp_packet_send(conn, buf, bufptr);
329 /*---------------------------------------------------------------------------*/
330 static void
331 parse_incoming_packet(const u8_t *buf, int len)
333 int numregs;
334 int flags;
335 int i;
336 int bufptr;
338 numregs = buf[MSG_NUMREGS_OFFSET];
339 flags = buf[MSG_FLAGS_OFFSET];
341 /* printf("Numregs %d flags %d\n", numregs, flags);*/
343 bufptr = MSG_ADDRS_OFFSET;
344 for(i = 0; i < numregs; ++i) {
345 handle_incoming_reg((uip_ipaddr_t *)&buf[bufptr + MSG_IPADDR_SUBOFFSET],
346 buf[bufptr + MSG_REGS_SUBOFFSET],
347 buf[bufptr + MSG_SEQNO_SUBOFFSET]);
350 /*---------------------------------------------------------------------------*/
351 PROCESS_THREAD(servreg_hack_process, ev, data)
353 static struct etimer periodic;
354 static struct uip_udp_conn *outconn, *inconn;
355 PROCESS_BEGIN();
357 /* Create outbound UDP connection. */
358 outconn = udp_broadcast_new(UIP_HTONS(UDP_PORT), NULL);
359 udp_bind(outconn, UIP_HTONS(UDP_PORT));
361 /* Create inbound UDP connection. */
362 inconn = udp_new(NULL, UIP_HTONS(UDP_PORT), NULL);
363 udp_bind(inconn, UIP_HTONS(UDP_PORT));
365 etimer_set(&periodic, PERIOD_TIME);
366 etimer_set(&sendtimer, random_rand() % (PERIOD_TIME));
367 while(1) {
368 PROCESS_WAIT_EVENT();
369 if(ev == PROCESS_EVENT_TIMER && data == &periodic) {
370 etimer_reset(&periodic);
371 etimer_set(&sendtimer, random_rand() % (PERIOD_TIME));
372 } else if(ev == PROCESS_EVENT_TIMER && data == &sendtimer) {
373 send_udp_packet(outconn);
374 } else if(ev == tcpip_event) {
375 parse_incoming_packet(uip_appdata, uip_datalen());
378 PROCESS_END();
380 /*---------------------------------------------------------------------------*/