47 #define PRINTF(...) printf(__VA_ARGS__)
48 #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])
49 #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])
52 #define PRINT6ADDR(addr)
53 #define PRINTLLADDR(addr)
56 PROCESS(coap_engine,
"CoAP Engine");
61 static service_callback_t service_cbk =
NULL;
69 erbium_status_code = NO_ERROR;
71 PRINTF(
"handle_incoming_data(): received uip_datalen=%u \n",
75 static coap_packet_t message[1];
76 static coap_packet_t response[1];
77 static coap_transaction_t *transaction =
NULL;
81 PRINTF(
"receiving UDP datagram from: ");
83 PRINTF(
":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF->srcport),
89 if(erbium_status_code == NO_ERROR) {
93 PRINTF(
" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version,
94 message->type, message->token_len, message->code, message->mid);
95 PRINTF(
" URL: %.*s\n", message->uri_path_len, message->uri_path);
96 PRINTF(
" Payload: %.*s\n", message->payload_len, message->payload);
99 if(message->code >= COAP_GET && message->code <= COAP_DELETE) {
103 coap_new_transaction(message->mid, &
UIP_IP_BUF->srcipaddr,
104 UIP_UDP_BUF->srcport))) {
105 uint32_t block_num = 0;
106 uint16_t block_size = REST_MAX_CHUNK_SIZE;
107 uint32_t block_offset = 0;
108 int32_t new_offset = 0;
111 if(message->type == COAP_TYPE_CON) {
113 coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
117 coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
120 }
if(message->token_len) {
121 coap_set_token(response, message->token, message->token_len);
124 if(coap_get_header_block2
125 (message, &block_num,
NULL, &block_size, &block_offset)) {
126 PRINTF(
"Blockwise: block request %lu (%u/%u) @ %lu bytes\n",
127 block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
128 block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
129 new_offset = block_offset;
137 (message, response, transaction->packet + COAP_MAX_HEADER_SIZE,
138 block_size, &new_offset)) {
140 if(erbium_status_code == NO_ERROR) {
145 if(IS_OPTION(message, COAP_OPTION_BLOCK1)
146 && response->code < BAD_REQUEST_4_00
147 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
148 PRINTF(
"Block1 NOT IMPLEMENTED\n");
150 erbium_status_code = NOT_IMPLEMENTED_5_01;
151 coap_error_message =
"NoBlock1Support";
154 }
else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) {
157 if(new_offset == block_offset) {
159 (
"Blockwise: unaware resource with payload length %u/%u\n",
160 response->payload_len, block_size);
161 if(block_offset >= response->payload_len) {
163 (
"handle_incoming_data(): block_offset >= response->payload_len\n");
165 response->code = BAD_OPTION_4_02;
166 coap_set_payload(response,
"BlockOutOfScope", 15);
168 coap_set_header_block2(response, block_num,
169 response->payload_len -
170 block_offset > block_size,
172 coap_set_payload(response,
173 response->payload + block_offset,
174 MIN(response->payload_len -
175 block_offset, block_size));
180 PRINTF(
"Blockwise: blockwise resource, new offset %ld\n",
182 coap_set_header_block2(response, block_num,
184 || response->payload_len >
185 block_size, block_size);
187 if(response->payload_len > block_size) {
188 coap_set_payload(response, response->payload,
194 }
else if(new_offset != 0) {
196 (
"Blockwise: no block option for blockwise resource, using block size %u\n",
197 COAP_MAX_BLOCK_SIZE);
199 coap_set_header_block2(response, 0, new_offset != -1,
200 COAP_MAX_BLOCK_SIZE);
201 coap_set_payload(response, response->payload,
202 MIN(response->payload_len,
203 COAP_MAX_BLOCK_SIZE));
209 if(erbium_status_code == NO_ERROR) {
210 if((transaction->packet_len = coap_serialize_message(response,
214 erbium_status_code = PACKET_SERIALIZATION_ERROR;
218 erbium_status_code = NOT_IMPLEMENTED_5_01;
219 coap_error_message =
"NoServiceCallbck";
222 erbium_status_code = SERVICE_UNAVAILABLE_5_03;
223 coap_error_message =
"NoFreeTraBuffer";
229 if(message->type == COAP_TYPE_CON && message->code == 0) {
230 PRINTF(
"Received Ping\n");
231 erbium_status_code = PING_RESPONSE;
232 }
else if(message->type == COAP_TYPE_ACK) {
234 PRINTF(
"Received ACK\n");
235 }
else if(message->type == COAP_TYPE_RST) {
236 PRINTF(
"Received RST\n");
238 coap_remove_observer_by_mid(&
UIP_IP_BUF->srcipaddr,
239 UIP_UDP_BUF->srcport, message->mid);
242 if((transaction = coap_get_transaction_by_mid(message->mid))) {
244 restful_response_handler callback = transaction->callback;
245 void *callback_data = transaction->callback_data;
247 coap_clear_transaction(transaction);
251 callback(callback_data, message);
260 if(erbium_status_code == NO_ERROR) {
262 coap_send_transaction(transaction);
264 }
else if(erbium_status_code == MANUAL_RESPONSE) {
265 PRINTF(
"Clearing transaction for manual response");
266 coap_clear_transaction(transaction);
268 coap_message_type_t reply_type = COAP_TYPE_ACK;
270 PRINTF(
"ERROR %u: %s\n", erbium_status_code, coap_error_message);
271 coap_clear_transaction(transaction);
273 if(erbium_status_code == PING_RESPONSE) {
274 erbium_status_code = 0;
275 reply_type = COAP_TYPE_RST;
276 }
else if(erbium_status_code >= 192) {
278 erbium_status_code = INTERNAL_SERVER_ERROR_5_00;
281 coap_init_message(message, reply_type, erbium_status_code,
283 coap_set_payload(message, coap_error_message,
284 strlen(coap_error_message));
285 coap_send_message(&
UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport,
292 return erbium_status_code;
296 coap_init_engine(
void)
302 coap_set_service_callback(service_callback_t callback)
304 service_cbk = callback;
308 coap_get_rest_method(
void *packet)
311 (((coap_packet_t *)packet)->code - 1));
318 extern resource_t res_well_known_core;
320 extern resource_t res_dtls;
327 PRINTF(
"Starting %s receiver...\n", coap_rest_implementation.name);
331 coap_register_as_transaction_handler();
332 coap_init_connection(SERVER_LISTEN_PORT);
339 }
else if(ev == PROCESS_EVENT_TIMER) {
341 coap_check_transactions();
351 coap_blocking_request_callback(
void *callback_data,
void *response)
353 struct request_state_t *state = (
struct request_state_t *)callback_data;
355 state->response = (coap_packet_t *)response;
360 (
struct request_state_t *state, process_event_t ev,
361 uip_ipaddr_t *remote_ipaddr, uint16_t remote_port,
362 coap_packet_t *request,
363 blocking_response_handler request_callback))
368 static uint32_t res_block;
369 static uint8_t block_error;
371 state->block_num = 0;
372 state->response =
NULL;
380 request->mid = coap_get_mid();
381 if((state->transaction = coap_new_transaction(request->mid, remote_ipaddr,
383 state->transaction->callback = coap_blocking_request_callback;
384 state->transaction->callback_data = state;
386 if(state->block_num > 0) {
387 coap_set_header_block2(request, state->block_num, 0,
388 REST_MAX_CHUNK_SIZE);
390 state->transaction->packet_len = coap_serialize_message(request,
395 coap_send_transaction(state->transaction);
396 PRINTF(
"Requested #%lu (MID %u)\n", state->block_num, request->mid);
400 if(!state->response) {
401 PRINTF(
"Server not responding\n");
405 coap_get_header_block2(state->response, &res_block, &more,
NULL,
NULL);
407 PRINTF(
"Received #%lu%s (%u bytes)\n", res_block, more ?
"+" :
"",
408 state->response->payload_len);
410 if(res_block == state->block_num) {
411 request_callback(state->response);
412 ++(state->block_num);
414 PRINTF(
"WRONG BLOCK %lu/%lu\n", res_block, state->block_num);
418 PRINTF(
"Could not allocate transaction buffer");
421 }
while(more && block_error < COAP_MAX_ATTEMPTS);
428 const struct rest_implementation coap_rest_implementation = {
432 coap_set_service_callback,
434 coap_get_header_uri_path,
435 coap_get_rest_method,
436 coap_set_status_code,
438 coap_get_header_content_format,
439 coap_set_header_content_format,
440 coap_get_header_accept,
441 coap_get_header_size2,
442 coap_set_header_size2,
443 coap_get_header_max_age,
444 coap_set_header_max_age,
445 coap_set_header_etag,
446 coap_get_header_if_match,
447 coap_get_header_if_none_match,
448 coap_get_header_uri_host,
449 coap_set_header_location_path,
454 coap_get_header_uri_query,
455 coap_get_query_variable,
456 coap_get_post_variable,
458 coap_notify_observers,
459 coap_observe_handler,
472 METHOD_NOT_ALLOWED_4_05,
474 REQUEST_ENTITY_TOO_LARGE_4_13,
475 UNSUPPORTED_MEDIA_TYPE_4_15,
476 INTERNAL_SERVER_ERROR_5_00,
477 NOT_IMPLEMENTED_5_01,
479 SERVICE_UNAVAILABLE_5_03,
480 GATEWAY_TIMEOUT_5_04,
481 PROXYING_NOT_SUPPORTED_5_05
495 APPLICATION_LINK_FORMAT,
497 APPLICATION_OCTET_STREAM,
499 APPLICATION_SOAP_XML,
500 APPLICATION_ATOM_XML,
501 APPLICATION_XMPP_XML,
503 APPLICATION_FASTINFOSET,
504 APPLICATION_SOAP_FASTINFOSET,
506 APPLICATION_X_OBIX_BINARY
#define PROCESS_CURRENT()
Get a pointer to the currently running process.
rest_resource_flags_t
Resource flags for allowed methods and special functionalities.
void process_poll(struct process *p)
Request a process to be polled.
#define PROCESS_BEGIN()
Define the beginning of a process.
#define uip_newdata()
Is new incoming data available?
#define NULL
The null pointer.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
#define UIP_IP_BUF
Pointer to IP header.
#define PROCESS_END()
Define the end of a process.
void rest_activate_resource(resource_t *resource, char *path)
Makes a resource available under the given URI path.
CoAP implementation for the REST Engine.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
#define PROCESS(name, strname)
Declare a process.
#define uip_datalen()
The length of any incoming data that is currently available (if available) in the uip_appdata buffer...
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
process_event_t tcpip_event
The uIP event.
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_YIELD()
Yield the currently running process.
#define PT_EXIT(pt)
Exit the protothread.
uip_appdata
Pointer to the application data in the packet buffer.