Contiki 3.x
er-coap-observe.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
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  * \file
34  * CoAP module for observing resources (draft-ietf-core-observe-11).
35  * \author
36  * Matthias Kovatsch <kovatsch@inf.ethz.ch>
37  */
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include "er-coap-observe.h"
42 
43 #define DEBUG 0
44 #if DEBUG
45 #include <stdio.h>
46 #define PRINTF(...) printf(__VA_ARGS__)
47 #define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15])
48 #define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5])
49 #else
50 #define PRINTF(...)
51 #define PRINT6ADDR(addr)
52 #define PRINTLLADDR(addr)
53 #endif
54 
55 /*---------------------------------------------------------------------------*/
56 MEMB(observers_memb, coap_observer_t, COAP_MAX_OBSERVERS);
57 LIST(observers_list);
58 /*---------------------------------------------------------------------------*/
59 /*- Internal API ------------------------------------------------------------*/
60 /*---------------------------------------------------------------------------*/
61 coap_observer_t *
62 coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token,
63  size_t token_len, const char *uri)
64 {
65  /* Remove existing observe relationship, if any. */
66  coap_remove_observer_by_uri(addr, port, uri);
67 
68  coap_observer_t *o = memb_alloc(&observers_memb);
69 
70  if(o) {
71  o->url = uri;
72  uip_ipaddr_copy(&o->addr, addr);
73  o->port = port;
74  o->token_len = token_len;
75  memcpy(o->token, token, token_len);
76  o->last_mid = 0;
77 
78  PRINTF("Adding observer (%u/%u) for /%s [0x%02X%02X]\n",
79  list_length(observers_list) + 1, COAP_MAX_OBSERVERS,
80  o->url, o->token[0], o->token[1]);
81  list_add(observers_list, o);
82  }
83 
84  return o;
85 }
86 /*---------------------------------------------------------------------------*/
87 /*- Removal -----------------------------------------------------------------*/
88 /*---------------------------------------------------------------------------*/
89 void
90 coap_remove_observer(coap_observer_t *o)
91 {
92  PRINTF("Removing observer for /%s [0x%02X%02X]\n", o->url, o->token[0],
93  o->token[1]);
94 
95  memb_free(&observers_memb, o);
96  list_remove(observers_list, o);
97 }
98 /*---------------------------------------------------------------------------*/
99 int
100 coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port)
101 {
102  int removed = 0;
103  coap_observer_t *obs = NULL;
104 
105  for(obs = (coap_observer_t *)list_head(observers_list); obs;
106  obs = obs->next) {
107  PRINTF("Remove check client ");
108  PRINT6ADDR(addr);
109  PRINTF(":%u\n", port);
110  if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port) {
111  coap_remove_observer(obs);
112  removed++;
113  }
114  }
115  return removed;
116 }
117 /*---------------------------------------------------------------------------*/
118 int
119 coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port,
120  uint8_t *token, size_t token_len)
121 {
122  int removed = 0;
123  coap_observer_t *obs = NULL;
124 
125  for(obs = (coap_observer_t *)list_head(observers_list); obs;
126  obs = obs->next) {
127  PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]);
128  if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port
129  && obs->token_len == token_len
130  && memcmp(obs->token, token, token_len) == 0) {
131  coap_remove_observer(obs);
132  removed++;
133  }
134  }
135  return removed;
136 }
137 /*---------------------------------------------------------------------------*/
138 int
139 coap_remove_observer_by_uri(uip_ipaddr_t *addr, uint16_t port,
140  const char *uri)
141 {
142  int removed = 0;
143  coap_observer_t *obs = NULL;
144 
145  for(obs = (coap_observer_t *)list_head(observers_list); obs;
146  obs = obs->next) {
147  PRINTF("Remove check URL %p\n", uri);
148  if((addr == NULL
149  || (uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port))
150  && (obs->url == uri || memcmp(obs->url, uri, strlen(obs->url)) == 0)) {
151  coap_remove_observer(obs);
152  removed++;
153  }
154  }
155  return removed;
156 }
157 /*---------------------------------------------------------------------------*/
158 int
159 coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid)
160 {
161  int removed = 0;
162  coap_observer_t *obs = NULL;
163 
164  for(obs = (coap_observer_t *)list_head(observers_list); obs;
165  obs = obs->next) {
166  PRINTF("Remove check MID %u\n", mid);
167  if(uip_ipaddr_cmp(&obs->addr, addr) && obs->port == port
168  && obs->last_mid == mid) {
169  coap_remove_observer(obs);
170  removed++;
171  }
172  }
173  return removed;
174 }
175 /*---------------------------------------------------------------------------*/
176 /*- Notification ------------------------------------------------------------*/
177 /*---------------------------------------------------------------------------*/
178 void
179 coap_notify_observers(resource_t *resource)
180 {
181  /* build notification */
182  coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */
183  coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0);
184  coap_observer_t *obs = NULL;
185 
186  PRINTF("Observe: Notification from %s\n", resource->url);
187 
188  /* iterate over observers */
189  for(obs = (coap_observer_t *)list_head(observers_list); obs;
190  obs = obs->next) {
191  if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */
192  coap_transaction_t *transaction = NULL;
193 
194  /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */
195 
196  if((transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) {
197  if(obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0) {
198  PRINTF(" Force Confirmable for\n");
199  notification->type = COAP_TYPE_CON;
200  }
201 
202  PRINTF(" Observer ");
203  PRINT6ADDR(&obs->addr);
204  PRINTF(":%u\n", obs->port);
205 
206  /* update last MID for RST matching */
207  obs->last_mid = transaction->mid;
208 
209  /* prepare response */
210  notification->mid = transaction->mid;
211 
212  resource->get_handler(NULL, notification,
213  transaction->packet + COAP_MAX_HEADER_SIZE,
214  REST_MAX_CHUNK_SIZE, NULL);
215 
216  if(notification->code < BAD_REQUEST_4_00) {
217  coap_set_header_observe(notification, (obs->obs_counter)++);
218  }
219  coap_set_token(notification, obs->token, obs->token_len);
220 
221  transaction->packet_len =
222  coap_serialize_message(notification, transaction->packet);
223 
224  coap_send_transaction(transaction);
225  }
226  }
227  }
228 }
229 /*---------------------------------------------------------------------------*/
230 void
231 coap_observe_handler(resource_t *resource, void *request, void *response)
232 {
233  coap_packet_t *const coap_req = (coap_packet_t *)request;
234  coap_packet_t *const coap_res = (coap_packet_t *)response;
235  coap_observer_t * obs;
236 
237  static char content[16];
238 
239  if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */
240  if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) {
241  if(coap_req->observe == 0) {
242  obs = coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
243  coap_req->token, coap_req->token_len,
244  resource->url);
245  if(obs) {
246  coap_set_header_observe(coap_res, (obs->obs_counter)++);
247  /*
248  * Following payload is for demonstration purposes only.
249  * A subscription should return the same representation as a normal GET.
250  * Uncomment if you want an information about the avaiable observers.
251  */
252  /*
253  * coap_set_payload(coap_res,
254  * content,
255  * snprintf(content, sizeof(content), "Added %u/%u",
256  * list_length(observers_list),
257  * COAP_MAX_OBSERVERS));
258  */
259  } else {
260  coap_res->code = SERVICE_UNAVAILABLE_5_03;
261  coap_set_payload(coap_res, "TooManyObservers", 16);
262  }
263  } else if(coap_req->observe == 1) {
264 
265  /* remove client if it is currently observe */
266  coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr,
267  UIP_UDP_BUF->srcport, coap_req->token,
268  coap_req->token_len);
269  }
270  }
271  }
272 }
273 /*---------------------------------------------------------------------------*/
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.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:240
int list_length(list_t list)
Get the length of a list.
Definition: list.c:275
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:104
#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 LIST(name)
Declare a linked list.
Definition: list.h:86
CoAP module for observing resources (draft-ietf-core-observe-11).