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_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_pretty_print(coap_pdu *pdu) { coap_option opt; opt.num = 0; if (coap_validate_pkt(pdu) == CE_NONE){ printf(" ------ Valid CoAP Packet (%zi) ------ \n", pdu->len); printf("Type: %i\n",coap_get_type(pdu)); printf("Code: %i.%02i\n", coap_get_code_class(pdu), coap_get_code_detail(pdu)); printf("MID: 0x%X\n", coap_get_mid(pdu)); printf("Token: 0x%llX\n", coap_get_token(pdu)); while ((opt = coap_get_option(pdu, &opt)).num != 0){ if (opt.num == 0) break; printf("Option: %i\n", opt.num); if (opt.val != NULL && opt.len != 0) printf(" Value: %.*s (%zi)\n", (int)opt.len, opt.val, opt.len); } // Note: get_option returns payload pointer when it finds the payload marker if (opt.val != NULL && opt.len != 0) printf("Payload: %.*s (%zi)\n", (int)opt.len, opt.val, opt.len); } else { printf(" ------ Non-CoAP Message (%zi) ------ \n", pdu->len); hex_dump(pdu->buf, pdu->len); } }
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(); 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(); }
/*----------------------------------------------------------------------------*/ 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(); }
/*-----------------------------------------------------------------------------------*/ 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); } } } }
/** * \brief Initiate a separate response with an empty ACK * \param request The request to accept * \param separate_store A pointer to the data structure that will store the * relevant information for the response * * When the server does not have enough resources left to store the information * for a separate response or otherwise cannot execute the resource handler, * this function will respond with 5.03 Service Unavailable. The client can * then retry later. */ void coap_separate_accept(void *request, coap_separate_t *separate_store) { coap_packet_t *const coap_req = (coap_packet_t *)request; coap_transaction_t *const t = coap_get_transaction_by_mid(coap_req->mid); PRINTF("Separate ACCEPT: /%.*s MID %u\n", coap_req->uri_path_len, coap_req->uri_path, coap_req->mid); if(t) { /* send separate ACK for CON */ if(coap_req->type == COAP_TYPE_CON) { coap_packet_t ack[1]; /* ACK with empty code (0) */ coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid); /* serializing into IPBUF: Only overwrites header parts that are already parsed into the request struct */ coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, (uip_appdata), coap_serialize_message(ack, uip_appdata)); } /* store remote address */ uip_ipaddr_copy(&separate_store->addr, &t->addr); separate_store->port = t->port; /* store correct response type */ separate_store->type = coap_req->type == COAP_TYPE_CON ? COAP_TYPE_CON : COAP_TYPE_NON; separate_store->mid = coap_get_mid(); /* if it was a NON, we burned one MID in the engine... */ memcpy(separate_store->token, coap_req->token, coap_req->token_len); separate_store->token_len = coap_req->token_len; separate_store->block1_num = coap_req->block1_num; separate_store->block1_size = coap_req->block1_size; separate_store->block2_num = coap_req->block2_num; separate_store->block2_size = coap_req->block2_size > 0 ? MIN(COAP_MAX_BLOCK_SIZE, coap_req->block2_size) : COAP_MAX_BLOCK_SIZE; /* signal the engine to skip automatic response and clear transaction by engine */ erbium_status_code = MANUAL_RESPONSE; } else { PRINTF("ERROR: Response transaction for separate request not found!\n"); erbium_status_code = INTERNAL_SERVER_ERROR_5_00; } }
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; } }
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 main(void) { char alias[] = "temp"; char cik[] = "a32c85ba9dda45823be416246cf8b433baa068d7"; char host[] = "coap.exosite.com"; char port[] = "5683"; srand(time(NULL)); // CoAP Message Setup #define MSG_BUF_LEN 64 uint8_t msg_send_buf[MSG_BUF_LEN]; coap_pdu msg_send = {msg_send_buf, 0, 64}; uint8_t msg_recv_buf[MSG_BUF_LEN]; coap_pdu msg_recv = {msg_recv_buf, 0, 64}; uint16_t message_id_counter = rand(); // Socket to Exosite int remotesock; size_t bytes_sent; ssize_t bytes_recv; int rv; struct addrinfo exohints, *servinfo, *q; memset(&exohints, 0, sizeof exohints); exohints.ai_family = AF_UNSPEC; exohints.ai_socktype = SOCK_DGRAM; exohints.ai_flags = AI_PASSIVE; if ((rv = getaddrinfo(host, port, &exohints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and make a socket for(q = servinfo; q != NULL; q = q->ai_next) { if ((remotesock = socket(q->ai_family, q->ai_socktype, q->ai_protocol)) == -1) { perror("bad socket"); continue; } break; } if (q == NULL) { fprintf(stderr, "Failed to Bind Socket\n"); return 2; } for (;;) { printf("--------------------------------------------------------------------------------\n"); // Build Message coap_init_pdu(&msg_send); //memset(msg_send, 0, msg_send_len); coap_set_version(&msg_send, COAP_V1); coap_set_type(&msg_send, CT_CON); coap_set_code(&msg_send, CC_GET); // or POST to write coap_set_mid(&msg_send, message_id_counter++); coap_set_token(&msg_send, rand(), 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)"1a", 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)alias, strlen(alias)); coap_add_option(&msg_send, CON_URI_QUERY, (uint8_t*)cik, strlen(cik)); // to write, set payload: //coap_set_payload(msg_send, &msg_send_len, MSG_BUF_LEN, (uint8_t*)"99", 2); // Send Message if ((bytes_sent = sendto(remotesock, msg_send.buf, msg_send.len, 0, q->ai_addr, q->ai_addrlen)) == -1){ fprintf(stderr, "Failed to Send Message\n"); return 2; } printf("Sent.\n"); coap_pretty_print(&msg_send); // Wait for Response bytes_recv = recvfrom(remotesock, (void *)msg_recv.buf, msg_recv.max, 0, q->ai_addr, &q->ai_addrlen); if (bytes_recv < 0) { fprintf(stderr, "%s\n", strerror(errno)); exit(EXIT_FAILURE); } msg_recv.len = bytes_recv; if(coap_validate_pkt(&msg_recv) == CE_NONE) { printf("Got Valid CoAP Packet\n"); if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) && coap_get_token(&msg_recv) == coap_get_token(&msg_send)) { printf("Is Response to Last Message\n"); coap_pretty_print(&msg_recv); } }else{ printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len); hex_dump(msg_recv.buf, msg_recv.len); } sleep(1); // One Second } }
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; } } }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { coap_status_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (coap_error_code==NO_ERROR) { LOG(" Parsed: ver %u, type %u, tkl %u, code %u, mid %u\r\n", message->version, message->type, message->token_len, message->code, message->mid); LOG(" Payload: %.*s\r\n\n", message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { 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_header_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("Blockwise: block request %u (%u/%u) @ %u 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; } coap_error_code = handle_request(contextP, fromSessionH, message, response); 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) ) { LOG("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) { LOG("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("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 */ LOG("Blockwise: blockwise resource, new offset %d\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) { LOG("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) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(response->payload); response->payload = NULL; response->payload_len = 0; } else { coap_error_code = message_send(contextP, response, fromSessionH); } } else { /* Responses */ lwm2m_transaction_t * transaction; if (message->type==COAP_TYPE_ACK) { LOG("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { LOG("Received RST\n"); /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); } #ifdef LWM2M_SERVER_MODE if (message->code == COAP_204_CHANGED && IS_OPTION(message, COAP_OPTION_OBSERVE)) { handle_observe_notify(contextP, fromSessionH, message); } else #endif { transaction_handle_response(contextP, fromSessionH, message); } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */ else { LOG("Message parsing failed %d\r\n", coap_error_code); } if (coap_error_code != NO_ERROR) { LOG("ERROR %u: %s\n", coap_error_code, coap_error_message); /* 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)); message_send(contextP, message, fromSessionH); } }
/*---------------------------------------------------------------------------*/ 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; }
void ICACHE_FLASH_ATTR coap_send(void *pvParameters) //int coap_send(void) { char *url = "coap.me"; int port = 5683; uint16_t message_id_counter = rand(); printf("%d,%d",message_id_counter, port); int sock; int bytes_sent; int bytes_recv; struct hostent *host; struct sockaddr_in server_addr; /* 通过函数入口参数url获得host地址*/ host= (struct hostent *) gethostbyname(url); printf("here"); /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { printf("Socket Error\n"); } printf("here2"); /* 初始化预连接的服务端地址 */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr = *((struct in_addr *)host->h_addr); memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); printf("--------------------\r\n"); // Build Message coap_init_pdu(&msg_send); //memset(msg_send, 0, msg_send_len); coap_set_version(&msg_send, COAP_V1); coap_set_type(&msg_send, CT_CON); coap_set_code(&msg_send, CC_GET); // or POST to write coap_set_mid(&msg_send, message_id_counter++); // coap_set_token(&msg_send, rand(), 2); coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)"hello", strlen("hello")); // coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)alias, strlen(alias)); // coap_add_option(&msg_send, CON_URI_QUERY, (uint8_t*)cik, strlen(cik)); // to write, set payload: //coap_set_payload(msg_send, &msg_send_len, MSG_BUF_LEN, (uint8_t*)"99", 2); // Send Message if ((bytes_sent = sendto(sock, msg_send.buf, msg_send.len, 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1) { printf("Failed to Send Message\r\n"); } else{ printf("bytes %d\n",bytes_sent); } socklen_t len = sizeof(server_addr); bytes_recv = recvfrom(sock, (void *)msg_recv.buf, msg_recv.max, 0, (struct sockaddr *)&server_addr,&len); if (bytes_recv < 0) { printf("game over baby\n"); } else{ printf("yuhu\n"); } msg_recv.len = bytes_recv; if(coap_validate_pkt(&msg_recv) == CE_NONE) { printf("Got Valid CoAP Packet\n"); if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) && coap_get_token(&msg_recv) == coap_get_token(&msg_send)) { printf("Is Response to Last Message\n"); coap_pretty_print(&msg_recv); } }else{ printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len); } vTaskDelete(NULL); }
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; } }
// server CB int request1 (void* transaction_, void* data) { #if COAP_CEU CEU_Transaction* transaction = (CEU_Transaction*) transaction_; #else coap_transaction_t* transaction = (coap_transaction_t*) transaction_; #endif /* Use transaction buffer for response to confirmable request. */ 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_header_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", 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) */ return coap_error_code; }
/*---------------------------------------------------------------------------*/ 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; }