Contiki 3.x
coap-server.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h> /*for isxdigit*/
5 #include "contiki.h"
6 #include "contiki-net.h"
7 
8 #include "buffer.h"
9 #include "coap-server.h"
10 #include "rest-util.h"
11 #include "rest.h" /*added for periodic_resource*/
12 
13 #include "dev/leds.h"
14 
15 #if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
16 #include "static-routing.h"
17 #endif
18 
19 #define DEBUG 0
20 #if DEBUG
21 #include <stdio.h>
22 #define PRINTF(...) printf(__VA_ARGS__)
23 #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])
24 #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])
25 #else
26 #define PRINTF(...)
27 #define PRINT6ADDR(addr)
28 #define PRINTLLADDR(addr)
29 #endif
30 
31 #define MAX_PAYLOAD_LEN 120
32 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
33 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
34 static struct uip_udp_conn *server_conn;
35 
36 static uint16_t current_tid;
37 
38 static service_callback service_cbk = NULL;
39 
40 void
41 coap_set_service_callback(service_callback callback)
42 {
43  service_cbk = callback;
44 }
45 
46 void
47 parse_message(coap_packet_t* packet, uint8_t* buf, uint16_t size)
48 {
49  int processed = 0;
50  int i = 0;
51  PRINTF("parse_message size %d-->\n",size);
52 
53  init_packet(packet);
54 
55  packet->ver = (buf[0] & COAP_HEADER_VERSION_MASK) >> COAP_HEADER_VERSION_POSITION;
56  packet->type = (buf[0] & COAP_HEADER_TYPE_MASK) >> COAP_HEADER_TYPE_POSITION;
57  packet->option_count = buf[0] & COAP_HEADER_OPTION_COUNT_MASK;
58  packet->code = buf[1];
59  packet->tid = (buf[2] << 8) + buf[3];
60 
61  processed += 4;
62 
63  if (packet->option_count) {
64  int option_index = 0;
65  uint8_t option_delta;
66  uint16_t option_len;
67  uint8_t* option_buf = buf + processed;
68  packet->options = (header_option_t*)allocate_buffer(sizeof(header_option_t) * packet->option_count);
69 
70  if (packet->options) {
71  header_option_t* current_option = packet->options;
72  header_option_t* prev_option = NULL;
73  while(option_index < packet->option_count) {
74  /*FIXME : put boundary controls*/
75  option_delta = (option_buf[i] & COAP_HEADER_OPTION_DELTA_MASK) >> COAP_HEADER_OPTION_DELTA_POSITION;
76  option_len = (option_buf[i] & COAP_HEADER_OPTION_SHORT_LENGTH_MASK);
77  i++;
78  if (option_len == 0xf) {
79  option_len += option_buf[i];
80  i++;
81  }
82 
83  current_option->option = option_delta;
84  current_option->len = option_len;
85  current_option->value = option_buf + i;
86  if (option_index) {
87  prev_option->next = current_option;
88  /*This field defines the difference between the option Type of
89  * this option and the previous option (or zero for the first option)*/
90  current_option->option += prev_option->option;
91  }
92 
93  if (current_option->option == Option_Type_Uri_Path) {
94  packet->url = (char*)current_option->value;
95  packet->url_len = current_option->len;
96  } else if (current_option->option == Option_Type_Uri_Query){
97  packet->query = (char*)current_option->value;
98  packet->query_len = current_option->len;
99  }
100 
101  PRINTF("OPTION %d %u %s \n", current_option->option, current_option->len, current_option->value);
102 
103  i += option_len;
104  option_index++;
105  prev_option = current_option++;
106  }
107  current_option->next = NULL;
108  } else {
109  PRINTF("MEMORY ERROR\n"); /*FIXME : add control here*/
110  return;
111  }
112  }
113  processed += i;
114 
115  /**/
116  if (processed < size) {
117  packet->payload = &buf[processed];
118  packet->payload_len = size - processed;
119  }
120 
121  /*FIXME url is not decoded - is necessary?*/
122 
123  /*If query is not already provided via Uri_Query option then check URL*/
124  if (packet->url && !packet->query) {
125  if ((packet->query = strchr(packet->url, '?'))) {
126  uint16_t total_url_len = packet->url_len;
127  /*set query len and update url len so that it does not include query part now*/
128  packet->url_len = packet->query - packet->url;
129  packet->query++;
130  packet->query_len = packet->url + total_url_len - packet->query;
131 
132  PRINTF("url %s, url_len %u, query %s, query_len %u\n", packet->url, packet->url_len, packet->query, packet->query_len);
133  }
134  }
135 
136  PRINTF("PACKET ver:%d type:%d oc:%d \ncode:%d tid:%u url:%s len:%u payload:%s pay_len %u\n", (int)packet->ver, (int)packet->type, (int)packet->option_count, (int)packet->code, packet->tid, packet->url, packet->url_len, packet->payload, packet->payload_len);
137 }
138 
139 int
140 coap_get_query_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
141 {
142  if (packet->query) {
143  return get_variable(name, packet->query, packet->query_len, output, output_size, 0);
144  }
145 
146  return 0;
147 }
148 
149 int
150 coap_get_post_variable(coap_packet_t* packet, const char *name, char* output, uint16_t output_size)
151 {
152  if (packet->payload) {
153  return get_variable(name, packet->payload, packet->payload_len, output, output_size, 1);
154  }
155 
156  return 0;
157 }
158 
159 static header_option_t*
160 allocate_header_option(uint16_t variable_len)
161 {
162  PRINTF("sizeof header_option_t %u variable size %u\n", sizeof(header_option_t), variable_len);
163  uint8_t* buffer = allocate_buffer(sizeof(header_option_t) + variable_len);
164  if (buffer){
165  header_option_t* option = (header_option_t*) buffer;
166  option->next = NULL;
167  option->len = 0;
168  option->value = buffer + sizeof(header_option_t);
169  return option;
170  }
171 
172  return NULL;
173 }
174 
175 /*FIXME : does not overwrite the same option yet.*/
176 int
177 coap_set_option(coap_packet_t* packet, option_type option_type, uint16_t len, uint8_t* value)
178 {
179  PRINTF("coap_set_option len %u\n", len);
180  header_option_t* option = allocate_header_option(len);
181  if (option){
182  option->next = NULL;
183  option->len = len;
184  option->option = option_type;
185  memcpy(option->value, value, len);
186  header_option_t* option_current = packet->options;
187  header_option_t* prev = NULL;
188  while (option_current){
189  if (option_current->option > option->option){
190  break;
191  }
192  prev = option_current;
193  option_current = option_current->next;
194  }
195 
196  if (!prev){
197  if (option_current){
198  option->next = option_current;
199  }
200  packet->options = option;
201  } else{
202  option->next = option_current;
203  prev->next = option;
204  }
205 
206  packet->option_count++;
207 
208  PRINTF("option->len %u option->option %u option->value %x next %x\n", option->len, option->option, (unsigned int) option->value, (unsigned int)option->next);
209 
210  int i = 0;
211  for ( ; i < option->len ; i++ ){
212  PRINTF(" (%u)", option->value[i]);
213  }
214  PRINTF("\n");
215 
216  return 1;
217  }
218 
219  return 0;
220 }
221 
222 header_option_t*
223 coap_get_option(coap_packet_t* packet, option_type option_type)
224 {
225  PRINTF("coap_get_option count: %u--> \n", packet->option_count);
226  int i = 0;
227 
228  header_option_t* current_option = packet->options;
229  for (; i < packet->option_count; current_option = current_option->next, i++) {
230  PRINTF("Current option: %u\n", current_option->option);
231  if (current_option->option == option_type){
232  return current_option;
233  }
234  }
235 
236  return NULL;
237 }
238 
239 static void
240 fill_error_packet(coap_packet_t* packet, int error, uint16_t tid)
241 {
242  packet->ver=1;
243  packet->option_count=0;
244  packet->url=NULL;
245  packet->options=NULL;
246  switch (error){
247  case MEMORY_ALLOC_ERR:
248  packet->code=INTERNAL_SERVER_ERROR_500;
249  packet->tid=tid;
250  packet->type=MESSAGE_TYPE_ACK;
251  break;
252  default:
253  break;
254  }
255 }
256 
257 static void
258 init_response(coap_packet_t* request, coap_packet_t* response)
259 {
260  init_packet(response);
261  if(request->type == MESSAGE_TYPE_CON) {
262  response->code = OK_200;
263  response->tid = request->tid;
264  response->type = MESSAGE_TYPE_ACK;
265  }
266 }
267 
268 uint16_t
269 coap_get_payload(coap_packet_t* packet, uint8_t** payload)
270 {
271  if (packet->payload) {
272  *payload = packet->payload;
273  return packet->payload_len;
274  } else {
275  *payload = NULL;
276  return 0;
277  }
278 }
279 
280 int
281 coap_set_payload(coap_packet_t* packet, uint8_t* payload, uint16_t size)
282 {
283  packet->payload = copy_to_buffer(payload, size);
284  if (packet->payload) {
285  packet->payload_len = size;
286  return 1;
287  }
288 
289  return 0;
290 }
291 
292 int
293 coap_set_header_content_type(coap_packet_t* packet, content_type_t content_type)
294 {
295  uint16_t len = 1;
296 
297  return coap_set_option(packet, Option_Type_Content_Type, len, (uint8_t*) &content_type);
298 }
299 
300 content_type_t
301 coap_get_header_content_type(coap_packet_t* packet)
302 {
303  header_option_t* option = coap_get_option(packet, Option_Type_Content_Type);
304  if (option){
305  return (uint8_t)(*(option->value));
306  }
307 
308  return DEFAULT_CONTENT_TYPE;
309 }
310 
311 int
312 coap_get_header_subscription_lifetime(coap_packet_t* packet, uint32_t* lifetime)
313 {
314  PRINTF("coap_get_header_subscription_lifetime --> \n");
315  header_option_t* option = coap_get_option(packet, Option_Type_Subscription_Lifetime);
316  if (option){
317  PRINTF("Subs Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
318 
319  *lifetime = read_int(option->value, option->len);
320  return 1;
321  }
322 
323  return 0;
324 }
325 
326 int
327 coap_set_header_subscription_lifetime(coap_packet_t* packet, uint32_t lifetime)
328 {
329  uint8_t temp[4];
330  uint16_t len = write_variable_int(temp, lifetime);
331 
332  return coap_set_option(packet, Option_Type_Subscription_Lifetime, len, temp);
333 }
334 
335 int
336 coap_get_header_block(coap_packet_t* packet, block_option_t* block)
337 {
338  uint32_t all_block;
339  PRINTF("coap_get_header_block --> \n");
340  header_option_t* option = coap_get_option(packet, Option_Type_Block);
341  if (option){
342  PRINTF("Block Found len %u (first byte %u)\n", option->len, (uint16_t)option->value[0]);
343 
344  all_block = read_int(option->value, option->len);
345  block->number = all_block >> 4;
346  block->more = (all_block & 0x8) >> 3;
347  block->size = (all_block & 0x7);
348  return 1;
349  }
350 
351  return 0;
352 }
353 
354 int
355 coap_set_header_block(coap_packet_t* packet, uint32_t number, uint8_t more, uint8_t size)
356 {
357  uint8_t temp[4];
358  size = log_2(size/16);
359  number = number << 4;
360  number |= (more << 3) & 0x8;
361  number |= size & 0x7;
362 
363  uint16_t len = write_variable_int(temp, number);
364  PRINTF("number %lu, more %u, size %u block[0] %u block[1] %u block[2] %u block[3] %u\n",
365  number, (uint16_t)more, (uint16_t)size, (uint16_t)temp[0], (uint16_t)temp[1], (uint16_t)temp[2], (uint16_t)temp[3]);
366  return coap_set_option(packet, Option_Type_Block, len, temp);
367 }
368 
369 
370 int
371 coap_set_header_uri(coap_packet_t* packet, char* uri)
372 {
373  return coap_set_option(packet, Option_Type_Uri_Path, strlen(uri), (uint8_t*) uri);
374 }
375 
376 int
377 coap_set_header_etag(coap_packet_t* packet, uint8_t* etag, uint8_t size)
378 {
379  return coap_set_option(packet, Option_Type_Etag, size, etag);
380 }
381 
382 void
383 coap_set_code(coap_packet_t* packet, status_code_t code)
384 {
385  packet->code = (uint8_t)code;
386 }
387 
388 coap_method_t
389 coap_get_method(coap_packet_t* packet)
390 {
391  return (coap_method_t)packet->code;
392 }
393 
394 void
395 coap_set_method(coap_packet_t* packet, coap_method_t method)
396 {
397  packet->code = (uint8_t)method;
398 }
399 
400 static void send_request(coap_packet_t* request, struct uip_udp_conn *client_conn)
401 {
402  char buf[MAX_PAYLOAD_LEN];
403  int data_size = 0;
404 
405  data_size = serialize_packet(request, buf);
406 
407  PRINTF("Created a connection with the server ");
408  PRINT6ADDR(&client_conn->ripaddr);
409  PRINTF(" local/remote port %u/%u\n",
410  uip_htons(client_conn->lport), uip_htons(client_conn->rport));
411 
412  PRINTF("Sending to: ");
413  PRINT6ADDR(&client_conn->ripaddr);
414  uip_udp_packet_send(client_conn, buf, data_size);
415 }
416 
417 static int
418 handle_incoming_data(void)
419 {
420  int error=NO_ERROR;
421  char buf[MAX_PAYLOAD_LEN];
422 
423  PRINTF("uip_datalen received %u \n",(uint16_t)uip_datalen());
424 
425  char* data = (char *)uip_appdata + uip_ext_len;
426  uint16_t datalen = uip_datalen() - uip_ext_len;
427 
428  int data_size = 0;
429 
430  if (uip_newdata()) {
431  ((char *)data)[datalen] = 0;
432  PRINTF("Server received: '%s' (port:%u) from ", (char *)data, uip_htons(UIP_UDP_BUF->srcport));
433  PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
434  PRINTF("\n");
435 
436  if (init_buffer(COAP_DATA_BUFF_SIZE)) {
437  coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
438  parse_message(request, (uint8_t*)data, datalen);
439 
440  uip_ipaddr_copy(&request->addr, &UIP_IP_BUF->srcipaddr);
441 
442  if (request->type != MESSAGE_TYPE_ACK) {
443  coap_packet_t* response = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
444  init_response(request, response);
445 
446  if (service_cbk) {
447  service_cbk(request, response);
448  }
449 
450  data_size = serialize_packet(response, buf);
451 
452  }
453  delete_buffer();
454  } else {
455  PRINTF("Memory Alloc Error\n");
456  error = MEMORY_ALLOC_ERR;
457  /*FIXME : Crappy way of accessing TID of the incoming packet, fix it!*/
458  coap_packet_t error_packet;
459  fill_error_packet(&error_packet,error, (data[2] << 8) + data[3]);
460  data_size = serialize_packet(&error_packet, buf);
461  }
462 
463  uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
464  server_conn->rport = UIP_UDP_BUF->srcport;
465 
466  PRINTF("Responding with message size: %d\n",data_size);
467  uip_udp_packet_send(server_conn, buf, data_size);
468  /* Restore server connection to allow data from any node */
469  memset(&server_conn->ripaddr, 0, sizeof(server_conn->ripaddr));
470  server_conn->rport = 0;
471  }
472 
473  return error;
474 }
475 
476 process_event_t resource_changed_event;
477 
478 void
479 resource_changed(struct periodic_resource_t* resource)
480 {
481  process_post(&coap_server, resource_changed_event, (process_data_t)resource);
482 }
483 
484 
485 /*---------------------------------------------------------------------------*/
486 
487 PROCESS(coap_server, "Coap Server");
488 PROCESS_THREAD(coap_server, ev, data)
489 {
490  PROCESS_BEGIN();
491  PRINTF("COAP SERVER\n");
492 
493 /* if static routes are used rather than RPL */
494 #if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
495  set_global_address();
496  configure_routing();
497 #endif
498 
499  current_tid = random_rand();
500 
501  resource_changed_event = process_alloc_event();
502 
503  /* new connection with remote host */
504  server_conn = udp_new(NULL, uip_htons(0), NULL);
505  udp_bind(server_conn, uip_htons(MOTE_SERVER_LISTEN_PORT));
506  PRINTF("Local/remote port %u/%u\n", uip_htons(server_conn->lport), uip_htons(server_conn->rport));
507 
508  while(1) {
509  PROCESS_YIELD();
510 
511  if(ev == tcpip_event) {
512  handle_incoming_data();
513  } else if (ev == resource_changed_event) {
514  periodic_resource_t* resource = (periodic_resource_t*)data;
515  PRINTF("resource_changed_event \n");
516 
517  if (init_buffer(COAP_DATA_BUFF_SIZE)) {
518  coap_packet_t* request = (coap_packet_t*)allocate_buffer(sizeof(coap_packet_t));
519  init_packet(request);
520  coap_set_code(request, COAP_GET);
521  request->tid = current_tid++;
522  coap_set_header_subscription_lifetime(request, resource->lifetime);
523  coap_set_header_uri(request, (char *)resource->resource->url);
524  if (resource->periodic_request_generator) {
525  resource->periodic_request_generator(request);
526  }
527 
528  if (!resource->client_conn) {
529  /*FIXME send port is fixed for now to 61616*/
530  resource->client_conn = udp_new(&resource->addr, uip_htons(61616), NULL);
531  udp_bind(resource->client_conn, uip_htons(MOTE_CLIENT_LISTEN_PORT));
532  }
533 
534  if (resource->client_conn) {
535  send_request(request, resource->client_conn);
536  }
537 
538  delete_buffer();
539  }
540  }
541  }
542 
543  PROCESS_END();
544 }
545 /*---------------------------------------------------------------------------*/
uint16_t rport
The remote port number in network byte order.
Definition: uip.h:1397
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
CCIF struct uip_udp_conn * udp_new(const uip_ipaddr_t *ripaddr, uint16_t port, void *appstate)
Create a new UDP connection.
#define uip_newdata()
Is new incoming data available?
Definition: uip.h:738
#define NULL
The null pointer.
process_event_t process_alloc_event(void)
Allocate a global event number.
Definition: process.c:93
uint16_t lport
The local port number in network byte order.
Definition: uip.h:1396
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
Definition: process.c:322
uip_ipaddr_t ripaddr
The IP address of the remote peer.
Definition: uip.h:1395
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define UIP_IP_BUF
Pointer to IP header.
Definition: uip-nd6.c:104
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
CCIF uint16_t uip_htons(uint16_t val)
Convert a 16-bit quantity from host byte order to network byte order.
Definition: uip6.c:2298
uint8_t uip_ext_len
The length of the extension headers.
Definition: uip6.c:137
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
Definition: uip.h:651
process_event_t tcpip_event
The uIP event.
Definition: tcpip.c:75
#define PROCESS_YIELD()
Yield the currently running process.
Definition: process.h:164
#define udp_bind(conn, port)
Bind a UDP connection to a local port.
Definition: tcpip.h:262
Representation of a uIP UDP connection.
Definition: uip.h:1394
unsigned short random_rand(void)
Generate the next state and return the upper part of it.
Definition: random.c:47
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74