Contiki 3.x
er-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 #include <string.h>
40 #include "er-coap-engine.h"
41 
42 #define DEBUG 0
43 #if DEBUG
44 #include <stdio.h>
45 #define PRINTF(...) printf(__VA_ARGS__)
46 #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])
47 #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])
48 #else
49 #define PRINTF(...)
50 #define PRINT6ADDR(addr)
51 #define PRINTLLADDR(addr)
52 #endif
53 
54 #define ADD_CHAR_IF_POSSIBLE(char) \
55  if(strpos >= *offset && bufpos < preferred_size) { \
56  buffer[bufpos++] = char; \
57  } \
58  ++strpos
59 
60 #define ADD_STRING_IF_POSSIBLE(string, op) \
61  tmplen = strlen(string); \
62  if(strpos + tmplen > *offset) { \
63  bufpos += snprintf((char *)buffer + bufpos, \
64  preferred_size - bufpos + 1, \
65  "%s", \
66  string \
67  + (*offset - (int32_t)strpos > 0 ? \
68  *offset - (int32_t)strpos : 0)); \
69  if(bufpos op preferred_size) { \
70  PRINTF("res: BREAK at %s (%p)\n", string, resource); \
71  break; \
72  } \
73  } \
74  strpos += tmplen
75 
76 /*---------------------------------------------------------------------------*/
77 /*- Resource Handlers -------------------------------------------------------*/
78 /*---------------------------------------------------------------------------*/
79 void
80 well_known_core_get_handler(void *request, void *response, uint8_t *buffer,
81  uint16_t preferred_size, 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  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  PRINTF("Filter %s = %.*s\n", filter, len, value);
105 
106  if(strcmp(filter, "href") == 0 && value[0] == '/') {
107  ++value;
108  --len;
109  }
110 
111  lastchar = value[len - 1];
112  value[len - 1] = '\0';
113  }
114 #endif
115 
116  for(resource = (resource_t *)list_head(rest_get_resources()); resource;
117  resource = resource->next) {
118 #if COAP_LINK_FORMAT_FILTERING
119  /* Filtering */
120  if(len) {
121  if(strcmp(filter, "href") == 0) {
122  attrib = strstr(resource->url, value);
123  if(attrib == NULL || (value[-1] == '/' && attrib != resource->url)) {
124  continue;
125  }
126  end = attrib + strlen(attrib);
127  } else {
128  attrib = strstr(resource->attributes, filter);
129  if(attrib == NULL
130  || (attrib[strlen(filter)] != '='
131  && attrib[strlen(filter)] != '"')) {
132  continue;
133  }
134  attrib += strlen(filter) + 2;
135  end = strchr(attrib, '"');
136  }
137 
138  PRINTF("Filter: res has attrib %s (%s)\n", attrib, value);
139  found = attrib;
140  while((found = strstr(found, value)) != NULL) {
141  if(found > end) {
142  found = NULL;
143  break;
144  }
145  if(lastchar == found[len - 1] || lastchar == '*') {
146  break;
147  }
148  ++found;
149  }
150  if(found == NULL) {
151  continue;
152  }
153  PRINTF("Filter: res has prefix %s\n", found);
154  if(lastchar != '*'
155  && (found[len] != '"' && found[len] != ' ' && found[len] != '\0')) {
156  continue;
157  }
158  PRINTF("Filter: res has match\n");
159  }
160 #endif
161 
162  PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource,
163  strpos, *offset, bufpos);
164 
165  if(strpos > 0) {
166  ADD_CHAR_IF_POSSIBLE(',');
167  }
168  ADD_CHAR_IF_POSSIBLE('<');
169  ADD_CHAR_IF_POSSIBLE('/');
170  ADD_STRING_IF_POSSIBLE(resource->url, >=);
171  ADD_CHAR_IF_POSSIBLE('>');
172 
173  if(resource->attributes[0]) {
174  ADD_CHAR_IF_POSSIBLE(';');
175  ADD_STRING_IF_POSSIBLE(resource->attributes, >);
176  }
177 
178  /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */
179  if(bufpos > preferred_size && strpos - bufpos > *offset) {
180  PRINTF("res: BREAK at %s (%p)\n", resource->url, resource);
181  break;
182  }
183  }
184 
185  if(bufpos > 0) {
186  PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *)buffer);
187 
188  coap_set_payload(response, buffer, bufpos);
189  coap_set_header_content_format(response, APPLICATION_LINK_FORMAT);
190  } else if(strpos > 0) {
191  PRINTF("well_known_core_handler(): bufpos<=0\n");
192 
193  coap_set_status_code(response, BAD_OPTION_4_02);
194  coap_set_payload(response, "BlockOutOfScope", 15);
195  }
196 
197  if(resource == NULL) {
198  PRINTF("res: DONE\n");
199  *offset = -1;
200  } else {
201  PRINTF("res: MORE at %s (%p)\n", resource->url, resource);
202  *offset += preferred_size;
203  }
204 }
205 /*---------------------------------------------------------------------------*/
206 RESOURCE(res_well_known_core, "ct=40", well_known_core_get_handler, NULL,
207  NULL, NULL);
208 /*---------------------------------------------------------------------------*/
list_t rest_get_resources(void)
Returns the list of registered RESTful resources.
Definition: rest-engine.c:113
#define NULL
The null pointer.
CoAP implementation for the REST Engine.
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83