1 /** \addtogroup servreghack
5 * Copyright (c) 2010, Swedish Institute of Computer Science.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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 $
39 * Implementation of the servreg-hack application
41 * Adam Dunkels <adam@sics.se>
45 #include "contiki-lib.h"
46 #include "contiki-net.h"
50 #include "net/uip-ds6.h"
52 #include "servreg-hack.h"
56 struct servreg_hack_registration
{
57 struct servreg_hack_registration
*next
;
66 #define MAX_REGISTRATIONS 16
68 LIST(others_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
93 purge_registrations(void)
95 struct servreg_hack_registration
*t
;
97 for(t
= list_head(own_services
);
99 t
= list_item_next(t
)) {
100 if(timer_expired(&t
->timer
)) {
102 timer_set(&t
->timer
, LIFETIME
/ 2);
106 for(t
= list_head(others_services
);
108 t
= list_item_next(t
)) {
109 if(timer_expired(&t
->timer
)) {
110 list_remove(others_services
, t
);
111 memb_free(®istrations
, t
);
112 t
= list_head(others_services
);
116 /*---------------------------------------------------------------------------*/
118 servreg_hack_init(void)
120 list_init(others_services
);
121 list_init(own_services
);
122 memb_init(®istrations
);
124 process_start(&servreg_hack_process
, NULL
);
126 /*---------------------------------------------------------------------------*/
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
);
139 t
= list_item_next(t
)) {
140 if(servreg_hack_item_id(t
) == id
) {
145 r
= memb_alloc(®istrations
);
147 printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
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 /*---------------------------------------------------------------------------*/
170 servreg_hack_item_id(servreg_hack_item_t
*item
)
172 return ((struct servreg_hack_registration
*)item
)->id
;
174 /*---------------------------------------------------------------------------*/
176 servreg_hack_item_address(servreg_hack_item_t
*item
)
178 return &((struct servreg_hack_registration
*)item
)->addr
;
180 /*---------------------------------------------------------------------------*/
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
);
195 /*---------------------------------------------------------------------------*/
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
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
215 /* printf("Handle incoming reg id %d seqno %d\n", id, seqno);*/
217 for(t
= servreg_hack_list_head();
219 t
= list_item_next(t
)) {
220 if(servreg_hack_item_id(t
) == id
) {
222 if(SEQNO_LT(r
->seqno
, seqno
)) {
224 timer_set(&r
->timer
, LIFETIME
);
226 /* Put item first on list, so that subsequent lookups will
228 list_remove(others_services
, r
);
229 list_push(others_services
, r
);
235 r
= memb_alloc(®istrations
);
237 printf("servreg_hack_register: error, could not allocate memory, should reclaim another registration but this has not been implemented yet.\n");
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 /*---------------------------------------------------------------------------*/
273 send_udp_packet(struct uip_udp_conn
*conn
)
276 uint8_t buf
[MAX_BUFSIZE
];
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;
286 bufptr
= MSG_ADDRS_OFFSET
;
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
],
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
;
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
;
321 /* printf("send_udp_packet numregs %d\n", numregs);*/
322 buf
[MSG_NUMREGS_OFFSET
] = numregs
;
325 /* printf("Sending buffer len %d\n", bufptr);*/
326 uip_udp_packet_send(conn
, buf
, bufptr
);
329 /*---------------------------------------------------------------------------*/
331 parse_incoming_packet(const u8_t
*buf
, int len
)
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
;
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
));
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());
380 /*---------------------------------------------------------------------------*/