Contiki 3.x
rest.c
1 #include "contiki.h"
2 #include <string.h> /*for string operations in match_addresses*/
3 #include "rest.h"
4 #include "buffer.h"
5 
6 #define DEBUG 0
7 #if DEBUG
8 #include <stdio.h>
9 #define PRINTF(...) printf(__VA_ARGS__)
10 #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])
11 #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])
12 #else
13 #define PRINTF(...)
14 #define PRINT6ADDR(addr)
15 #define PRINTLLADDR(addr)
16 #endif
17 
18 /*FIXME it is possible to define some of the rest functions as MACROs rather than functions full of ifdefs.*/
19 
20 PROCESS_NAME(rest_manager_process);
21 
22 LIST(restful_services);
23 LIST(restful_periodic_services);
24 
25 void
26 rest_init(void)
27 {
28  list_init(restful_services);
29 
30 #ifdef WITH_COAP
31  coap_set_service_callback(rest_invoke_restful_service);
32 #else /*WITH_COAP*/
33  http_set_service_callback(rest_invoke_restful_service);
34 #endif /*WITH_COAP*/
35 
36  /*Start rest framework process*/
37  process_start(&rest_manager_process, NULL);
38 }
39 
40 void
41 rest_activate_resource(resource_t* resource)
42 {
43  /*add it to the restful web service link list*/
44  list_add(restful_services, resource);
45 }
46 
47 void
48 rest_activate_periodic_resource(periodic_resource_t* periodic_resource)
49 {
50  list_add(restful_periodic_services, periodic_resource);
51  rest_activate_resource(periodic_resource->resource);
52 }
53 
54 void
55 rest_set_user_data(resource_t* resource, void* user_data)
56 {
57  resource->user_data = user_data;
58 }
59 
60 void*
61 rest_get_user_data(resource_t* resource)
62 {
63  return resource->user_data;
64 }
65 
66 void
67 rest_set_pre_handler(resource_t* resource, restful_pre_handler pre_handler)
68 {
69  resource->pre_handler = pre_handler;
70 }
71 
72 void
73 rest_set_post_handler(resource_t* resource, restful_post_handler post_handler)
74 {
75  resource->post_handler = post_handler;
76 }
77 
78 list_t
80 {
81  return restful_services;
82 }
83 
84 void
85 rest_set_response_status(RESPONSE* response, status_code_t status)
86 {
87 #ifdef WITH_COAP
88  coap_set_code(response, status);
89 #else /*WITH_COAP*/
90  http_set_status(response, status);
91 #endif /*WITH_COAP*/
92 }
93 
94 #ifdef WITH_COAP
95 static method_t coap_to_rest_method(coap_method_t method)
96 {
97  return (method_t)(1 << (method - 1));
98 }
99 
100 static coap_method_t rest_to_coap_method(method_t method)
101 {
102  coap_method_t coap_method = COAP_GET;
103  switch (method) {
104  case METHOD_GET:
105  coap_method = COAP_GET;
106  break;
107  case METHOD_POST:
108  coap_method = COAP_POST;
109  break;
110  case METHOD_PUT:
111  coap_method = COAP_PUT;
112  break;
113  case METHOD_DELETE:
114  coap_method = COAP_DELETE;
115  break;
116  default:
117  break;
118  }
119  return coap_method;
120 }
121 #endif /*WITH_COAP*/
122 
123 method_t
124 rest_get_method_type(REQUEST* request)
125 {
126 #ifdef WITH_COAP
127  return coap_to_rest_method(coap_get_method(request));
128 #else
129  return (method_t)(request->request_type);
130 #endif
131 }
132 
133 /*Only defined for COAP for now.*/
134 #ifdef WITH_COAP
135 void
136 rest_set_method_type(REQUEST* request, method_t method)
137 {
138  coap_set_method(request, rest_to_coap_method(method));
139 }
140 #endif /*WITH_COAP*/
141 
142 void
143 rest_set_response_payload(RESPONSE* response, uint8_t* payload, uint16_t size)
144 {
145 #ifdef WITH_COAP
146  coap_set_payload(response, payload, size);
147 #else
148  http_set_res_payload(response, payload, size);
149 #endif /*WITH_COAP*/
150 }
151 
152 /*Only defined for COAP for now.*/
153 #ifdef WITH_COAP
154 void
155 rest_set_request_payload(REQUEST* request, uint8_t* payload, uint16_t size)
156 {
157  coap_set_payload(request, payload, size);
158 }
159 #endif /*WITH_COAP*/
160 
161 int
162 rest_get_query_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
163 {
164 #ifdef WITH_COAP
165  return coap_get_query_variable(request, name, output, output_size);
166 #else
167  return http_get_query_variable(request, name, output, output_size);
168 #endif /*WITH_COAP*/
169 }
170 
171 int
172 rest_get_post_variable(REQUEST* request, const char *name, char* output, uint16_t output_size)
173 {
174 #ifdef WITH_COAP
175  return coap_get_post_variable(request, name, output, output_size);
176 #else
177  return http_get_post_variable(request, name, output, output_size);
178 #endif /*WITH_COAP*/
179 }
180 
181 content_type_t
182 rest_get_header_content_type(REQUEST* request)
183 {
184 #ifdef WITH_COAP
185  return coap_get_header_content_type(request);
186 #else
187  return http_get_header_content_type(request);
188 #endif /*WITH_COAP*/
189 }
190 
191 int
192 rest_set_header_content_type(RESPONSE* response, content_type_t content_type)
193 {
194 #ifdef WITH_COAP
195  return coap_set_header_content_type(response, content_type);
196 #else
197  return http_set_res_header(response, HTTP_HEADER_NAME_CONTENT_TYPE, http_get_content_type_string(content_type), 1);
198 #endif /*WITH_COAP*/
199 
200 }
201 
202 int
203 rest_set_header_etag(RESPONSE* response, uint8_t* etag, uint8_t size)
204 {
205 #ifdef WITH_COAP
206  return coap_set_header_etag(response, etag, size);
207 #else
208  /*FIXME for now etag should be a "/0" ending string for http part*/
209  char temp_etag[10];
210  memcpy(temp_etag, etag, size);
211  temp_etag[size] = 0;
212  return http_set_res_header(response, HTTP_HEADER_NAME_ETAG, temp_etag, 1);
213 #endif /*WITH_COAP*/
214 }
215 
216 int
217 rest_invoke_restful_service(REQUEST* request, RESPONSE* response)
218 {
219  int found = 0;
220  const char* url = request->url;
221  uint16_t url_len = request->url_len;
222 
223  PRINTF("rest_invoke_restful_service url %s url_len %d -->\n", url, url_len);
224 
225  resource_t* resource = NULL;
226 
227  for (resource = (resource_t*)list_head(restful_services); resource; resource = resource->next) {
228  /*if the web service handles that kind of requests and urls matches*/
229  if (url && strlen(resource->url) == url_len && strncmp(resource->url, url, url_len) == 0){
230  found = 1;
231  method_t method = rest_get_method_type(request);
232 
233  PRINTF("method %u, resource->methods_to_handle %u\n", (uint16_t)method, resource->methods_to_handle);
234 
235  if (resource->methods_to_handle & method) {
236 
237  /*FIXME Need to move somewhere else*/
238  #ifdef WITH_COAP
239  uint32_t lifetime = 0;
240  if (coap_get_header_subscription_lifetime(request, &lifetime)) {
241  PRINTF("Lifetime %lu\n", lifetime);
242 
243  periodic_resource_t* periodic_resource = NULL;
244  for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);
245  periodic_resource;
246  periodic_resource = periodic_resource->next) {
247  if (periodic_resource->resource == resource) {
248  PRINTF("Periodic Resource Found\n");
249  PRINT6ADDR(&request->addr);
250  periodic_resource->lifetime = lifetime;
251  stimer_set(periodic_resource->lifetime_timer, lifetime);
252  uip_ipaddr_copy(&periodic_resource->addr, &request->addr);
253  }
254  }
255  }
256  #endif /*WITH_COAP*/
257 
258  /*call pre handler if it exists*/
259  if (!resource->pre_handler || resource->pre_handler(request, response)) {
260  /* call handler function*/
261  resource->handler(request, response);
262 
263  /*call post handler if it exists*/
264  if (resource->post_handler) {
265  resource->post_handler(request, response);
266  }
267  }
268  } else {
269  rest_set_response_status(response, METHOD_NOT_ALLOWED_405);
270  }
271  break;
272  }
273  }
274 
275  if (!found) {
276  rest_set_response_status(response, NOT_FOUND_404);
277  }
278 
279  return found;
280 }
281 
282 PROCESS(rest_manager_process, "Rest Process");
283 
284 PROCESS_THREAD(rest_manager_process, ev, data)
285 {
286  PROCESS_BEGIN();
287 
288  /*start the coap or http server*/
289  process_start(SERVER_PROCESS, NULL);
290 
291  PROCESS_PAUSE();
292 
293  /*Periodic resources are only available to COAP implementation*/
294 #if 0
295 #ifdef WITH_COAP
296  periodic_resource_t* periodic_resource = NULL;
297  for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services); periodic_resource; periodic_resource = periodic_resource->next) {
298  if (periodic_resource->period) {
299  PRINTF("Set timer for Res: %s to %lu\n", periodic_resource->resource->url, periodic_resource->period);
300  etimer_set(periodic_resource->handler_cb_timer, periodic_resource->period);
301  }
302  }
303 
304  while(1) {
306  if (ev == PROCESS_EVENT_TIMER) {
307  for (periodic_resource = (periodic_resource_t*)list_head(restful_periodic_services);periodic_resource;periodic_resource = periodic_resource->next) {
308  if (periodic_resource->period && etimer_expired(periodic_resource->handler_cb_timer)) {
309  PRINTF("Etimer expired for %s (period:%lu life:%lu)\n", periodic_resource->resource->url, periodic_resource->period, periodic_resource->lifetime);
310  /*call the periodic handler function if exists*/
311  if (periodic_resource->periodic_handler) {
312  if ((periodic_resource->periodic_handler)(periodic_resource->resource)) {
313  PRINTF("RES CHANGE\n");
314  if (!stimer_expired(periodic_resource->lifetime_timer)) {
315  PRINTF("TIMER NOT EXPIRED\n");
316  resource_changed(periodic_resource);
317  periodic_resource->lifetime = stimer_remaining(periodic_resource->lifetime_timer);
318  } else {
319  periodic_resource->lifetime = 0;
320  }
321  }
322 
323  PRINTF("%s lifetime %lu (%lu) expired %d\n", periodic_resource->resource->url, stimer_remaining(periodic_resource->lifetime_timer), periodic_resource->lifetime, stimer_expired(periodic_resource->lifetime_timer));
324  }
325  etimer_reset(periodic_resource->handler_cb_timer);
326  }
327  }
328  }
329  }
330 #endif /*WITH_COAP*/
331 #endif
332  PROCESS_END();
333 }
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
list_t rest_get_resources(void)
Returns the list of registered RESTful resources.
Definition: rest-engine.c:113
int stimer_expired(struct stimer *t)
Check if a timer has expired.
Definition: stimer.c:124
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void ** list_t
The linked list type.
Definition: list.h:133
#define PROCESS_NAME(name)
Declare the name of a process.
Definition: process.h:286
#define NULL
The null pointer.
void stimer_set(struct stimer *t, unsigned long interval)
Set a timer.
Definition: stimer.c:67
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void list_init(list_t list)
Initialize a list.
Definition: list.c:66
void rest_activate_resource(resource_t *resource, char *path)
Makes a resource available under the given URI path.
Definition: rest-engine.c:94
#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 PROCESS_PAUSE()
Yield the process for a short while.
Definition: process.h:221
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define LIST(name)
Declare a linked list.
Definition: list.h:86
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:184
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
unsigned long stimer_remaining(struct stimer *t)
The time until the timer expires.
Definition: stimer.c:140