53 #define LOG_MODULE "coap" 54 #define LOG_LEVEL LOG_LEVEL_COAP 57 MEMB(observers_memb, coap_observer_t, COAP_MAX_OBSERVERS);
62 static coap_observer_t *
63 add_observer(
const coap_endpoint_t *endpoint,
const uint8_t *token,
64 size_t token_len,
const char *uri,
int uri_len)
67 coap_remove_observer_by_uri(endpoint, uri);
69 coap_observer_t *o =
memb_alloc(&observers_memb);
72 int max =
sizeof(o->url) - 1;
76 memcpy(o->url, uri, max);
79 o->token_len = token_len;
80 memcpy(o->token, token, token_len);
83 LOG_INFO(
"Adding observer (%u/%u) for /%s [0x%02X%02X]\n",
84 list_length(observers_list) + 1, COAP_MAX_OBSERVERS,
85 o->url, o->token[0], o->token[1]);
95 coap_remove_observer(coap_observer_t *o)
97 LOG_INFO(
"Removing observer for /%s [0x%02X%02X]\n", o->url, o->token[0],
105 coap_remove_observer_by_client(
const coap_endpoint_t *endpoint)
108 coap_observer_t *obs = NULL;
110 LOG_DBG(
"Remove check client ");
111 LOG_DBG_COAP_EP(endpoint);
113 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
116 coap_remove_observer(obs);
124 coap_remove_observer_by_token(
const coap_endpoint_t *endpoint,
125 uint8_t *token,
size_t token_len)
128 coap_observer_t *obs = NULL;
130 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
132 LOG_DBG(
"Remove check Token 0x%02X%02X\n", token[0], token[1]);
134 && obs->token_len == token_len
135 && memcmp(obs->token, token, token_len) == 0) {
136 coap_remove_observer(obs);
144 coap_remove_observer_by_uri(
const coap_endpoint_t *endpoint,
148 coap_observer_t *obs = NULL;
150 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
152 LOG_DBG(
"Remove check URL %p\n", uri);
155 && (obs->url == uri || memcmp(obs->url, uri, strlen(obs->url)) == 0)) {
156 coap_remove_observer(obs);
164 coap_remove_observer_by_mid(
const coap_endpoint_t *endpoint, uint16_t mid)
167 coap_observer_t *obs = NULL;
169 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
171 LOG_DBG(
"Remove check MID %u\n", mid);
173 && obs->last_mid == mid) {
174 coap_remove_observer(obs);
184 coap_notify_observers(coap_resource_t *resource)
186 coap_notify_observers_sub(resource, NULL);
191 coap_notify_observers_sub(coap_resource_t *resource,
const char *subpath)
194 coap_message_t notification[1];
195 coap_message_t request[1];
196 coap_observer_t *obs = NULL;
197 int url_len, obs_url_len;
198 char url[COAP_OBSERVER_URL_LEN];
201 if(resource != NULL) {
202 url_len = strlen(resource->url);
203 strncpy(url, resource->url, COAP_OBSERVER_URL_LEN - 1);
204 if(url_len < COAP_OBSERVER_URL_LEN - 1 && subpath != NULL) {
205 strncpy(&url[url_len], subpath, COAP_OBSERVER_URL_LEN - url_len - 1);
207 }
else if(subpath != NULL) {
208 strncpy(url, subpath, COAP_OBSERVER_URL_LEN - 1);
215 url[COAP_OBSERVER_URL_LEN - 1] =
'\0';
217 LOG_INFO(
"Notification from %s\n", url);
219 coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0);
221 coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0);
222 coap_set_header_uri_path(request, url);
225 url_len = strlen(url);
227 sub_ok = (resource == NULL) || (resource->flags & HAS_SUB_RESOURCES);
228 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
230 obs_url_len = strlen(obs->url);
237 if((obs_url_len == url_len
238 || (obs_url_len > url_len
240 && obs->url[url_len] ==
'/'))
241 && strncmp(url, obs->url, url_len) == 0) {
242 coap_transaction_t *transaction = NULL;
246 if((transaction = coap_new_transaction(coap_get_mid(), &obs->endpoint))) {
248 if(COAP_OBSERVE_REFRESH_INTERVAL != 0
249 && (obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0)) {
250 LOG_DBG(
" Force Confirmable for\n");
251 notification->type = COAP_TYPE_CON;
254 LOG_DBG(
" Observer ");
255 LOG_DBG_COAP_EP(&obs->endpoint);
259 obs->last_mid = transaction->mid;
262 notification->mid = transaction->mid;
264 int32_t new_offset = 0;
267 if(coap_call_handlers(request, notification, transaction->message +
268 COAP_MAX_HEADER_SIZE, COAP_MAX_CHUNK_SIZE,
270 LOG_DBG(
"Notification on new handlers\n");
272 if(resource != NULL) {
273 resource->get_handler(request, notification,
274 transaction->message + COAP_MAX_HEADER_SIZE,
275 COAP_MAX_CHUNK_SIZE, &new_offset);
278 notification->code = BAD_REQUEST_4_00;
282 if(notification->code < BAD_REQUEST_4_00) {
283 coap_set_header_observe(notification, (obs->obs_counter)++);
285 obs->obs_counter &= 0xffffff;
287 coap_set_token(notification, obs->token, obs->token_len);
289 if(new_offset != 0) {
290 coap_set_header_block2(notification,
293 COAP_MAX_BLOCK_SIZE);
294 coap_set_payload(notification,
295 notification->payload,
296 MIN(notification->payload_len,
297 COAP_MAX_BLOCK_SIZE));
300 transaction->message_len =
301 coap_serialize_message(notification, transaction->message);
303 coap_send_transaction(transaction);
310 coap_observe_handler(coap_resource_t *resource, coap_message_t *coap_req,
311 coap_message_t *coap_res)
313 const coap_endpoint_t *src_ep;
314 coap_observer_t *obs;
316 LOG_DBG(
"CoAP observer handler rsc: %d\n", resource != NULL);
318 if(coap_req->code == COAP_GET && coap_res->code < 128) {
319 if(coap_is_option(coap_req, COAP_OPTION_OBSERVE)) {
320 src_ep = coap_get_src_endpoint(coap_req);
323 }
else if(coap_req->observe == 0) {
324 obs = add_observer(src_ep,
325 coap_req->token, coap_req->token_len,
326 coap_req->uri_path, coap_req->uri_path_len);
328 coap_set_header_observe(coap_res, (obs->obs_counter)++);
330 obs->obs_counter &= 0xffffff;
337 static char content[16];
338 coap_set_payload(coap_res,
340 snprintf(content,
sizeof(content),
"Added %u/%u",
342 COAP_MAX_OBSERVERS));
345 coap_res->code = SERVICE_UNAVAILABLE_5_03;
346 coap_set_payload(coap_res,
"TooManyObservers", 16);
348 }
else if(coap_req->observe == 1) {
351 coap_remove_observer_by_token(src_ep,
352 coap_req->token, coap_req->token_len);
359 coap_has_observers(
char *path)
361 coap_observer_t *obs = NULL;
363 for(obs = (coap_observer_t *)
list_head(observers_list); obs;
365 if((strncmp(obs->url, path, strlen(path))) == 0) {
CoAP module for observing resources (draft-ietf-core-observe-11).
int memb_free(struct memb *m, void *ptr)
Deallocate a memory block from a memory block previously declared with MEMB().
CoAP engine implementation.
Linked list manipulation routines.
void * list_head(list_t list)
Get a pointer to the first element of a list.
Memory block allocation routines.
void list_add(list_t list, void *item)
Add an item at the end of a list.
#define LIST(name)
Declare a linked list.
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
void coap_endpoint_copy(coap_endpoint_t *dest, const coap_endpoint_t *src)
Copy a CoAP endpoint from one memory area to another.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
int coap_endpoint_cmp(const coap_endpoint_t *e1, const coap_endpoint_t *e2)
Compare two CoAP endpoints.
#define MEMB(name, structure, num)
Declare a memory block.
int list_length(list_t list)
Get the length of a list.