coap_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi) { coap_opt_filter_t f; memset(f, 0, sizeof(coap_opt_filter_t)); coap_option_setb(f, type); coap_option_iterator_init(pdu, oi, f); coap_option_next(oi); return oi->option && oi->type == type ? oi->option : NULL; }
/* handler for TD_COAP_CORE_16 */ void hnd_get_separate(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_opt_filter_t f; unsigned long delay = 5; (void)resource; (void)token; if (async) { if (async->id != request->hdr->id) { coap_opt_filter_t f; coap_option_filter_clear(f); response->hdr->code = COAP_RESPONSE_CODE(503); } return; } /* search for option delay in query list */ coap_option_filter_clear(f); coap_option_setb(f, COAP_OPTION_URI_QUERY); coap_option_iterator_init(request, &opt_iter, f); while ((option = coap_option_next(&opt_iter))) { if (strncmp("delay=", (char *)COAP_OPT_VALUE(option), 6) == 0) { int i; unsigned long d = 0; for (i = 6; i < COAP_OPT_LENGTH(option); ++i) d = d * 10 + COAP_OPT_VALUE(option)[i] - '0'; /* don't allow delay to be less than COAP_RESOURCE_CHECK_TIME*/ delay = d < COAP_RESOURCE_CHECK_TIME_SEC ? COAP_RESOURCE_CHECK_TIME_SEC : d; debug("set delay to %lu\n", delay); break; } } async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE, (void *)(COAP_TICKS_PER_SECOND * delay)); }
uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter) { OIC_LOG(DEBUG, TAG, "IN"); uint32_t count = 0; coap_opt_t *option; while ((option = coap_option_next(&opt_iter))) { if (COAP_OPTION_URI_PATH != opt_iter.type && COAP_OPTION_URI_QUERY != opt_iter.type && COAP_OPTION_BLOCK1 != opt_iter.type && COAP_OPTION_BLOCK2 != opt_iter.type && COAP_OPTION_SIZE1 != opt_iter.type && COAP_OPTION_SIZE2 != opt_iter.type && COAP_OPTION_CONTENT_FORMAT != opt_iter.type) { count++; } } OIC_LOG(DEBUG, TAG, "OUT"); return count; }
void hnd_get_query(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_filter_t f; coap_opt_t *q; size_t len, L; unsigned char buf[70]; (void)ctx; (void)resource; (void)peer; (void)token; response->hdr->code = COAP_RESPONSE_CODE(205); coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); coap_option_filter_clear(f); coap_option_setb(f, COAP_OPTION_URI_QUERY); coap_option_iterator_init(request, &opt_iter, f); len = 0; while ((len < sizeof(buf)) && (q = coap_option_next(&opt_iter))) { L = min(sizeof(buf) - len, 11); memcpy(buf + len, "Uri-Query: ", L); len += L; L = min(sizeof(buf) - len, COAP_OPT_LENGTH(q)); memcpy(buf + len, COAP_OPT_VALUE(q), L); len += L; if (len < sizeof(buf)) buf[len++] = '\n'; } coap_add_data(response, len, buf); }
// 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; } }
CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo) { OIC_LOG(DEBUG, TAG, "IN"); if (!pdu || !outCode || !outInfo) { OIC_LOG(ERROR, TAG, "NULL pointer param"); return CA_STATUS_INVALID_PARAM; } coap_opt_iterator_t opt_iter; coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL); if (outCode) { (*outCode) = (uint32_t) CA_RESPONSE_CODE(pdu->hdr->code); } // init HeaderOption list uint32_t count = CAGetOptionCount(opt_iter); memset(outInfo, 0, sizeof(*outInfo)); outInfo->numOptions = count; // set type outInfo->type = pdu->hdr->type; // set message id outInfo->messageId = pdu->hdr->id; outInfo->payloadFormat = CA_FORMAT_UNDEFINED; if (count > 0) { outInfo->options = (CAHeaderOption_t *) OICCalloc(count, sizeof(CAHeaderOption_t)); if (NULL == outInfo->options) { OIC_LOG(ERROR, TAG, "Out of memory"); return CA_MEMORY_ALLOC_FAILED; } } coap_opt_t *option; char optionResult[CA_MAX_URI_LENGTH] = {0}; uint32_t idx = 0; uint32_t optionLength = 0; bool isfirstsetflag = false; bool isQueryBeingProcessed = false; while ((option = coap_option_next(&opt_iter))) { char buf[COAP_MAX_PDU_SIZE] = {0}; uint32_t bufLength = CAGetOptionData(opt_iter.type, (uint8_t *)(COAP_OPT_VALUE(option)), COAP_OPT_LENGTH(option), (uint8_t *)buf, sizeof(buf)); if (bufLength) { OIC_LOG_V(DEBUG, TAG, "COAP URI element : %s", buf); if (COAP_OPTION_URI_PATH == opt_iter.type || COAP_OPTION_URI_QUERY == opt_iter.type) { if (false == isfirstsetflag) { isfirstsetflag = true; optionResult[optionLength] = '/'; optionLength++; // Make sure there is enough room in the optionResult buffer if ((optionLength + bufLength) < sizeof(optionResult)) { memcpy(&optionResult[optionLength], buf, bufLength); optionLength += bufLength; } else { goto exit; } } else { if (COAP_OPTION_URI_PATH == opt_iter.type) { // Make sure there is enough room in the optionResult buffer if (optionLength < sizeof(optionResult)) { optionResult[optionLength] = '/'; optionLength++; } else { goto exit; } } else if (COAP_OPTION_URI_QUERY == opt_iter.type) { if (false == isQueryBeingProcessed) { // Make sure there is enough room in the optionResult buffer if (optionLength < sizeof(optionResult)) { optionResult[optionLength] = '?'; optionLength++; isQueryBeingProcessed = true; } else { goto exit; } } else { // Make sure there is enough room in the optionResult buffer if (optionLength < sizeof(optionResult)) { optionResult[optionLength] = ';'; optionLength++; } else { goto exit; } } } // Make sure there is enough room in the optionResult buffer if ((optionLength + bufLength) < sizeof(optionResult)) { memcpy(&optionResult[optionLength], buf, bufLength); optionLength += bufLength; } else { goto exit; } } } else if (COAP_OPTION_BLOCK1 == opt_iter.type || COAP_OPTION_BLOCK2 == opt_iter.type || COAP_OPTION_SIZE1 == opt_iter.type || COAP_OPTION_SIZE2 == opt_iter.type) { OIC_LOG_V(DEBUG, TAG, "option[%d] will be filtering", opt_iter.type); } else if (COAP_OPTION_CONTENT_FORMAT == opt_iter.type) { if (1 == COAP_OPT_LENGTH(option) && COAP_MEDIATYPE_APPLICATION_CBOR == buf[0]) { outInfo->payloadFormat = CA_FORMAT_CBOR; } else { outInfo->payloadFormat = CA_FORMAT_UNSUPPORTED; } OIC_LOG_V(DEBUG, TAG, "option[%d] has format [%d]", opt_iter.type, (uint8_t)buf[0]); } else { if (idx < count) { uint32_t length = bufLength; if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH) { outInfo->options[idx].optionID = opt_iter.type; outInfo->options[idx].optionLength = length; outInfo->options[idx].protocolID = CA_COAP_ID; memcpy(outInfo->options[idx].optionData, buf, length); idx++; } } } } } // set token data if (pdu->hdr->token_length > 0) { OIC_LOG_V(DEBUG, TAG, "inside token length : %d", pdu->hdr->token_length); outInfo->token = (char *) OICMalloc(pdu->hdr->token_length); if (NULL == outInfo->token) { OIC_LOG(ERROR, TAG, "Out of memory"); OICFree(outInfo->options); return CA_MEMORY_ALLOC_FAILED; } memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length); } outInfo->tokenLength = pdu->hdr->token_length; // set payload data size_t dataSize; uint8_t *data; if (coap_get_data(pdu, &dataSize, &data)) { OIC_LOG(DEBUG, TAG, "inside pdu->data"); outInfo->payload = (uint8_t *) OICMalloc(dataSize); if (NULL == outInfo->payload) { OIC_LOG(ERROR, TAG, "Out of memory"); OICFree(outInfo->options); OICFree(outInfo->token); return CA_MEMORY_ALLOC_FAILED; } memcpy(outInfo->payload, pdu->data, dataSize); outInfo->payloadSize = dataSize; } if (optionResult[0] != '\0') { OIC_LOG_V(DEBUG, TAG, "URL length:%d", strlen(optionResult)); outInfo->resourceUri = OICStrdup(optionResult); if (!outInfo->resourceUri) { OIC_LOG(ERROR, TAG, "Out of memory"); OICFree(outInfo->options); OICFree(outInfo->token); return CA_MEMORY_ALLOC_FAILED; } } OIC_LOG(DEBUG, TAG, "OUT"); return CA_STATUS_OK; exit: OIC_LOG(ERROR, TAG, "buffer too small"); OICFree(outInfo->options); return CA_STATUS_FAILED; }
void CAGetRequestPDUInfo(const coap_pdu_t *pdu, uint32_t* outCode, CAInfo_t* outInfo) { unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */ uint32_t encode = 0; coap_opt_iterator_t opt_iter; coap_opt_t *option; char optionResult[CA_URI_MAX_SIZE] = { 0, }; uint32_t count = 0; uint32_t isfirstsetflag = 0; /* show options, if any */ coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL); memset(optionResult, 0, sizeof(optionResult)); while ((option = coap_option_next(&opt_iter))) { if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf), encode)) { if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) { if (0 == isfirstsetflag) { isfirstsetflag = 1; memcpy(optionResult + count, buf, strlen(buf)); count += strlen(buf); } else { if (opt_iter.type == COAP_OPTION_URI_PATH) { memcpy(optionResult + count, "/", 1); count++; } else if (opt_iter.type == COAP_OPTION_URI_QUERY) { memcpy(optionResult + count, "?", 1); count++; } memcpy(optionResult + count, buf, strlen(buf)); count += strlen(buf); } } } } OIC_LOG(DEBUG, TAG, "set CAInfo_t after parsing"); // set pdu info (*outCode) = (uint32_t) pdu->hdr->code; memset(outInfo, 0, sizeof(CAInfo_t)); outInfo->options = (CAHeaderOption_t*) OICMalloc(sizeof(CAHeaderOption_t)); memset(outInfo->options, 0, sizeof(CAHeaderOption_t)); outInfo->options->optionID = opt_iter.type; outInfo->options->optionLength = count; memcpy(outInfo->options->optionData, optionResult, CA_MAX_HEADER_OPTION_DATA_LENGTH); if (pdu->hdr->token_length > 0) { outInfo->token = (char*) OICMalloc(pdu->hdr->token_length); memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length); } if (NULL != pdu->data) { outInfo->payload = (char*) OICMalloc(strlen(pdu->data) + 1); memcpy(outInfo->payload, pdu->data, strlen(pdu->data) + 1); } }