54 #define LOG_MODULE "coap-eng" 55 #define LOG_LEVEL LOG_LEVEL_COAP 57 static void process_callback(coap_timer_t *t);
63 static int invoke_coap_resource_service(coap_message_t *request,
64 coap_message_t *response,
65 uint8_t *buffer, uint16_t buffer_size,
72 LIST(coap_resource_services);
73 static uint8_t is_initialized = 0;
79 coap_add_handler(coap_handler_t *handler)
85 coap_remove_handler(coap_handler_t *handler)
91 coap_call_handlers(coap_message_t *request, coap_message_t *response,
92 uint8_t *buffer, uint16_t buffer_size, int32_t *offset)
94 coap_handler_status_t status;
96 for(r =
list_head(coap_handlers); r != NULL; r = r->next) {
98 status = r->handler(request, response, buffer, buffer_size, offset);
99 if(status != COAP_HANDLER_STATUS_CONTINUE) {
103 if(request->code == COAP_GET) {
104 coap_observe_handler(NULL, request, response);
111 return COAP_HANDLER_STATUS_CONTINUE;
114 static CC_INLINE coap_handler_status_t
115 call_service(coap_message_t *request, coap_message_t *response,
116 uint8_t *buffer, uint16_t buffer_size, int32_t *offset)
118 coap_handler_status_t status;
119 status = coap_call_handlers(request, response, buffer, buffer_size, offset);
120 if(status != COAP_HANDLER_STATUS_CONTINUE) {
123 status = invoke_coap_resource_service(request, response, buffer, buffer_size, offset);
124 if(status != COAP_HANDLER_STATUS_CONTINUE) {
128 coap_set_status_code(response, NOT_FOUND_4_04);
130 return COAP_HANDLER_STATUS_CONTINUE;
138 extern coap_resource_t res_well_known_core;
144 coap_receive(
const coap_endpoint_t *src,
145 uint8_t *payload, uint16_t payload_length)
148 static coap_message_t message[1];
149 static coap_message_t response[1];
150 coap_transaction_t *transaction = NULL;
151 coap_handler_status_t status;
153 coap_status_code = coap_parse_message(message, payload, payload_length);
154 coap_set_src_endpoint(message, src);
156 if(coap_status_code == NO_ERROR) {
160 LOG_DBG(
" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version,
161 message->type, message->token_len, message->code, message->mid);
163 LOG_DBG_COAP_STRING(message->uri_path, message->uri_path_len);
165 LOG_DBG(
" Payload: ");
166 LOG_DBG_COAP_STRING((
const char *)message->payload, message->payload_len);
170 if(message->code >= COAP_GET && message->code <= COAP_DELETE) {
173 if((transaction = coap_new_transaction(message->mid, src))) {
174 uint32_t block_num = 0;
175 uint16_t block_size = COAP_MAX_BLOCK_SIZE;
176 uint32_t block_offset = 0;
177 int32_t new_offset = 0;
180 if(message->type == COAP_TYPE_CON) {
182 coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
186 coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
190 if(message->token_len) {
191 coap_set_token(response, message->token, message->token_len);
194 if(coap_get_header_block2
195 (message, &block_num, NULL, &block_size, &block_offset)) {
196 LOG_DBG(
"Blockwise: block request %"PRIu32
" (%u/%u) @ %"PRIu32
" bytes\n",
197 block_num, block_size, COAP_MAX_BLOCK_SIZE, block_offset);
198 block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE);
199 new_offset = block_offset;
203 LOG_DBG(
"Blockwise: block request offset overflow\n");
204 coap_status_code = BAD_OPTION_4_02;
205 coap_error_message =
"BlockOutOfScope";
206 status = COAP_HANDLER_STATUS_CONTINUE;
209 status = call_service(message, response,
210 transaction->message + COAP_MAX_HEADER_SIZE,
211 block_size, &new_offset);
214 if(status != COAP_HANDLER_STATUS_CONTINUE) {
216 if(coap_status_code == NO_ERROR) {
221 if(coap_is_option(message, COAP_OPTION_BLOCK1)
222 && response->code < BAD_REQUEST_4_00
223 && !coap_is_option(response, COAP_OPTION_BLOCK1)) {
224 LOG_DBG(
"Block1 NOT IMPLEMENTED\n");
226 coap_status_code = NOT_IMPLEMENTED_5_01;
227 coap_error_message =
"NoBlock1Support";
230 }
else if(coap_is_option(message, COAP_OPTION_BLOCK2)) {
233 if(new_offset == block_offset) {
234 LOG_DBG(
"Blockwise: unaware resource with payload length %u/%u\n",
235 response->payload_len, block_size);
236 if(block_offset >= response->payload_len) {
237 LOG_DBG(
"handle_incoming_data(): block_offset >= response->payload_len\n");
239 response->code = BAD_OPTION_4_02;
240 coap_set_payload(response,
"BlockOutOfScope", 15);
242 coap_set_header_block2(response, block_num,
243 response->payload_len -
244 block_offset > block_size,
246 coap_set_payload(response,
247 response->payload + block_offset,
248 MIN(response->payload_len -
249 block_offset, block_size));
254 LOG_DBG(
"Blockwise: blockwise resource, new offset %"PRId32
"\n",
256 coap_set_header_block2(response, block_num,
258 || response->payload_len >
259 block_size, block_size);
261 if(response->payload_len > block_size) {
262 coap_set_payload(response, response->payload,
268 }
else if(new_offset != 0) {
269 LOG_DBG(
"Blockwise: no block option for blockwise resource, using block size %u\n",
270 COAP_MAX_BLOCK_SIZE);
272 coap_set_header_block2(response, 0, new_offset != -1,
273 COAP_MAX_BLOCK_SIZE);
274 coap_set_payload(response, response->payload,
275 MIN(response->payload_len,
276 COAP_MAX_BLOCK_SIZE));
282 if(coap_status_code == NO_ERROR) {
283 if((transaction->message_len = coap_serialize_message(response,
287 coap_status_code = PACKET_SERIALIZATION_ERROR;
291 coap_status_code = SERVICE_UNAVAILABLE_5_03;
292 coap_error_message =
"NoFreeTraBuffer";
298 if(message->type == COAP_TYPE_CON && message->code == 0) {
299 LOG_INFO(
"Received Ping\n");
300 coap_status_code = PING_RESPONSE;
301 }
else if(message->type == COAP_TYPE_ACK) {
303 LOG_DBG(
"Received ACK\n");
304 }
else if(message->type == COAP_TYPE_RST) {
305 LOG_INFO(
"Received RST\n");
307 coap_remove_observer_by_mid(src, message->mid);
310 if((transaction = coap_get_transaction_by_mid(message->mid))) {
312 coap_resource_response_handler_t callback = transaction->callback;
313 void *callback_data = transaction->callback_data;
315 coap_clear_transaction(transaction);
319 callback(callback_data, message);
325 #if COAP_OBSERVE_CLIENT 327 if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON)
328 && coap_is_option(message, COAP_OPTION_OBSERVE)) {
329 LOG_DBG(
"Observe [%"PRId32
"]\n", message->observe);
330 coap_handle_notification(src, message);
337 if(coap_status_code == NO_ERROR) {
339 coap_send_transaction(transaction);
341 }
else if(coap_status_code == MANUAL_RESPONSE) {
342 LOG_DBG(
"Clearing transaction for manual response");
343 coap_clear_transaction(transaction);
345 coap_message_type_t reply_type = COAP_TYPE_ACK;
347 LOG_WARN(
"ERROR %u: %s\n", coap_status_code, coap_error_message);
348 coap_clear_transaction(transaction);
350 if(coap_status_code == PING_RESPONSE) {
351 coap_status_code = 0;
352 reply_type = COAP_TYPE_RST;
353 }
else if(coap_status_code >= 192) {
355 coap_status_code = INTERNAL_SERVER_ERROR_5_00;
358 coap_init_message(message, reply_type, coap_status_code,
360 coap_set_payload(message, coap_error_message,
361 strlen(coap_error_message));
362 coap_sendto(src, payload, coap_serialize_message(message, payload));
366 return coap_status_code;
370 coap_engine_init(
void)
378 LOG_INFO(
"Starting CoAP engine...\n");
386 coap_init_connection();
401 coap_periodic_resource_t *periodic;
402 resource->url = path;
403 list_add(coap_resource_services, resource);
405 LOG_INFO(
"Activating: %s\n", resource->url);
408 if(resource->flags & IS_PERIODIC && resource->periodic
409 && resource->periodic->periodic_handler
410 && resource->periodic->period) {
411 LOG_DBG(
"Periodic resource: %p (%s)\n", resource->periodic, path);
412 periodic = resource->periodic;
426 return list_head(coap_resource_services);
436 invoke_coap_resource_service(coap_message_t *request, coap_message_t *response,
437 uint8_t *buffer, uint16_t buffer_size,
443 coap_resource_t *resource = NULL;
444 const char *url = NULL;
445 int url_len, res_url_len;
447 url_len = coap_get_header_uri_path(request, &url);
448 for(resource =
list_head(coap_resource_services);
449 resource; resource = resource->next) {
452 res_url_len = strlen(resource->url);
453 if((url_len == res_url_len
454 || (url_len > res_url_len
455 && (resource->flags & HAS_SUB_RESOURCES)
456 && url[res_url_len] ==
'/'))
457 && strncmp(resource->url, url, res_url_len) == 0) {
461 LOG_INFO(
"/%s, method %u, resource->flags %u\n", resource->url,
462 (uint16_t)method, resource->flags);
464 if((method & METHOD_GET) && resource->get_handler != NULL) {
466 resource->get_handler(request, response, buffer, buffer_size, offset);
467 }
else if((method & METHOD_POST) && resource->post_handler != NULL) {
469 resource->post_handler(request, response, buffer, buffer_size,
471 }
else if((method & METHOD_PUT) && resource->put_handler != NULL) {
473 resource->put_handler(request, response, buffer, buffer_size, offset);
474 }
else if((method & METHOD_DELETE) && resource->delete_handler != NULL) {
476 resource->delete_handler(request, response, buffer, buffer_size,
480 coap_set_status_code(response, METHOD_NOT_ALLOWED_4_05);
486 coap_set_status_code(response, NOT_FOUND_4_04);
489 if(resource->flags & IS_OBSERVABLE) {
490 coap_observe_handler(resource, request, response);
493 return found & allowed;
498 process_callback(coap_timer_t *t)
500 coap_resource_t *resource;
502 if(resource != NULL && (resource->flags & IS_PERIODIC)
503 && resource->periodic != NULL && resource->periodic->period) {
504 LOG_DBG(
"Periodic: timer expired for /%s (period: %"PRIu32
")\n",
505 resource->url, resource->periodic->period);
507 if(!is_initialized) {
509 }
else if(resource->periodic->periodic_handler) {
511 resource->periodic->periodic_handler();
static void * coap_timer_get_user_data(coap_timer_t *timer)
Get user data that has been attached to a CoAP timer.
void coap_transport_init(void)
Initialize the CoAP transport.
CoAP engine implementation.
void coap_activate_resource(coap_resource_t *resource, const char *path)
Makes a resource available under the given URI path.
static void coap_timer_set_callback(coap_timer_t *timer, void(*callback)(coap_timer_t *))
Set a callback function to be called when a CoAP timer expires.
Linked list manipulation routines.
void * list_head(list_t list)
Get a pointer to the first element of a list.
int coap_sendto(const coap_endpoint_t *ep, const uint8_t *data, uint16_t len)
Send a message to the specified CoAP endpoint.
void list_add(list_t list, void *item)
Add an item at the end of a list.
void list_init(list_t list)
Initialize a list.
#define LIST(name)
Declare a linked list.
static void coap_timer_set_user_data(coap_timer_t *timer, void *data)
Attach user data to a CoAP timer.
void coap_timer_set(coap_timer_t *timer, uint64_t time)
Set a CoAP timer to expire after the specified time.
Default definitions of C compiler quirk work-arounds.
coap_resource_t * coap_get_first_resource(void)
Returns the first of registered CoAP resources.
coap_resource_t * coap_get_next_resource(coap_resource_t *resource)
Returns the next registered CoAP resource.
coap_resource_flags_t
Resource flags for allowed methods and special functionalities.
void list_remove(list_t list, void *item)
Remove a specific element from a list.
void * list_item_next(void *item)
Get the next item following this item.