Contiki-NG
coap-res-well-known-core.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  * /.well-known/core resource implementation.
35  * \author
36  * Matthias Kovatsch <kovatsch@inf.ethz.ch>
37  */
38 
39 /**
40  * \addtogroup coap
41  * @{
42  */
43 
44 #include "coap-engine.h"
45 #include <string.h>
46 #include <stdio.h>
47 
48 /* Log configuration */
49 #include "coap-log.h"
50 #define LOG_MODULE "coap"
51 #define LOG_LEVEL LOG_LEVEL_COAP
52 
53 #define ADD_CHAR_IF_POSSIBLE(char) \
54  if(strpos >= *offset && bufpos < preferred_size) { \
55  buffer[bufpos++] = char; \
56  } \
57  ++strpos
58 
59 #define ADD_STRING_IF_POSSIBLE(string, op) \
60  tmplen = strlen(string); \
61  if(strpos + tmplen > *offset) { \
62  bufpos += snprintf((char *)buffer + bufpos, \
63  preferred_size - bufpos + 1, \
64  "%s", \
65  string \
66  + (*offset - (int32_t)strpos > 0 ? \
67  *offset - (int32_t)strpos : 0)); \
68  if(bufpos op preferred_size) { \
69  LOG_DBG("BREAK at %s (%p)\n", string, resource); \
70  break; \
71  } \
72  } \
73  strpos += tmplen
74 
75 /*---------------------------------------------------------------------------*/
76 /*- Resource Handlers -------------------------------------------------------*/
77 /*---------------------------------------------------------------------------*/
78 static void
79 well_known_core_get_handler(coap_message_t *request, coap_message_t *response,
80  uint8_t *buffer, uint16_t preferred_size,
81  int32_t *offset)
82 {
83  size_t strpos = 0; /* position in overall string (which is larger than the buffer) */
84  size_t bufpos = 0; /* position within buffer (bytes written) */
85  size_t tmplen = 0;
86  coap_resource_t *resource = NULL;
87 
88 #if COAP_LINK_FORMAT_FILTERING
89  /* For filtering. */
90  const char *filter = NULL;
91  const char *attrib = NULL;
92  const char *found = NULL;
93  const char *end = NULL;
94  char *value = NULL;
95  char lastchar = '\0';
96  int len = coap_get_header_uri_query(request, &filter);
97 
98  if(len) {
99  value = strchr(filter, '=');
100  value[0] = '\0';
101  ++value;
102  len -= strlen(filter) + 1;
103 
104  LOG_DBG("Filter %s = ", filter);
105  LOG_DBG_COAP_STRING(value, len);
106  LOG_DBG_("\n");
107 
108  if(strcmp(filter, "href") == 0 && value[0] == '/') {
109  ++value;
110  --len;
111  }
112 
113  lastchar = value[len - 1];
114  value[len - 1] = '\0';
115  }
116 #endif /* COAP_LINK_FORMAT_FILTERING */
117 
118  for(resource = coap_get_first_resource(); resource;
119  resource = coap_get_next_resource(resource)) {
120 #if COAP_LINK_FORMAT_FILTERING
121  /* Filtering */
122  if(len) {
123  if(strcmp(filter, "href") == 0) {
124  attrib = strstr(resource->url, value);
125  if(attrib == NULL || (value[-1] == '/' && attrib != resource->url)) {
126  continue;
127  }
128  end = attrib + strlen(attrib);
129  } else if(resource->attributes != NULL) {
130  attrib = strstr(resource->attributes, filter);
131  if(attrib == NULL
132  || (attrib[strlen(filter)] != '='
133  && attrib[strlen(filter)] != '"')) {
134  continue;
135  }
136  attrib += strlen(filter) + 2;
137  end = strchr(attrib, '"');
138  }
139 
140  LOG_DBG("Filter: res has attrib %s (%s)\n", attrib, value);
141  found = attrib;
142  while((found = strstr(found, value)) != NULL) {
143  if(found > end) {
144  found = NULL;
145  break;
146  }
147  if(lastchar == found[len - 1] || lastchar == '*') {
148  break;
149  }
150  ++found;
151  }
152  if(found == NULL) {
153  continue;
154  }
155  LOG_DBG("Filter: res has prefix %s\n", found);
156  if(lastchar != '*'
157  && (found[len] != '"' && found[len] != ' ' && found[len] != '\0')) {
158  continue;
159  }
160  LOG_DBG("Filter: res has match\n");
161  }
162 #endif
163 
164  LOG_DBG("/%s (%p)\npos: s%zu, o%ld, b%zu\n", resource->url, resource,
165  strpos, (long)*offset, bufpos);
166 
167  if(strpos > 0) {
168  ADD_CHAR_IF_POSSIBLE(',');
169  }
170  ADD_CHAR_IF_POSSIBLE('<');
171  ADD_CHAR_IF_POSSIBLE('/');
172  ADD_STRING_IF_POSSIBLE(resource->url, >=);
173  ADD_CHAR_IF_POSSIBLE('>');
174 
175  if(resource->attributes != NULL && resource->attributes[0]) {
176  ADD_CHAR_IF_POSSIBLE(';');
177  ADD_STRING_IF_POSSIBLE(resource->attributes, >);
178  }
179 
180  /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */
181  if(bufpos > preferred_size && strpos - bufpos > *offset) {
182  LOG_DBG("BREAK at %s (%p)\n", resource->url, resource);
183  break;
184  }
185  }
186 
187  if(bufpos > 0) {
188  LOG_DBG("BUF %zu: ", bufpos);
189  LOG_DBG_COAP_STRING((char *)buffer, bufpos);
190  LOG_DBG_("\n");
191 
192  coap_set_payload(response, buffer, bufpos);
193  coap_set_header_content_format(response, APPLICATION_LINK_FORMAT);
194  } else if(strpos > 0) {
195  LOG_DBG("well_known_core_handler(): bufpos<=0\n");
196 
197  coap_set_status_code(response, BAD_OPTION_4_02);
198  coap_set_payload(response, "BlockOutOfScope", 15);
199  }
200 
201  if(resource == NULL) {
202  LOG_DBG("DONE\n");
203  *offset = -1;
204  } else {
205  LOG_DBG("MORE at %s (%p)\n", resource->url, resource);
206  *offset += preferred_size;
207  }
208 }
209 /*---------------------------------------------------------------------------*/
210 RESOURCE(res_well_known_core, "ct=40", well_known_core_get_handler, NULL,
211  NULL, NULL);
212 /*---------------------------------------------------------------------------*/
213 /** @} */
Log support for CoAP
CoAP engine implementation.
coap_resource_t * coap_get_first_resource(void)
Returns the first of registered CoAP resources.
Definition: coap-engine.c:424
coap_resource_t * coap_get_next_resource(coap_resource_t *resource)
Returns the next registered CoAP resource.
Definition: coap-engine.c:430