f168d9648aff2e794f2ec0bb7e2c4d23e8b812f4
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / subscribe.c
1 /* subscribe.c -- subscription handling for CoAP
2  *                see draft-ietf-coap-observe-09
3  *
4  * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see
7  * README for terms of use.
8  */
9
10 #include "config.h"
11
12 #if defined(HAVE_ASSERT_H) && !defined(assert)
13 # include <assert.h>
14 #endif
15
16 #include <stdio.h>
17 #include <limits.h>
18 #ifdef HAVE_ARPA_INET_H
19 # include <arpa/inet.h>
20 #endif
21
22 /* #include "resource.h" */
23
24 #include "mem.h"
25 #include "encode.h"
26 #include "debug.h"
27 #include "subscribe.h"
28
29 void coap_subscription_init(coap_subscription_t *s)
30 {
31     assert(s);
32     memset(s, 0, sizeof(coap_subscription_t));
33 }
34
35 #if 0
36 #define HMASK (ULONG_MAX >> 1)
37
38 void
39 notify(coap_context_t *context, coap_resource_t *res,
40         coap_subscription_t *sub, unsigned int duration, int code)
41 {
42 #if 0
43     coap_pdu_t *pdu;
44     int ls, finished=0;
45     unsigned char ct, d;
46     unsigned int length;
47 #ifndef NDEBUG
48     char addr[INET6_ADDRSTRLEN];
49 #endif
50
51     if ( !context || !res || !sub || !(pdu = coap_new_pdu()) )
52     return;
53
54     pdu->hdr->coap_hdr_udp_t.type = COAP_MESSAGE_CON;
55     pdu->hdr->coap_hdr_udp_t.id = rand(); /* use a random transaction id */
56     pdu->hdr->coap_hdr_udp_t.code = code;
57
58     /* FIXME: content-type and data (how about block?) */
59     if (res->uri->host.length)
60     coap_add_option (pdu, COAP_OPTION_URI_HOST,
61             res->uri->host.length,
62             res->uri->host.s );
63
64     if (res->uri->path.length)
65     coap_add_option (pdu, COAP_OPTION_URI_PATH,
66             res->uri->path.length,
67             res->uri->path.s);
68
69     d = COAP_PSEUDOFP_ENCODE_8_4_DOWN(duration, ls);
70
71     coap_add_option ( pdu, COAP_OPTION_SUBSCRIPTION, 1, &d );
72
73     if (sub->token.length)
74     {
75         coap_add_option (pdu, COAP_OPTION_TOKEN,
76                 sub->token.length,
77                 sub->token.s);
78     }
79
80     if (res->uri->query.length)
81     coap_add_option (pdu, COAP_OPTION_URI_QUERY,
82             res->uri->query.length,
83             res->uri->query.s );
84
85     if (res->data)
86     {
87         length = (unsigned char *)pdu->hdr + COAP_MAX_PDU_SIZE - pdu->data;
88         ct = res->mediatype;
89         res->data(res->uri, &ct, 0, pdu->data, &length, &finished);
90         pdu->length += length;
91
92         /* TODO: add block option if not finished */
93         /* TODO: add mediatype */
94     }
95
96 #ifndef NDEBUG
97     if ( inet_ntop(sub->subscriber.addr.sa.sa_family,
98                     &sub->subscriber.addr, addr, sizeof(addr)) )
99     {
100         debug("*** notify for %s to [%s]\n", res->uri->path.s, addr);
101     }
102 #endif
103     if (pdu && coap_send_confirmed(context,
104                     &sub->subscriber.addr.sa,
105                     sub->subscriber.size, pdu)
106             == COAP_INVALID_TID)
107     {
108 #ifndef NDEBUG
109         debug("coap_check_resource_list: error sending notification\n");
110 #endif
111         coap_delete_pdu(pdu);
112     }
113 #endif
114 }
115
116 void
117 coap_check_resource_list(coap_context_t *context)
118 {
119     coap_resource_t *res, *tmp;
120     coap_list_t *sub;
121     coap_key_t key;
122     time_t now;
123
124     if ( !context || !context->resources /* || !context->subscribers */)
125     return;
126
127     time(&now); /* FIXME: use coap_ticks() */
128
129     HASH_ITER(hh, context->resources, res, tmp)
130     {
131         if (res->dirty)
132         {
133             debug("FIXME: notify subscribers\n");
134 #if 0
135             key = coap_uri_hash( COAP_RESOURCE(res)->uri );
136
137             /* is subscribed? */
138             for (sub = context->subscriptions; sub; sub = sub->next)
139             {
140                 if ( COAP_SUBSCRIPTION(sub)->resource == key )
141                 {
142                     /* notify subscriber */
143                     notify(context, COAP_RESOURCE(res), COAP_SUBSCRIPTION(sub),
144                             COAP_SUBSCRIPTION(sub)->expires - now, COAP_RESPONSE_200);
145                 }
146
147             }
148
149             COAP_RESOURCE(res)->dirty = 0;
150 #endif
151         }
152     }
153 }
154
155 #if 0
156 coap_resource_t *
157 coap_get_resource_from_key(coap_context_t *ctx, coap_key_t key)
158 {
159     coap_list_t *node;
160
161     if (ctx)
162     {
163         /* TODO: use hash table for resources with key to access */
164         for (node = ctx->resources; node; node = node->next)
165         {
166             printf("check %ux\n", coap_uri_hash(COAP_RESOURCE(node)->uri));
167             if ( key == coap_uri_hash(COAP_RESOURCE(node)->uri) )
168             {
169                 printf("found\n");
170                 return COAP_RESOURCE(node);
171             }
172         }
173     }
174
175     printf("not found\n");
176     return NULL;
177 }
178
179 coap_resource_t *
180 coap_get_resource(coap_context_t *ctx, coap_uri_t *uri)
181 {
182 #ifndef NDEBUG
183     int i;
184     printf("search resource %ux", coap_uri_hash(uri));
185     for (i=0; i < uri->path.length; ++i)
186     {
187         printf(" %02x", uri->path.s[i]);
188     }
189     printf("\n");
190 #endif
191     return uri ? coap_get_resource_from_key(ctx, coap_uri_hash(uri)) : NULL;
192 }
193 #endif
194
195 void
196 coap_check_subscriptions(coap_context_t *context)
197 {
198     time_t now;
199     coap_list_t *node;
200 #ifndef NDEBUG
201     char addr[INET6_ADDRSTRLEN];
202 #endif
203
204     if ( !context )
205     return;
206
207     time(&now);
208
209     node = context->subscriptions;
210     while ( node && COAP_SUBSCRIPTION(node)->expires < now )
211     {
212 #ifndef NDEBUG
213         if (inet_ntop(COAP_SUBSCRIPTION(node)->subscriber.addr.sa.sa_family,
214                         &COAP_SUBSCRIPTION(node)->subscriber.addr,
215                         addr, sizeof(addr)))
216         {
217
218             debug("** removed expired subscription from [%s]\n", addr);
219         }
220 #endif
221 #if 0
222         notify(context,
223                 coap_get_resource_from_key(context, COAP_SUBSCRIPTION(node)->resource),
224                 COAP_SUBSCRIPTION(node),
225                 0, COAP_RESPONSE_400);
226 #endif
227         context->subscriptions = node->next;
228         coap_delete(node);
229         node = context->subscriptions;
230     }
231 }
232
233 void
234 coap_free_resource(void *res)
235 {
236     if ( res )
237     {
238 #if 0
239         coap_free(((coap_resource_t *)res)->uri);
240         coap_delete_string(((coap_resource_t *)res)->name);
241 #endif
242     }
243 }
244
245 #if 0
246 /**
247  * Deletes the resource that is identified by key. Returns 1 if the resource was
248  * removed, 0 on error (e.g. if no such resource exists).
249  */
250 int
251 coap_delete_resource(coap_context_t *context, coap_key_t key)
252 {
253     coap_list_t *prev, *node;
254
255     if (!context || key == COAP_INVALID_HASHKEY)
256     return 0;
257
258     for (prev = NULL, node = context->resources; node;
259             prev = node, node = node->next)
260     {
261         if (coap_uri_hash(COAP_RESOURCE(node)->uri) == key)
262         {
263 #ifndef NDEBUG
264             debug("removed key %lu (%s)\n",key,COAP_RESOURCE(node)->uri->path.s);
265 #endif
266             if (!prev)
267             context->resources = node->next;
268             else
269             prev->next = node->next;
270
271             coap_delete(node);
272             return 1;
273         }
274     }
275     return 0;
276 }
277 #endif
278
279 coap_subscription_t *
280 coap_new_subscription(coap_context_t *context, const coap_uri_t *resource,
281         const struct sockaddr *addr, socklen_t addrlen, time_t expiry)
282 {
283     coap_subscription_t *result;
284
285     if ( !context || !resource || !addr
286             || !(result = coap_malloc(sizeof(coap_subscription_t))))
287     return NULL;
288
289     result->resource = coap_uri_hash(resource);
290     result->expires = expiry;
291     memcpy(&result->subscriber.addr.sa, addr, addrlen);
292
293     memset(&result->token, 0, sizeof(str));
294
295     return result;
296
297 }
298
299 coap_list_t *
300 coap_list_push_first(coap_list_t **list, void *data, void (*delete_func)(void *) )
301 {
302     coap_list_t *node;
303     node = coap_new_listnode(data, delete_func);
304     if ( !node || !list )
305     return NULL;
306
307     if ( !*list )
308     {
309         *list = node;
310     }
311     else
312     {
313         node->next = *list;
314         *list = node;
315     }
316
317     return node;
318 }
319
320 int
321 _order_subscription(void *a, void *b)
322 {
323     if ( !a || !b )
324     return a < b ? -1 : 1;
325
326     return ((coap_subscription_t *)a)->expires < ((coap_subscription_t *)b)->expires ? -1 : 1;
327 }
328
329 coap_key_t
330 coap_subscription_hash(coap_subscription_t *subscription)
331 {
332     if ( !subscription )
333     return COAP_INVALID_HASHKEY;
334
335     return _hash2( subscription->resource, (unsigned char *)&subscription->subscriber,
336             sizeof(subscription->subscriber) );
337 }
338
339 coap_key_t
340 coap_add_subscription(coap_context_t *context,
341         coap_subscription_t *subscription)
342 {
343     coap_list_t *node;
344     if ( !context || !subscription )
345     return COAP_INVALID_HASHKEY;
346
347     if ( !(node = coap_new_listnode(subscription, NULL)) )
348     return COAP_INVALID_HASHKEY;
349
350     if ( !coap_insert(&context->subscriptions, node, _order_subscription ) )
351     {
352         coap_free( node ); /* do not call coap_delete(), so subscription object will survive */
353         return COAP_INVALID_HASHKEY;
354     }
355
356     return coap_subscription_hash(subscription);
357 }
358
359 coap_subscription_t *
360 coap_find_subscription(coap_context_t *context,
361         coap_key_t hashkey,
362         struct sockaddr *addr,
363         str *token)
364 {
365 #if 0
366     coap_list_t *node;
367 #endif
368
369     if (!context || !addr || hashkey == COAP_INVALID_HASHKEY)
370     return NULL;
371
372     /* FIXME: I do not like the way subscriptions work right now. To be fixed. */
373
374 #if 0
375     for (node = context->subscriptions; node; node = node->next)
376     {
377         if (COAP_SUBSCRIPTION(node)->resource == hashkey)
378         {
379
380             if (token)
381             { /* do not proceed if tokens do not match */
382                 if (token->length != COAP_SUBSCRIPTION(node)->token.length ||
383                         memcmp(token->s, COAP_SUBSCRIPTION(node)->token.s,
384                                 token->length) != 0)
385                 continue;
386             }
387
388             if (subscriber->sin6_port == COAP_SUBSCRIPTION(node)->subscriber.sin6_port
389                     && memcmp(&subscriber->sin6_addr,
390                             &COAP_SUBSCRIPTION(node)->subscriber.sin6_addr,
391                             sizeof(struct in6_addr)) == 0)
392             return COAP_SUBSCRIPTION(node);
393         }
394     }
395 #endif
396     return NULL;
397 }
398
399 int
400 coap_delete_subscription(coap_context_t *context,
401         coap_key_t key,
402         struct sockaddr *addr)
403 {
404 #if 0
405     coap_list_t *prev, *node;
406 #endif
407
408     if (!context || !addr || key == COAP_INVALID_HASHKEY)
409     return 0;
410
411     /* FIXME: I do not like the way subscriptions work right now. To be fixed. */
412
413 #if 0
414     for (prev = NULL, node = context->subscriptions; node;
415             prev = node, node = node->next)
416     {
417         if (COAP_SUBSCRIPTION(node)->resource == key)
418         {
419             if (subscriber->sin6_port == COAP_SUBSCRIPTION(node)->subscriber.sin6_port
420                     && memcmp(&subscriber->sin6_addr,
421                             &COAP_SUBSCRIPTION(node)->subscriber.sin6_addr,
422                             sizeof(struct in6_addr)) == 0)
423             {
424
425                 if (!prev)
426                 {
427                     context->subscriptions = node->next;
428                     coap_free(COAP_SUBSCRIPTION(node)->token.s);
429                     coap_delete(node);
430                 }
431                 else
432                 {
433                     prev->next = node->next;
434                     coap_free(COAP_SUBSCRIPTION(node)->token.s);
435                     coap_delete(node);
436                 }
437                 return 1;
438             }
439         }
440     }
441 #endif
442
443     return 0;
444 }
445 #endif