48 #define PRINTF(...) printf(__VA_ARGS__)
49 #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])
50 #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])
53 #define PRINT6ADDR(addr)
54 #define PRINTLLADDR(addr)
57 PROCESS(coap_engine,
"CoAP Engine");
62 static service_callback_t service_cbk =
NULL;
70 erbium_status_code = NO_ERROR;
72 PRINTF(
"handle_incoming_data(): received uip_datalen=%u \n",
76 static coap_packet_t message[1];
77 static coap_packet_t response[1];
78 static coap_transaction_t *transaction =
NULL;
82 PRINTF(
"receiving UDP datagram from: ");
84 PRINTF(
":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF->srcport),
90 if(erbium_status_code == NO_ERROR) {
94 PRINTF(
" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version,
95 message->type, message->token_len, message->code, message->mid);
96 PRINTF(
" URL: %.*s\n", message->uri_path_len, message->uri_path);
97 PRINTF(
" Payload: %.*s\n", message->payload_len, message->payload);
100 if(message->code >= COAP_GET && message->code <= COAP_DELETE) {
104 coap_new_transaction(message->mid, &
UIP_IP_BUF->srcipaddr,
105 UIP_UDP_BUF->srcport))) {
106 uint32_t block_num = 0;
107 uint16_t block_size = COAP_MAX_BLOCK_SIZE;
108 uint32_t block_offset = 0;
109 int32_t new_offset = 0;
112 if(message->type == COAP_TYPE_CON) {
114 coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
118 coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
121 }
if(message->token_len) {
122 coap_set_token(response, message->token, message->token_len);
125 if(coap_get_header_block2
126 (message, &block_num,
NULL, &block_size, &block_offset)) {
127 PRINTF(
"Blockwise: block request %lu (%u/%u) @ %lu bytes\n",
128 block_num, block_size, COAP_MAX_BLOCK_SIZE, block_offset);
129 block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE);
130 new_offset = block_offset;
138 (message, response, transaction->packet + COAP_MAX_HEADER_SIZE,
139 block_size, &new_offset)) {
141 if(erbium_status_code == NO_ERROR) {
146 if(IS_OPTION(message, COAP_OPTION_BLOCK1)
147 && response->code < BAD_REQUEST_4_00
148 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
149 PRINTF(
"Block1 NOT IMPLEMENTED\n");
151 erbium_status_code = NOT_IMPLEMENTED_5_01;
152 coap_error_message =
"NoBlock1Support";
155 }
else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) {
158 if(new_offset == block_offset) {
160 (
"Blockwise: unaware resource with payload length %u/%u\n",
161 response->payload_len, block_size);
162 if(block_offset >= response->payload_len) {
164 (
"handle_incoming_data(): block_offset >= response->payload_len\n");
166 response->code = BAD_OPTION_4_02;
167 coap_set_payload(response,
"BlockOutOfScope", 15);
169 coap_set_header_block2(response, block_num,
170 response->payload_len -
171 block_offset > block_size,
173 coap_set_payload(response,
174 response->payload + block_offset,
175 MIN(response->payload_len -
176 block_offset, block_size));
181 PRINTF(
"Blockwise: blockwise resource, new offset %ld\n",
183 coap_set_header_block2(response, block_num,
185 || response->payload_len >
186 block_size, block_size);
188 if(response->payload_len > block_size) {
189 coap_set_payload(response, response->payload,
195 }
else if(new_offset != 0) {
197 (
"Blockwise: no block option for blockwise resource, using block size %u\n",
198 COAP_MAX_BLOCK_SIZE);
200 coap_set_header_block2(response, 0, new_offset != -1,
201 COAP_MAX_BLOCK_SIZE);
202 coap_set_payload(response, response->payload,
203 MIN(response->payload_len,
204 COAP_MAX_BLOCK_SIZE));
210 if(erbium_status_code == NO_ERROR) {
211 if((transaction->packet_len = coap_serialize_message(response,
215 erbium_status_code = PACKET_SERIALIZATION_ERROR;
219 erbium_status_code = NOT_IMPLEMENTED_5_01;
220 coap_error_message =
"NoServiceCallbck";
223 erbium_status_code = SERVICE_UNAVAILABLE_5_03;
224 coap_error_message =
"NoFreeTraBuffer";
230 if(message->type == COAP_TYPE_CON && message->code == 0) {
231 PRINTF(
"Received Ping\n");
232 erbium_status_code = PING_RESPONSE;
233 }
else if(message->type == COAP_TYPE_ACK) {
235 PRINTF(
"Received ACK\n");
236 }
else if(message->type == COAP_TYPE_RST) {
237 PRINTF(
"Received RST\n");
239 coap_remove_observer_by_mid(&
UIP_IP_BUF->srcipaddr,
240 UIP_UDP_BUF->srcport, message->mid);
243 if((transaction = coap_get_transaction_by_mid(message->mid))) {
245 restful_response_handler callback = transaction->callback;
246 void *callback_data = transaction->callback_data;
248 coap_clear_transaction(transaction);
252 callback(callback_data, message);
258 #if COAP_OBSERVE_CLIENT
260 if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON)
261 && IS_OPTION(message, COAP_OPTION_OBSERVE)) {
262 PRINTF(
"Observe [%u]\n", message->observe);
263 coap_handle_notification(&
UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
271 if(erbium_status_code == NO_ERROR) {
273 coap_send_transaction(transaction);
275 }
else if(erbium_status_code == MANUAL_RESPONSE) {
276 PRINTF(
"Clearing transaction for manual response");
277 coap_clear_transaction(transaction);
279 coap_message_type_t reply_type = COAP_TYPE_ACK;
281 PRINTF(
"ERROR %u: %s\n", erbium_status_code, coap_error_message);
282 coap_clear_transaction(transaction);
284 if(erbium_status_code == PING_RESPONSE) {
285 erbium_status_code = 0;
286 reply_type = COAP_TYPE_RST;
287 }
else if(erbium_status_code >= 192) {
289 erbium_status_code = INTERNAL_SERVER_ERROR_5_00;
292 coap_init_message(message, reply_type, erbium_status_code,
294 coap_set_payload(message, coap_error_message,
295 strlen(coap_error_message));
296 coap_send_message(&
UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
303 return erbium_status_code;
307 coap_init_engine(
void)
313 coap_set_service_callback(service_callback_t callback)
315 service_cbk = callback;
319 coap_get_rest_method(
void *packet)
322 (((coap_packet_t *)packet)->code - 1));
329 #ifndef COAP_RES_WITHOUT_WELL_KNOWN
330 extern resource_t res_well_known_core;
333 extern resource_t res_dtls;
340 PRINTF(
"Starting %s receiver...\n", coap_rest_implementation.name);
342 #ifndef COAP_RES_WITHOUT_WELL_KNOWN
345 coap_register_as_transaction_handler();
346 coap_init_connection(SERVER_LISTEN_PORT);
353 }
else if(ev == PROCESS_EVENT_TIMER) {
355 coap_check_transactions();
365 coap_blocking_request_callback(
void *callback_data,
void *response)
367 struct request_state_t *state = (
struct request_state_t *)callback_data;
369 state->response = (coap_packet_t *)response;
374 (
struct request_state_t *state, process_event_t ev,
375 uip_ipaddr_t *remote_ipaddr, uint16_t remote_port,
376 coap_packet_t *request,
377 blocking_response_handler request_callback))
382 static uint32_t res_block;
383 static uint8_t block_error;
385 state->block_num = 0;
386 state->response =
NULL;
394 request->mid = coap_get_mid();
395 if((state->transaction = coap_new_transaction(request->mid, remote_ipaddr,
397 state->transaction->callback = coap_blocking_request_callback;
398 state->transaction->callback_data = state;
400 if(state->block_num > 0) {
401 coap_set_header_block2(request, state->block_num, 0,
402 REST_MAX_CHUNK_SIZE);
404 state->transaction->packet_len = coap_serialize_message(request,
409 coap_send_transaction(state->transaction);
410 PRINTF(
"Requested #%lu (MID %u)\n", state->block_num, request->mid);
414 if(!state->response) {
415 PRINTF(
"Server not responding\n");
419 coap_get_header_block2(state->response, &res_block, &more,
NULL,
NULL);
421 PRINTF(
"Received #%lu%s (%u bytes)\n", res_block, more ?
"+" :
"",
422 state->response->payload_len);
424 if(res_block == state->block_num) {
425 request_callback(state->response);
426 ++(state->block_num);
428 PRINTF(
"WRONG BLOCK %lu/%lu\n", res_block, state->block_num);
432 PRINTF(
"Could not allocate transaction buffer");
435 }
while(more && block_error < COAP_MAX_ATTEMPTS);
442 const struct rest_implementation coap_rest_implementation = {
446 coap_set_service_callback,
448 coap_get_header_uri_path,
449 coap_get_rest_method,
450 coap_set_status_code,
452 coap_get_header_content_format,
453 coap_set_header_content_format,
454 coap_get_header_accept,
455 coap_get_header_size2,
456 coap_set_header_size2,
457 coap_get_header_max_age,
458 coap_set_header_max_age,
459 coap_set_header_etag,
460 coap_get_header_if_match,
461 coap_get_header_if_none_match,
462 coap_get_header_uri_host,
463 coap_set_header_location_path,
468 coap_get_header_uri_query,
469 coap_get_query_variable,
470 coap_get_post_variable,
472 coap_notify_observers,
473 coap_observe_handler,
486 METHOD_NOT_ALLOWED_4_05,
488 REQUEST_ENTITY_TOO_LARGE_4_13,
489 UNSUPPORTED_MEDIA_TYPE_4_15,
490 INTERNAL_SERVER_ERROR_5_00,
491 NOT_IMPLEMENTED_5_01,
493 SERVICE_UNAVAILABLE_5_03,
494 GATEWAY_TIMEOUT_5_04,
495 PROXYING_NOT_SUPPORTED_5_05
509 APPLICATION_LINK_FORMAT,
511 APPLICATION_OCTET_STREAM,
513 APPLICATION_SOAP_XML,
514 APPLICATION_ATOM_XML,
515 APPLICATION_XMPP_XML,
517 APPLICATION_FASTINFOSET,
518 APPLICATION_SOAP_FASTINFOSET,
520 APPLICATION_X_OBIX_BINARY
void process_poll(struct process *p)
Request a process to be polled.
process_event_t tcpip_event
The uIP event.
rest_resource_flags_t
Resource flags for allowed methods and special functionalities.
Default definitions of C compiler quirk work-arounds.
#define PROCESS_END()
Define the end of a process.
#define PROCESS(name, strname)
Declare a process.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
uip_appdata
Pointer to the application data in the packet buffer.
#define UIP_IP_BUF
Pointer to IP header.
#define PT_EXIT(pt)
Exit the protothread.
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
void rest_activate_resource(resource_t *resource, char *path)
Makes a resource available under the given URI path.
#define NULL
The null pointer.
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
#define PROCESS_YIELD()
Yield the currently running process.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
void process_start(struct process *p, process_data_t data)
Start a process.
#define PT_END(pt)
Declare the end of a protothread.
#define PROCESS_CURRENT()
Get a pointer to the currently running process.
CoAP implementation for the REST Engine.
#define uip_newdata()
Is new incoming data available?
#define PROCESS_BEGIN()
Define the beginning of a process.