coap_list_t *CACreateNewOptionNode(uint16_t key, uint32_t length, const char *data) { OIC_LOG(DEBUG, TAG, "IN"); if (!data) { OIC_LOG(ERROR, TAG, "invalid pointer parameter"); return NULL; } coap_option *option = coap_malloc(sizeof(coap_option) + length + 1); if (!option) { OIC_LOG(ERROR, TAG, "Out of memory"); return NULL; } memset(option, 0, sizeof(coap_option) + length + 1); COAP_OPTION_KEY(*option) = key; coap_option_def_t* def = coap_opt_def(key); if (NULL != def && coap_is_var_bytes(def)) { if (length > def->max) { // make sure we shrink the value so it fits the coap option definition // by truncating the value, disregard the leading bytes. OIC_LOG_V(DEBUG, TAG, "Option [%d] data size [%d] shrunk to [%d]", def->key, length, def->max); data = &(data[length-def->max]); length = def->max; } // Shrink the encoding length to a minimum size for coap // options that support variable length encoding. COAP_OPTION_LENGTH(*option) = coap_encode_var_bytes( COAP_OPTION_DATA(*option), coap_decode_var_bytes((unsigned char *)data, length)); } else { COAP_OPTION_LENGTH(*option) = length; memcpy(COAP_OPTION_DATA(*option), data, length); } /* we can pass NULL here as delete function since option is released automatically */ coap_list_t *node = coap_new_listnode(option, NULL); if (!node) { OIC_LOG(ERROR, TAG, "node is NULL"); coap_free(option); return NULL; } OIC_LOG(DEBUG, TAG, "OUT"); return node; }
void hnd_put_test(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response) { coap_opt_iterator_t opt_iter; coap_opt_t *option; coap_payload_t *payload; size_t len; unsigned char *data; (void)ctx; (void)peer; (void)token; response->hdr->code = COAP_RESPONSE_CODE(204); coap_get_data(request, &len, &data); payload = coap_find_payload(resource->key); if (payload && payload->max_data < len) { /* need more storage */ coap_delete_payload(payload); payload = NULL; /* bug: when subsequent coap_new_payload() fails, our old contents is gone */ } if (!payload) { /* create new payload */ payload = coap_new_payload(len); if (!payload) goto error; coap_add_payload(resource->key, payload, NULL); } payload->length = len; memcpy(payload->data, data, len); option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter); if (option) { /* set media type given in request */ payload->media_type = coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)); } else { /* set default value */ payload->media_type = COAP_MEDIATYPE_TEXT_PLAIN; } /* FIXME: need to change attribute ct of resource. To do so, we need dynamic management of the attribute value */ return; error: warn("cannot modify resource\n"); response->hdr->code = COAP_RESPONSE_CODE(500); }
// When we receive the CoAP response we build and send the HTTP response void coap_response_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) { printf("COAP %13s:%-5u -> ", inet_ntoa((&remote->addr.sin)->sin_addr), ntohs((&remote->addr.sin)->sin_port)); coap_show_pdu(received); for(int i = 0; i < MAX_HTTP_CONNECTIONS; i++) { if(http_coap_pairs[i].message_id == received->hdr->id) { struct MHD_Connection *connection = http_coap_pairs[i].connection; size_t len = 0; unsigned char *databuf = NULL; struct MHD_Response *response = MHD_create_response_from_buffer(len, databuf, MHD_RESPMEM_MUST_COPY); int read_result = coap_get_data(received, &len, &databuf); if(received->hdr->code == COAP_RESPONSE_CODE(205) && read_result == 0) { coap_abort_to_http(connection, "coap_get_data: cannot read CoAP response data\n"); } static char tid_str[8]; snprintf(tid_str, sizeof(tid_str), "%u", ntohs(received->hdr->id)); MHD_add_response_header(response, "X-CoAP-Message-Id", tid_str); MHD_add_response_header(response, "X-CoAP-Response-Code", msg_code_string(received->hdr->code)); // HTTP Content-Type const char *http_content_type; int coap_content_format; coap_opt_iterator_t opt_iter; coap_opt_t *option; coap_option_iterator_init(received, &opt_iter, COAP_OPT_ALL); while((option = coap_option_next(&opt_iter))) { switch(opt_iter.type) { case COAP_OPTION_CONTENT_FORMAT: coap_content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)); break; default: continue; } } switch(coap_content_format) { case COAP_MEDIATYPE_TEXT_PLAIN: http_content_type = "text/plain"; break; case COAP_MEDIATYPE_APPLICATION_LINK_FORMAT: http_content_type = "application/link-format"; break; case COAP_MEDIATYPE_APPLICATION_XML: http_content_type = "application/xml"; break; case COAP_MEDIATYPE_APPLICATION_OCTET_STREAM: http_content_type = "application/octet-stream"; break; case COAP_MEDIATYPE_APPLICATION_EXI: http_content_type = "application/exi"; break; case COAP_MEDIATYPE_APPLICATION_JSON: http_content_type = "application/json"; break; case COAP_MEDIATYPE_APPLICATION_CBOR: http_content_type = "application/cbor"; break; default: http_content_type = "unknown"; break; } MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, http_content_type); // HTTP Code unsigned int http_code; switch(received->hdr->code) { case COAP_RESPONSE_200: http_code = MHD_HTTP_NO_CONTENT; break; /* 2.00 OK */ case COAP_RESPONSE_201: http_code = MHD_HTTP_CREATED; break; /* 2.01 Created */ case COAP_RESPONSE_CODE(205): http_code = MHD_HTTP_OK; break; case COAP_RESPONSE_304: http_code = MHD_HTTP_ACCEPTED; break; /* 2.03 Valid */ case COAP_RESPONSE_400: http_code = MHD_HTTP_BAD_REQUEST; break; /* 4.00 Bad Request */ case COAP_RESPONSE_404: http_code = MHD_HTTP_NOT_FOUND; break; /* 4.04 Not Found */ case COAP_RESPONSE_405: http_code = MHD_HTTP_NOT_ACCEPTABLE; break; /* 4.05 Method Not Allowed */ case COAP_RESPONSE_415: http_code = MHD_HTTP_UNSUPPORTED_MEDIA_TYPE;break; /* 4.15 Unsupported Media Type */ case COAP_RESPONSE_500: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; /* 5.00 Internal Server Error */ case COAP_RESPONSE_501: http_code = MHD_HTTP_NOT_IMPLEMENTED; break; /* 5.01 Not Implemented */ case COAP_RESPONSE_503: http_code = MHD_HTTP_SERVICE_UNAVAILABLE; break; /* 5.03 Service Unavailable */ case COAP_RESPONSE_504: http_code = MHD_HTTP_GATEWAY_TIMEOUT; break; /* 5.04 Gateway Timeout */ default: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; } // Send the response MHD_queue_response(connection, http_code, response); MHD_destroy_response(response); const struct sockaddr_in *client_addr = (const struct sockaddr_in *) MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr; printf("HTTP %13s:%-5u <- %u %s [ %s, %zu bytes, \"%s\" ]\n", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port), http_code, http_reason_phrase_for(http_code), http_content_type, len, (databuf != NULL) ? (char *)databuf : ""); } // clear the association http_coap_pairs[i].connection = NULL; return; } }
void hnd_post_test(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer, coap_pdu_t *request, str *token, coap_pdu_t *response) { coap_opt_iterator_t opt_iter; coap_opt_t *option; coap_payload_t *test_payload; size_t len; size_t l = 6 + sizeof(void *); coap_dynamic_uri_t *uri; unsigned char *data; #define BUFSIZE 20 int res; unsigned char _buf[BUFSIZE]; unsigned char *buf = _buf; size_t buflen = BUFSIZE; (void)resource; (void)peer; (void)token; coap_get_data(request, &len, &data); /* allocate storage for resource and to hold URI */ test_payload = coap_new_payload(len); uri = (coap_dynamic_uri_t *)coap_malloc(sizeof(coap_dynamic_uri_t) + l); if (!(test_payload && uri)) { coap_log(LOG_CRIT, "cannot allocate new resource under /test"); response->hdr->code = COAP_RESPONSE_CODE(500); coap_free(test_payload); coap_free(uri); } else { coap_resource_t *r; memset(uri, 0, sizeof(coap_dynamic_uri_t)); uri->length = min(l, (size_t)snprintf((char *)uri->data, l, "test/%p", (void*)test_payload)); test_payload->length = len; memcpy(test_payload->data, data, len); r = coap_resource_init(uri->data, uri->length, 0); coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource); coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_resource); /* set media_type if available */ option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter); if (option) { test_payload->media_type = coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)); } coap_add_resource(ctx, r); coap_add_payload(r->key, test_payload, uri); /* add Location-Path */ res = coap_split_path(uri->data, uri->length, buf, &buflen); while (res--) { coap_add_option(response, COAP_OPTION_LOCATION_PATH, COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf)); buf += COAP_OPT_SIZE(buf); } response->hdr->code = COAP_RESPONSE_CODE(201); } }