void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType, const char * payload, int payloadLen, int sequence) { coap_packet_t notify; coap_transaction_t *transaction; Lwm2m_Debug("Coap notify: %s\n", path); Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr)); Lwm2m_Debug("Coap request port: %d\n", addr->Port); coap_init_message(¬ify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); if (contentType != ContentType_None) { coap_set_header_content_format(¬ify, contentType); coap_set_payload(¬ify, payload, payloadLen); } coap_set_token(¬ify, token, tokenSize); coap_set_header_observe(¬ify, sequence); if ((transaction = coap_new_transaction(notify.mid, &addr->Addr, uip_htons(addr->Port)))) { transaction->packet_len = coap_serialize_message(¬ify, transaction->packet); coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction(); } }
void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType, const char * payload, int payloadLen, int sequence) { // TODO - FIXME: if path is not full uri then map addr to Network address + append path(?) coap_packet_t notify; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(path, strlen(path)); Lwm2m_Debug("Coap notify: %s\n", path); //Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr)); //Lwm2m_Debug("Coap request port: %d\n", addr->Port); coap_init_message(¬ify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); if (contentType != ContentType_None) { coap_set_header_content_format(¬ify, contentType); coap_set_payload(¬ify, payload, payloadLen); } coap_set_token(¬ify, token, tokenSize); coap_set_header_observe(¬ify, sequence); if ((transaction = coap_new_transaction(networkSocket, notify.mid, remoteAddress))) { transaction->packet_len = coap_serialize_message(¬ify, transaction->packet); coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction(); } }
void coap_createCoapRequest(void * context, coap_method_t method, const char * uri, ContentType contentType, const char * payload, int payloadLen, TransactionCallback callback) { coap_packet_t request; uip_ipaddr_t * remote_ipaddr = coap_getIpFromURI(uri); int remote_port = coap_getPortFromURI(uri); coap_transaction_t *transaction; char path[128] = {0}; char query[128] = {0}; coap_getPathQueryFromURI(uri, path, query); Lwm2m_Debug("Coap request: %s\n", uri); Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(remote_ipaddr)); Lwm2m_Debug("Coap request port: %d\n", remote_port); Lwm2m_Debug("Coap request path: %s\n", path); Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); coap_set_header_uri_query(&request, query); if (contentType != ContentType_None) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) { transaction->callback = coap_CoapRequestCallback; CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; memcpy(&CurrentTransaction[CurrentTransactionIndex].Address.Addr, remote_ipaddr, sizeof(uip_ipaddr_t)); CurrentTransaction[CurrentTransactionIndex].Address.Port = uip_htons(remote_port); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if(CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }
/*----------------------------------------------------------------------------*/ PROCESS_THREAD(tres_process, ev, data) { PROCESS_BEGIN(); srand(node_id); rest_init_engine(); tres_init(); SENSORS_ACTIVATE(light_sensor); rest_activate_periodic_resource(&periodic_resource_light); rplinfo_activate_resources(); static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ SERVER_NODE(&server_ipaddr); /* receives all CoAP messages */ coap_receiver_init(); int wait_time = getRandUint(MAX_WAITING); int base_wait = BASE_WAITING; static int g_time=0; static char content[12]; etimer_set(&et, (wait_time + base_wait) * CLOCK_SECOND); while(1) { PROCESS_YIELD(); if (etimer_expired(&et)) break; } etimer_reset(&et); etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); while(1) { PROCESS_YIELD(); if (etimer_expired(&et)) { coap_init_message(request, COAP_TYPE_NON, COAP_POST, 0 ); coap_set_header_uri_path(request, service_urls[1]); coap_set_payload(request, content, snprintf(content, sizeof(content), "%d", g_time++)); coap_transaction_t *transaction; request->mid = coap_get_mid(); if ((transaction = coap_new_transaction(request->mid, &server_ipaddr, REMOTE_PORT))) { transaction->packet_len = coap_serialize_message(request, transaction->packet); coap_send_transaction(transaction); } etimer_reset(&et); } } /* while (1) */ PROCESS_END(); }
/*----------------------------------------------------------------------------*/ PROCESS_THREAD(tres_process, ev, data) { PROCESS_BEGIN(); srand(node_id); rest_init_engine(); tres_init(); rest_activate_resource(&actuator, "actuator"); rplinfo_activate_resources(); sprintf(setpoint, "0"); #if PYOT_KEEPALIVE static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ SERVER_NODE(&server_ipaddr); int wait_time = (unsigned int)(rand() % MAX_WAITING); int base_wait = BASE_WAITING; static int g_time=0; static char content[12]; etimer_set(&et, (wait_time + base_wait) * CLOCK_SECOND); while(1) { PROCESS_YIELD(); //PROCESS_WAIT_EVENT(); if (etimer_expired(&et)) break; } etimer_reset(&et); etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); while(1) { PROCESS_YIELD(); if (etimer_expired(&et)) { coap_init_message(request, COAP_TYPE_NON, COAP_POST, 0 ); coap_set_header_uri_path(request, "/rd"); coap_set_payload(request, content, snprintf(content, sizeof(content), "%d", g_time++)); //PRINT6ADDR(&server_ipaddr); //PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); coap_transaction_t *transaction; request->mid = coap_get_mid(); if ((transaction = coap_new_transaction(request->mid, &server_ipaddr, REMOTE_PORT))) { transaction->packet_len = coap_serialize_message(request, transaction->packet); coap_send_transaction(transaction); } etimer_reset(&et); } } /* while (1) */ #endif PROCESS_END(); }
/*-----------------------------------------------------------------------------------*/ void coap_notify_observers(resource_t *resource, int32_t obs_counter, void *notification) { coap_packet_t *const coap_res = (coap_packet_t *) notification; coap_observer_t* obs = NULL; uint8_t preferred_type = coap_res->type; PRINTF("Observing: Notification from %s\n", resource->url); /* Iterate over observers. */ for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) { if (obs->url==resource->url) /* using RESOURCE url pointer as handle */ { coap_transaction_t *transaction = NULL; /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers. */ if ( (transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port)) ) { PRINTF(" Observer "); PRINT6ADDR(&obs->addr); PRINTF(":%u\n", obs->port); /* Update last MID for RST matching. */ obs->last_mid = transaction->mid; /* Prepare response */ coap_res->mid = transaction->mid; coap_set_header_observe(coap_res, obs_counter); coap_set_header_token(coap_res, obs->token, obs->token_len); /* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */ if (stimer_expired(&obs->refresh_timer)) { PRINTF(" Refreshing with CON\n"); coap_res->type = COAP_TYPE_CON; stimer_restart(&obs->refresh_timer); } else { coap_res->type = preferred_type; } transaction->packet_len = coap_serialize_message(coap_res, transaction->packet); coap_send_transaction(transaction); } } } }
/*---------------------------------------------------------------------------*/ void coap_notify_observers(resource_t *resource) { /* build notification */ coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */ coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0); coap_observer_t *obs = NULL; PRINTF("Observe: Notification from %s\n", resource->url); /* iterate over observers */ for(obs = (coap_observer_t *)list_head(observers_list); obs; obs = obs->next) { if(obs->url == resource->url) { /* using RESOURCE url pointer as handle */ coap_transaction_t *transaction = NULL; /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ if((transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) { if(obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0) { PRINTF(" Force Confirmable for\n"); notification->type = COAP_TYPE_CON; } PRINTF(" Observer "); PRINT6ADDR(&obs->addr); PRINTF(":%u\n", obs->port); /* update last MID for RST matching */ obs->last_mid = transaction->mid; /* prepare response */ notification->mid = transaction->mid; resource->get_handler(NULL, notification, transaction->packet + COAP_MAX_HEADER_SIZE, REST_MAX_CHUNK_SIZE, NULL); if(notification->code < BAD_REQUEST_4_00) { coap_set_header_observe(notification, (obs->obs_counter)++); } coap_set_token(notification, obs->token, obs->token_len); transaction->packet_len = coap_serialize_message(notification, transaction->packet); coap_send_transaction(transaction); } } } }
void separate_finalize_handler() { if(separate_active) { coap_transaction_t *transaction = NULL; if((transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port))) { /* This way the packet can be treated as pointer as usual. */ coap_packet_t response[1]; /* Restore the request information for the response. */ coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); /* * Be aware to respect the Block2 option, which is also stored * in the coap_separate_t. As it is a critical option, this * example resource pretends to handle it for compliance. */ coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); /* Warning: No check for serialization error. */ transaction->packet_len = coap_serialize_message(response, transaction->packet); coap_send_transaction(transaction); /* The engine will clear the transaction (right after send for NON, after acked for CON). */ separate_active = 0; } else { /* * Set timer for retry, send error message, ... * The example simply waits for another button press. */ } } /* if (separate_active) */ }
void oc_send_separate_response(oc_separate_response_t *handle, oc_status_t response_code) { oc_response_buffer_t response_buffer; response_buffer.buffer = handle->buffer; response_buffer.response_length = response_length(); response_buffer.code = oc_status_code(response_code); coap_separate_t *cur = oc_list_head(handle->requests), *next = NULL; coap_packet_t response[1]; while (cur != NULL) { next = cur->next; if (cur->observe > 0) { coap_transaction_t *t = coap_new_transaction(coap_get_mid(), &cur->endpoint); if (t) { coap_separate_resume(response, cur, oc_status_code(response_code), t->mid); coap_set_header_content_format(response, APPLICATION_CBOR); if (cur->observe == 1) { coap_set_header_observe(response, 1); } if (response_buffer.response_length > 0) { coap_set_payload(response, handle->buffer, response_buffer.response_length); } t->message->length = coap_serialize_message(response, t->message->data); coap_send_transaction(t); } coap_separate_clear(handle, cur); } else { if (coap_notify_observers(NULL, &response_buffer, &cur->endpoint) == 0) { coap_separate_clear(handle, cur); } } cur = next; } if (oc_list_length(handle->requests) == 0) { handle->active = 0; } }
static void res_resume_handler() { if(separate_active) { PRINTF("/separate "); coap_transaction_t *transaction = NULL; if((transaction = coap_new_transaction(separate_store->request_metadata.mid, NULL, &separate_store->request_metadata.addr, separate_store->request_metadata.port))) { PRINTF( "RESPONSE (%s %u)\n", separate_store->request_metadata.type == COAP_TYPE_CON ? "CON" : "NON", separate_store->request_metadata.mid); coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ /* Restore the request information for the response. */ coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); REST.set_header_content_type(response, REST.type.TEXT_PLAIN); coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); /* * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. * As it is a critical option, this example resource pretends to handle it for compliance. */ coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); /* Warning: No check for serialization error. */ transaction->packet_len = coap_serialize_message(response, transaction->packet); coap_send_transaction(transaction); /* The engine will clear the transaction (right after send for NON, after acked for CON). */ separate_active = 0; } else { PRINTF("ERROR (transaction)\n"); } } /* if (separate_active) */ }
/*-----------------------------------------------------------------------------------*/ void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len) { coap_observer_t* obs = NULL; for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) { if (obs->url==url) /* using RESOURCE url string as handle */ { coap_transaction_t *transaction = NULL; /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ if ( (transaction = coap_new_transaction(coap_get_tid(), &obs->addr, obs->port)) ) { /* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */ if (stimer_expired(&obs->refresh_timer)) { PRINTF("Observing: Refresh client with CON\n"); type = COAP_TYPE_CON; stimer_restart(&obs->refresh_timer); } /* prepare response */ coap_packet_t push[1]; /* This way the packet can be treated as pointer as usual. */ coap_init_message(push, (coap_message_type_t)type, OK_200, transaction->tid ); coap_set_header_observe(push, observe); coap_set_header_token(push, obs->token, obs->token_len); coap_set_payload(push, payload, payload_len); transaction->packet_len = coap_serialize_message(push, transaction->packet); PRINTF("Observing: Notify from /%s for ", url); PRINT6ADDR(&obs->addr); PRINTF(":%u\n", obs->port); PRINTF(" %.*s\n", payload_len, payload); coap_send_transaction(transaction); } } } }
static int coap_receive(void) { coap_error_code = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n", (uint16_t)uip_datalen()); if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen()); if (coap_error_code==NO_ERROR) { /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, message->type, message->token_len, message->code, message->mid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); /* Handle requests. */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { #if COAP_CEU int ret; TCEU_Transaction t = { message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, request1, NULL, NULL, NULL, 0, {} }; tceu__int___void_ ps = { &ret, &t }; ceu_go_event(CEU_IN_COAP_REQUEST, &ps); if (! ret) { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } #else /* Use transaction buffer for response to confirmable request. */ if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) { request1(transaction,NULL); } else { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if (transaction buffer) */ #endif } else { /* Responses */ if (message->type==COAP_TYPE_CON && message->code==0) { PRINTF("Received Ping\n"); coap_error_code = PING_RESPONSE; } else if (message->type==COAP_TYPE_ACK) { /* Transactions are closed through lookup below */ PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ #ifdef COAP_OBSERVER coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); #endif } #if COAP_CEU ceu_go_event(CEU_IN_COAP_RESPONSE, message); #else if ( (transaction = coap_get_transaction_by_mid(message->mid)) ) { /* Free transaction memory before callback, as it may create a new transaction. */ restful_response_handler callback = transaction->callback; void *callback_data = transaction->callback_data; coap_clear_transaction(transaction); /* Check if someone registered for the response */ if (callback) { callback(callback_data, message); } } /* if (ACKed transaction) */ transaction = NULL; #endif } /* Request or Response */ } /* if (parsed correctly) */ if (coap_error_code==NO_ERROR) { #if ! COAP_CEU if (transaction) coap_send_transaction(transaction); #endif } else if (coap_error_code==MANUAL_RESPONSE) /* TODO! */ { PRINTF("Clearing transaction for manual response"); #if ! COAP_CEU coap_clear_transaction(transaction); #endif } else { coap_message_type_t reply_type = COAP_TYPE_ACK; PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); #if ! COAP_CEU coap_clear_transaction(transaction); #endif /* Set to sendable error code. */ if (coap_error_code >= 192) { coap_error_code = INTERNAL_SERVER_ERROR_5_00; } if (coap_error_code == PING_RESPONSE) { coap_error_code = 0; reply_type = COAP_TYPE_RST; } /* Reuse input buffer for error message. */ coap_init_message(message, reply_type, coap_error_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return coap_error_code; }
PROCESS_THREAD(poti, ev, data) { static struct etimer loop_timer; PROCESS_BEGIN(); /* Initialize the REST engine. */ rest_init_engine (); SERVER_NODE (&server_ipaddr); adc_init (); /* Activate the application-specific resources. */ #if PLATFORM_HAS_BATTERY SENSORS_ACTIVATE(battery_sensor); rest_activate_resource (&res_battery, "s/battery"); #endif rest_activate_resource (&res_server_ip, "poti/ip"); rest_activate_resource (&res_server_resource, "poti/resource"); rest_activate_resource (&res_interval, "poti/interval"); etimer_set (&loop_timer, LOOP_INTERVAL); /* Define application-specific events here. */ while(1) { static int count = 0; static int lastval = -1; static coap_packet_t request [1]; /* Array: treat as pointer */ uint8_t val = 127; PROCESS_WAIT_EVENT(); if (etimer_expired (&loop_timer)) { uint16_t sum = 0; int i; count++; adc_setup (ADC_DEFAULT, A5); for (i=0; i<5; i++) { sum += adc_read (); clock_delay_usec (50); } adc_fin (); val = (sum / 5) >> 2; if ((interval > 0 && count > interval) || (val != lastval)) { char buf [4]; coap_transaction_t *transaction; sprintf (buf, "%d", val); lastval = val; printf ("Sending Value: %s\n", buf); coap_init_message (request, COAP_TYPE_NON, COAP_PUT, 0); coap_set_header_uri_path (request, server_resource); coap_set_header_content_format (request, REST.type.TEXT_PLAIN); coap_set_payload (request, buf, strlen (buf)); request->mid = coap_get_mid (); transaction = coap_new_transaction (request->mid, &server_ipaddr, REMOTE_PORT); transaction->packet_len = coap_serialize_message (request, transaction->packet); coap_send_transaction (transaction); count = 0; } etimer_reset (&loop_timer); } } /* while (1) */
/*----------------------------------------------------------------------------*/ static int coap_receive(void) { coap_error_code = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen()); /* Static declaration reduces stack peaks and program code size. */ static coap_packet_t message[1]; /* This way the packet can be treated as pointer as usual. */ static coap_packet_t response[1]; static coap_transaction_t *transaction = NULL; if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen()); if (coap_error_code==NO_ERROR) { /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, oc %u, c %u, mid %u\n", message->version, message->type, message->option_count, message->code, message->mid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); /* Handle requests. */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { /* Use transaction buffer for response to confirmable request. */ if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ if (message->type==COAP_TYPE_CON) { /* Reliable CON requests are answered with an ACK. */ coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); } /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { coap_set_header_token(response, message->token, message->token_len); SET_OPTION(response, COAP_OPTION_TOKEN); } /* get offset for blockwise transfers */ if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset)) { PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /* Invoke resource handler. */ if (service_cbk) { /* Call REST framework and check if found and allowed. */ if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset)) { if (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { PRINTF("Block1 NOT IMPLEMENTED\n"); coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; } else if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n"); response->code = BAD_OPTION_4_02; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if (valid offset) */ } else { /* resource provides chunk-wise data */ PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset); coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size); } /* if (resource aware of blockwise) */ } else if (new_offset!=0) { PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ } /* no errors/hooks */ } /* successful service callback */ /* Serialize response. */ if (coap_error_code==NO_ERROR) { if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0) { coap_error_code = PACKET_SERIALIZATION_ERROR; } } } else { coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoServiceCallbck"; // no a to fit 16 bytes } /* if (service callback) */ } else { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if (transaction buffer) */ } else { /* Responses */ if (message->type==COAP_TYPE_ACK) { PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); } transaction = coap_get_transaction_by_mid(message->mid); if (message->type != COAP_TYPE_CON && transaction) { /* Free transaction memory before callback, as it may create a new transaction. */ restful_response_handler callback = transaction->callback; void *callback_data = transaction->callback_data; coap_clear_transaction(transaction); /* Check if someone registered for the response */ if (callback) { callback(callback_data, message); } } /* if (ACKed transaction) */ /* Observe notification */ if ((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON) \ && IS_OPTION(message, COAP_OPTION_OBSERVE)) { PRINTF("Observe [%u]\n", message->observe); coap_handle_notification(&UIP_IP_BUF->srcipaddr, \ UIP_UDP_BUF->srcport, message); } transaction = NULL; } /* Request or Response */ } /* if (parsed correctly) */ if (coap_error_code==NO_ERROR) { if (transaction) coap_send_transaction(transaction); } else if (coap_error_code==MANUAL_RESPONSE) { PRINTF("Clearing transaction for manual response"); coap_clear_transaction(transaction); } else { PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); coap_clear_transaction(transaction); /* Set to sendable error code. */ if (coap_error_code >= 192) { coap_error_code = INTERNAL_SERVER_ERROR_5_00; } /* Reuse input buffer for error message. */ coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return coap_error_code; }
/*---------------------------------------------------------------------------*/ int coap_engine_receive(coap_context_t *coap_ctx) { erbium_status_code = NO_ERROR; coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ coap_packet_t response[1]; coap_transaction_t *transaction = NULL; PRINTF("%s(): received data len %u\n", __FUNCTION__, (uint16_t)uip_appdatalen(coap_ctx->buf)); if(uip_newdata(coap_ctx->buf)) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF(coap_ctx->buf)->srcipaddr); PRINTF(":%u\n Length: %u\n", uip_ntohs(UIP_UDP_BUF(coap_ctx->buf)->srcport), uip_appdatalen(coap_ctx->buf)); erbium_status_code = coap_parse_message(message, uip_appdata(coap_ctx->buf), uip_appdatalen(coap_ctx->buf)); coap_set_context(message, coap_ctx); if(erbium_status_code == NO_ERROR) { NET_COAP_STAT(recv++); /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version, message->type, message->token_len, message->code, message->mid); PRINTF(" URL[%d]: %.*s\n", message->uri_path_len, message->uri_path_len, message->uri_path); PRINTF(" Payload[%d]: %.*s\n", message->payload_len, message->payload_len, message->payload); /* handle requests */ if(message->code >= COAP_GET && message->code <= COAP_DELETE) { /* use transaction buffer for response to confirmable request */ if((transaction = coap_new_transaction(message->mid, coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport))) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ if(message->type == COAP_TYPE_CON) { /* reliable CON requests are answered with an ACK */ coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* unreliable NON requests are answered with a NON as well */ coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); /* mirror token */ } if(message->token_len) { coap_set_token(response, message->token, message->token_len); /* get offset for blockwise transfers */ } if(coap_get_header_block2 (message, &block_num, NULL, &block_size, &block_offset)) { PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", (unsigned long)block_num, block_size, REST_MAX_CHUNK_SIZE, (unsigned long)block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /* invoke resource handler */ if(service_cbk) { /* call REST framework and check if found and allowed */ if(service_cbk (message, response, transaction->packet + COAP_MAX_HEADER_SIZE, block_size, &new_offset)) { if(erbium_status_code == NO_ERROR) { /* TODO coap_handle_blockwise(request, response, start_offset, end_offset); */ /* resource is unaware of Block1 */ if(IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code < BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { PRINTF("Block1 NOT IMPLEMENTED\n"); erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; /* client requested Block2 transfer */ } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if(new_offset == block_offset) { PRINTF ("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if(block_offset >= response->payload_len) { PRINTF ("handle_incoming_data(): block_offset >= response->payload_len\n"); response->code = BAD_OPTION_4_02; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload + block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if(valid offset) */ /* resource provides chunk-wise data */ } else { PRINTF("Blockwise: blockwise resource, new offset %ld\n", (long)new_offset); coap_set_header_block2(response, block_num, new_offset != -1 || response->payload_len > block_size, block_size); if(response->payload_len > block_size) { coap_set_payload(response, response->payload, block_size); } } /* if(resource aware of blockwise) */ /* Resource requested Block2 transfer */ } else if(new_offset != 0) { PRINTF ("Blockwise: no block option for blockwise resource, using block size %u\n", COAP_MAX_BLOCK_SIZE); coap_set_header_block2(response, 0, new_offset != -1, COAP_MAX_BLOCK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, COAP_MAX_BLOCK_SIZE)); } /* blockwise transfer handling */ } /* no errors/hooks */ /* successful service callback */ /* serialize response */ } if(erbium_status_code == NO_ERROR) { if((transaction->packet_len = coap_serialize_message(response, transaction-> packet)) == 0) { erbium_status_code = PACKET_SERIALIZATION_ERROR; } } } else { erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */ } /* if(service callback) */ } else { erbium_status_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if(transaction buffer) */ /* handle responses */ } else { if(message->type == COAP_TYPE_CON && message->code == 0) { PRINTF("Received Ping\n"); erbium_status_code = PING_RESPONSE; } else if(message->type == COAP_TYPE_ACK) { /* transactions are closed through lookup below */ PRINTF("Received ACK\n"); } else if(message->type == COAP_TYPE_RST) { PRINTF("Received RST\n"); /* cancel possible subscriptions */ coap_remove_observer_by_mid(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, message->mid); } if((transaction = coap_get_transaction_by_mid(message->mid))) { /* free transaction memory before callback, as it may create a new transaction */ restful_response_handler callback = transaction->callback; void *callback_data = transaction->callback_data; coap_clear_transaction(transaction); /* check if someone registered for the response */ if(callback) { callback(callback_data, message); } } /* if(ACKed transaction) */ transaction = NULL; #if COAP_OBSERVE_CLIENT /* if observe notification */ if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON) && IS_OPTION(message, COAP_OPTION_OBSERVE)) { PRINTF("Observe [%u]\n", message->observe); coap_handle_notification(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, message); } #endif /* COAP_OBSERVE_CLIENT */ } /* request or response */ } else { /* parsed correctly */ NET_COAP_STAT(recv_err++); } /* if(parsed correctly) */ if(erbium_status_code == NO_ERROR) { if(transaction) { coap_send_transaction(transaction); } } else if(erbium_status_code == MANUAL_RESPONSE) { PRINTF("Clearing transaction for manual response"); coap_clear_transaction(transaction); } else { coap_message_type_t reply_type = COAP_TYPE_ACK; PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message); coap_clear_transaction(transaction); if(erbium_status_code == PING_RESPONSE) { erbium_status_code = 0; reply_type = COAP_TYPE_RST; } else if(erbium_status_code >= 192) { /* set to sendable error code */ erbium_status_code = INTERNAL_SERVER_ERROR_5_00; /* reuse input buffer for error message */ } coap_init_message(message, reply_type, erbium_status_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr, UIP_UDP_BUF(coap_ctx->buf)->srcport, uip_appdata(coap_ctx->buf), coap_serialize_message(message, uip_appdata(coap_ctx->buf))); } } /* if(new data) */ return erbium_status_code; }
/*-----------------------------------------------------------------------------------*/ static int handle_incoming_data(void) { int error = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen()); if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_packet_t message[1]; coap_transaction_t *transaction = NULL; error = coap_parse_message(message, uip_appdata, uip_datalen()); if (error==NO_ERROR) { /*TODO duplicates suppression, if required */ PRINTF(" Parsed: v %u, t %u, oc %u, c %u, tid %u\n", message->version, message->type, message->option_count, message->code, message->tid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); /* Handle requests. */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { /* Use transaction buffer for response to confirmable request. */ if ( (transaction = coap_new_transaction(message->tid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ if (message->type==COAP_TYPE_CON) { /* Reliable CON requests are answered with an ACK. */ coap_init_message(response, COAP_TYPE_ACK, OK_200, message->tid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, OK_200, coap_get_tid()); } /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { coap_set_header_token(response, message->token, message->token_len); SET_OPTION(response, COAP_OPTION_TOKEN); } /* get offset for blockwise transfers */ if (coap_get_header_block(message, &block_num, NULL, &block_size, &block_offset)) { PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /*------------------------------------------*/ /* call application-specific handler */ /*------------------------------------------*/ if (service_cbk) { service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset); } /*------------------------------------------*/ /* apply blockwise transfers */ if ( IS_OPTION(message, COAP_OPTION_BLOCK) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { response->code = BAD_REQUEST_400; coap_set_payload(response, (uint8_t*)"Block out of scope", 18); } else { coap_set_header_block(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if (valid offset) */ } else { /* resource provides chunk-wise data */ PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset); coap_set_header_block(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size); } /* if (resource aware of blockwise) */ } else if (new_offset!=0) { PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0) { error = PACKET_SERIALIZATION_ERROR; } } else { error = MEMORY_ALLOCATION_ERROR; } } else { /* Responses */ coap_transaction_t *t; if (message->type==COAP_TYPE_ACK) { PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { PRINTF(" Token 0x%02X%02X\n", message->token[0], message->token[1]); coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->token, message->token_len); } } if ( (t = coap_get_transaction_by_tid(message->tid)) ) { /* Free transaction memory before callback, as it may create a new transaction. */ restful_response_handler callback = t->callback; void *callback_data = t->callback_data; coap_clear_transaction(t); /* Check if someone registered for the response */ if (callback) { callback(callback_data, message); } } /* if (transaction) */ } } /* if (parsed correctly) */ if (error==NO_ERROR) { if (transaction) coap_send_transaction(transaction); } else { PRINTF("ERROR %u: %s\n", error, error_messages[error]); /* reuse input buffer */ coap_init_message(message, COAP_TYPE_ACK, INTERNAL_SERVER_ERROR_500, message->tid); coap_set_payload(message, (uint8_t *) error_messages[error], strlen(error_messages[error])); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return error; }
void coap_createCoapRequest(coap_method_t method, const char * uri, ContentType contentType, ObserveState observeState, const char * payload, int payloadLen, TransactionCallback callback, void * context) { coap_packet_t request; char path[MAX_COAP_PATH] = { 0 }; char query[128] = { 0 }; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(uri, strlen(uri)); coap_getPathQueryFromURI(uri, path, query); Lwm2m_Info("Coap request: %s\n", uri); //Lwm2m_Debug("Coap request path: %s\n", path); //Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); if (strlen(query) > 0) coap_set_header_uri_query(&request, query); // TODO - REVIEW: Erbium must copy path/query from request - else mem out of scope if (contentType != ContentType_None) { if ((method == COAP_POST) || (method == COAP_PUT)) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } else { coap_set_header_accept(&request, contentType); } } if (method == COAP_GET) { if (observeState == ObserveState_Establish) { coap_set_header_observe(&request, 0); int token = addObserve(remoteAddress, path, callback, context); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } else if (observeState == ObserveState_Cancel) { coap_set_header_observe(&request, 1); int token = removeObserve(remoteAddress, path); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(&CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } //if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) if ((transaction = coap_new_transaction(networkSocket, request.mid, remoteAddress))) { transaction->callback = coap_CoapRequestCallback; memcpy(CurrentTransaction[CurrentTransactionIndex].Path, path, MAX_COAP_PATH); CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; NetworkAddress_SetAddressType(remoteAddress, &CurrentTransaction[CurrentTransactionIndex].Address); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if (CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }
void http_get_task(void *pvParameters) { coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ int failures = 0; // create network socket struct addrinfo hints; struct addrinfo *res; // Use an UDP socket hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; // Get host/port from request URL // should call free(uri) somewhere coap_uri_t *uri = coap_new_uri((unsigned char*)URI, strlen(URI)); if (uri == NULL) { COAP_PRINTF("coap_new_uri(): URI failed\n"); vTaskDelete(NULL); } // DNS lookup int err; char port[6]; char host[32]; char path[64]; sprintf(port, "%d", uri->port); sprintf(path, "%s", uri->path.s); memcpy(host, uri->host.s, uri->host.length); host[uri->host.length] = '\0'; COAP_PRINTF("URI Path: %s\n", path); COAP_PRINTF("URI Host: %s\n", host); COAP_PRINTF("URI Port: %s\n", port); printf("Running DNS lookup for %s...\r\n", host); while (1) { err = getaddrinfo(host, port, &hints, &res); if (err == 0) break; freeaddrinfo(res); printf("DNS lookup failed err=%d res=%p\r\n", err, res); vTaskDelay(3000 / portTICK_RATE_MS); } /* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */ struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; char *ip = inet_ntoa(*addr); printf("DNS lookup succeeded. HOST=%s, IP=%s\r\n", host, ip); // init a HTTP POST message and set message header coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_set_header_uri_path(request, path); coap_set_header_uri_host(request, host); // Create a local socket int s = socket(res->ai_family, res->ai_socktype, 0); if(s < 0) { printf("... Failed to allocate socket.\r\n"); freeaddrinfo(res); vTaskDelete(NULL); } printf("... allocated socket\r\n"); int a; int ret; char payload[128]; struct request_state_t state[1]; ip_addr_t ipaddr; ipaddr.addr = ipaddr_addr(ip); while(1) { if(connect(s, res->ai_addr, res->ai_addrlen) != 0) { close(s); freeaddrinfo(res); printf("... socket connect failed.\r\n"); vTaskDelay(3000 / portTICK_RATE_MS); failures++; continue; } printf("... connected\r\n"); freeaddrinfo(res); repeat: vTaskDelay(5000 / portTICK_RATE_MS); // read sensor data from ESP8266 A0 a = sdk_system_adc_read(); sprintf(payload, "{ \"quality\": %d }\n", a); COAP_PRINTF("Payload: %s\n", payload); // CoAP payload coap_set_payload(request, payload, strlen(payload)); // Make CoAP transaction request->mid = coap_get_mid(); if ((state->transaction = coap_new_transaction(request->mid, &ipaddr, uri->port))) { state->transaction->callback = coap_blocking_request_callback; state->transaction->callback_data = state; if (state->block_num > 0) { coap_set_header_block2(request, state->block_num, 0, REST_MAX_CHUNK_SIZE); } // Build CoAP header and Options state->transaction->packet_len = coap_serialize_message(request, state->transaction->packet); COAP_PRINTF("Header dump: [0x%02X %02X %02X %02X]. Size: %d\n", request->buffer[0], request->buffer[1], request->buffer[2], request->buffer[3], state->transaction->packet_len ); COAP_PRINTF("Requested #%u (MID %u)\n", state->block_num, request->mid); // Transmit ret = write(s, state->transaction->packet, state->transaction->packet_len); //ret = sendto(s, state->transaction->packet, state->transaction->packet_len); if (ret < 0) { printf("[RET: %d] CoAP packet send failed.\n", ret); continue; } } else { COAP_PRINTF("Could not allocate transaction buffer"); } goto repeat; } }
/*---------------------------------------------------------------------------*/ int coap_receive(oc_message_t *msg) { erbium_status_code = NO_ERROR; LOG("\n\nCoAP Engine: received datalen=%u \n", (unsigned int) msg->length); /* static declaration reduces stack peaks and program code size */ static coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */ static coap_packet_t response[1]; static coap_transaction_t *transaction = NULL; erbium_status_code = coap_parse_message(message, msg->data, msg->length); if (erbium_status_code == NO_ERROR) { /*TODO duplicates suppression, if required by application */ #if DEBUG LOG(" Parsed: CoAP version: %u, token: 0x%02X%02X, mid: %u\n", message->version, message->token[0], message->token[1], message->mid); switch (message->type) { case COAP_TYPE_CON: LOG(" type: CON\n"); break; case COAP_TYPE_NON: LOG(" type: NON\n"); break; case COAP_TYPE_ACK: LOG(" type: ACK\n"); break; case COAP_TYPE_RST: LOG(" type: RST\n"); break; default: break; } #endif /* handle requests */ if (message->code >= COAP_GET && message->code <= COAP_DELETE) { #if DEBUG switch (message->code) { case COAP_GET: LOG(" method: GET\n"); break; case COAP_PUT: LOG(" method: PUT\n"); break; case COAP_POST: LOG(" method: POST\n"); break; case COAP_DELETE: LOG(" method: DELETE\n"); break; } LOG(" URL: %.*s\n", (int) message->uri_path_len, message->uri_path); LOG(" Payload: %.*s\n", (int) message->payload_len, message->payload); #endif /* use transaction buffer for response to confirmable request */ if ((transaction = coap_new_transaction(message->mid, &msg->endpoint))) { uint32_t block_num = 0; uint16_t block_size = COAP_MAX_BLOCK_SIZE; uint32_t block_offset = 0; int32_t new_offset = 0; /* prepare response */ if (message->type == COAP_TYPE_CON) { /* reliable CON requests are answered with an ACK */ coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* unreliable NON requests are answered with a NON as well */ coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid()); /* mirror token */ } if (message->token_len) { coap_set_token(response, message->token, message->token_len); /* get offset for blockwise transfers */ } if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset)) { LOG("\tBlockwise: block request %u (%u/%u) @ %u bytes\n", (unsigned int) block_num, block_size, COAP_MAX_BLOCK_SIZE, (unsigned int) block_offset); block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE); new_offset = block_offset; } /* invoke resource handler in RI layer */ if (oc_ri_invoke_coap_entity_handler( message, response, transaction->message->data + COAP_MAX_HEADER_SIZE, block_size, &new_offset, &msg->endpoint)) { if (erbium_status_code == NO_ERROR) { /* TODO coap_handle_blockwise(request, response, start_offset, * end_offset); */ /* resource is unaware of Block1 */ if (IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code < BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1)) { LOG("\tBlock1 option NOT IMPLEMENTED\n"); erbium_status_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; /* client requested Block2 transfer */ } else if (IS_OPTION(message, COAP_OPTION_BLOCK2)) { /* unchanged new_offset indicates that resource is unaware of * blockwise transfer */ if (new_offset == block_offset) { LOG("\tBlockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("\t\t: block_offset >= response->payload_len\n"); response->code = BAD_OPTION_4_02; coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ } else { coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); coap_set_payload( response, response->payload + block_offset, MIN(response->payload_len - block_offset, block_size)); } /* if(valid offset) */ /* resource provides chunk-wise data */ } else { LOG("\tBlockwise: blockwise resource, new offset %d\n", (int) new_offset); coap_set_header_block2(response, block_num, new_offset != -1 || response->payload_len > block_size, block_size); if (response->payload_len > block_size) { coap_set_payload(response, response->payload, block_size); } } /* if(resource aware of blockwise) */ /* Resource requested Block2 transfer */ } else if (new_offset != 0) { LOG("\tBlockwise: no block option for blockwise resource, using " "block size %u\n", COAP_MAX_BLOCK_SIZE); coap_set_header_block2(response, 0, new_offset != -1, COAP_MAX_BLOCK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, COAP_MAX_BLOCK_SIZE)); } /* blockwise transfer handling */ } /* no errors/hooks */ /* successful service callback */ /* serialize response */ } if (erbium_status_code == NO_ERROR) { if ((transaction->message->length = coap_serialize_message( response, transaction->message->data)) == 0) { erbium_status_code = PACKET_SERIALIZATION_ERROR; } } } else { erbium_status_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if(transaction buffer) */ /* handle responses */ } else { // Fix this if (message->type == COAP_TYPE_CON) { erbium_status_code = EMPTY_ACK_RESPONSE; } else if (message->type == COAP_TYPE_ACK) { /* transactions are closed through lookup below */ } else if (message->type == COAP_TYPE_RST) { #ifdef OC_SERVER /* cancel possible subscriptions */ coap_remove_observer_by_mid(&msg->endpoint, message->mid); #endif } /* Open transaction now cleared for ACK since mid matches */ if ((transaction = coap_get_transaction_by_mid(message->mid))) { coap_clear_transaction(transaction); } /* if(ACKed transaction) */ transaction = NULL; #ifdef OC_CLIENT // ACKs and RSTs sent to oc_ri.. RSTs cleared, ACKs sent to // client oc_ri_invoke_client_cb(message, &msg->endpoint); #endif } /* request or response */ } /* parsed correctly */ /* if(parsed correctly) */ if (erbium_status_code == NO_ERROR) { if (transaction) { // Server transactions sent from here coap_send_transaction(transaction); } } else if (erbium_status_code == CLEAR_TRANSACTION) { LOG("Clearing transaction for manual response"); coap_clear_transaction(transaction); // used in server for separate response } #ifdef OC_CLIENT else if (erbium_status_code == EMPTY_ACK_RESPONSE) { coap_init_message(message, COAP_TYPE_ACK, 0, message->mid); oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); response->length = coap_serialize_message(message, response->data); coap_send_message(response); } } #endif /* OC_CLIENT */ #ifdef OC_SERVER else { // framework errors handled here coap_message_type_t reply_type = COAP_TYPE_RST; coap_clear_transaction(transaction); coap_init_message(message, reply_type, SERVICE_UNAVAILABLE_5_03, message->mid); oc_message_t *response = oc_allocate_message(); if (response) { memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint)); response->length = coap_serialize_message(message, response->data); coap_send_message(response); } } #endif /* OC_SERVER */ /* if(new data) */ return erbium_status_code; }