mbed 5.4 with sleep mode
Diff: Coap/coap_client.c
- Revision:
- 34:d6ce8f961b8b
diff -r e27f40fada64 -r d6ce8f961b8b Coap/coap_client.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coap/coap_client.c Fri Mar 24 05:42:34 2017 +0000 @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2015 Keith Cullen. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file coap_client.c + * + * @brief Source file for the FreeCoAP client library + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> + +#include "coap_client.h" +#include "main.h" + +#define COAP_CLIENT_ACK_TIMEOUT_SEC 2 /**< Minimum delay to wait before retransmitting a confirmable message */ +#define COAP_CLIENT_MAX_RETRANSMIT 4 /**< Maximum number of times a confirmable message can be retransmitted */ +#define COAP_CLIENT_RESP_TIMEOUT_SEC 30 /**< Maximum amount of time to wait for a response */ + +/**************************************************************************************************** + * coap_client * + ****************************************************************************************************/ + +int coap_client_create(coap_client_t *client, + const char *host, + const char *port) +{ + strncpy(client->server_host, host, sizeof(client->server_host) - 1); + strncpy(client->server_port, port, sizeof(client->server_port) - 1); + + printf("Connected to host %s and port %s", client->server_host, client->server_port); + return 0; +} + +void coap_client_destroy(coap_client_t *client) +{ + memset(client, 0, sizeof(coap_client_t)); +} + +/** + * @brief Send a message to the server + * + * @param[in,out] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Number of bytes sent or error code + * @retval >0 Number of bytes sent + * @retval <0 Error + */ +static int coap_client_send(coap_client_t *client, coap_msg_t *msg) +{ + int num = 0; + char buf[COAP_MSG_MAX_BUF_LEN] = {0}; + + num = coap_msg_format(msg, buf, sizeof(buf)); + if (num < 0) + { + return num; + } + num = send(client->sd, buf, num); + if (num < 0) + { + printf("send error\n"); + return -errno; + } + + printf("Sent to host %s and port %s\n", client->server_host, client->server_port); + return num; +} + +/** + * @brief Handle a format error in a received message + * + * Special handling for the case where a received + * message could not be parsed due to a format error. + * Extract enough information from the received message + * to form a reset message. + * + * @param[in,out] client Pointer to a client structure + * @param[in] buf Buffer containing the message + * @param[in] len length of the buffer + */ +static void coap_client_handle_format_error(coap_client_t *client, char *buf, size_t len) +{ + coap_msg_t msg = {0}; + unsigned msg_id = 0; + unsigned type = 0; + int ret = 0; + + ret = coap_msg_parse_type_msg_id(buf, len, &type, &msg_id); + if ((ret == 0) && (type == COAP_MSG_CON)) + { + coap_msg_create(&msg); + ret = coap_msg_set_type(&msg, COAP_MSG_RST); + if (ret < 0) + { + coap_msg_destroy(&msg); + return; + } + ret = coap_msg_set_msg_id(&msg, msg_id); + if (ret < 0) + { + coap_msg_destroy(&msg); + return; + } + coap_client_send(client, &msg); + coap_msg_destroy(&msg); + } +} + +/** + * @brief Receive a message from the server + * + * @param[in,out] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Number of bytes received or error code + * @retval >0 Number of bytes received + * @retval <0 Error + */ +static int coap_client_recv(coap_client_t *client, coap_msg_t *msg) +{ + int num = 0; + int ret = 0; + char buf[COAP_MSG_MAX_BUF_LEN] = {0}; + + num = recv(client->sd, buf, sizeof(buf)); + if (num < 0) + { + return -errno; + } + + ret = coap_msg_parse(msg, buf, num); + if (ret < 0) + { + if (ret == -EBADMSG) + { + coap_client_handle_format_error(client, buf, num); + } + return ret; + } + printf("Received from host %s and port %s\n", client->server_host, client->server_port); + return num; +} + +/** + * @brief Reject a received confirmable message + * + * Send a reset message to the server. + * + * @param[in,out] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_reject_con(coap_client_t *client, coap_msg_t *msg) +{ + coap_msg_t rej = {0}; + int num = 0; + int ret = 0; + + printf("Rejecting confirmable message from host %s and port %s\n", client->server_host, client->server_port); + coap_msg_create(&rej); + ret = coap_msg_set_type(&rej, COAP_MSG_RST); + if (ret < 0) + { + coap_msg_destroy(&rej); + return ret; + } + ret = coap_msg_set_msg_id(&rej, coap_msg_get_msg_id(msg)); + if (ret < 0) + { + coap_msg_destroy(&rej); + return ret; + } + num = coap_client_send(client, &rej); + coap_msg_destroy(&rej); + if (num < 0) + { + return num; + } + return 0; +} + +/** + * @brief Reject a received non-confirmable message + * + * @param[in] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + */ +static int coap_client_reject_non(coap_client_t *client, coap_msg_t *msg) +{ + printf("Rejecting non-confirmable message from host %s and port %s\n", client->server_host, client->server_port); + return 0; +} + +/** + * @brief Reject a received acknowledgement message + * + * @param[in] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + */ +static int coap_client_reject_ack(coap_client_t *client, coap_msg_t *msg) +{ + printf("Rejecting acknowledgement message from host %s and port %s\n", client->server_host, client->server_port); + return 0; +} + +/** + * @brief Reject a received reset message + * + * @param[in] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + */ +static int coap_client_reject_reset(coap_client_t *client, coap_msg_t *msg) +{ + printf("Rejecting reset message from host %s and port %s\n", client->server_host, client->server_port); + return 0; +} + +/** + * @brief Reject a received message + * + * @param[in,out] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_reject(coap_client_t *client, coap_msg_t *msg) +{ + if (coap_msg_get_type(msg) == COAP_MSG_CON) + { + return coap_client_reject_con(client, msg); + } + else if (coap_msg_get_type(msg) == COAP_MSG_NON) + { + return coap_client_reject_non(client, msg); + } + else if (coap_msg_get_type(msg) == COAP_MSG_ACK) + { + return coap_client_reject_ack(client, msg); + } + else if (coap_msg_get_type(msg) == COAP_MSG_RST) + { + return coap_client_reject_reset(client, msg); + } + return 0; /* should never arrive here */ +} + +/** + * @brief Send an acknowledgement message to the server + * + * @param[in,out] client Pointer to a client structure + * @param[in] msg Pointer to a message structure + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_send_ack(coap_client_t *client, coap_msg_t *msg) +{ + coap_msg_t ack = {0}; + int num = 0; + int ret = 0; + + printf("Acknowledging confirmable message from host %s and port %s\n", client->server_host, client->server_port); + coap_msg_create(&ack); + ret = coap_msg_set_type(&ack, COAP_MSG_ACK); + if (ret < 0) + { + coap_msg_destroy(&ack); + return ret; + } + ret = coap_msg_set_msg_id(&ack, coap_msg_get_msg_id(msg)); + if (ret < 0) + { + coap_msg_destroy(&ack); + return ret; + } + num = coap_client_send(client, &ack); + coap_msg_destroy(&ack); + if (num < 0) + { + return num; + } + return 0; +} + +/** + * @brief Compare the token values in a request message and a response message + * + * @param[in] req Pointer to the request message + * @param[in] resp Pointer to the response message + * + * @returns Comparison value + * @retval 0 the tokens are not equal + * @retval 1 the tokens are equal + */ +static int coap_client_match_token(coap_msg_t *req, coap_msg_t *resp) +{ + return ((coap_msg_get_token_len(resp) == coap_msg_get_token_len(req)) + && (memcmp(coap_msg_get_token(resp), coap_msg_get_token(req), coap_msg_get_token_len(req)) == 0)); +} + +/** + * @brief Check that all of the options in a message are acceptable + * + * For a proxy, options are acceptable if they are safe to forward or recognized or both. + * For a server, options are acceptable if they are elective or recognized or both. + * + * @param[in] msg Pointer to message structure + * + * @returns Operation status or bad option number + * @retval 0 Success + * @retval >0 Bad option number + */ +static unsigned coap_client_check_options(coap_msg_t *msg) +{ +#ifdef COAP_PROXY + return coap_msg_check_unsafe_ops(msg); +#else /* !COAP_PROXY */ + return coap_msg_check_critical_ops(msg); +#endif /* COAP_PROXY */ +} + +/** + * @brief Handle a received piggy-backed response message + * + * An acknowledgement has been received that contains + * the same token as the request. Check the response + * contained within it. + * + * @param[in,out] client Pointer to a client structure + * @param[in] resp Pointer to the response message + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_handle_piggybacked_response(coap_client_t *client, coap_msg_t *resp) +{ + unsigned op_num = 0; + + op_num = coap_client_check_options(resp); + if (op_num != 0) + { + printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); + coap_client_reject(client, resp); + return -EBADMSG; + } + printf("Received acknowledgement and response from host %s and port %s\n", client->server_host, client->server_port); + return 0; +} + +/** + * @brief Handle a received separate response message + * + * A separate response has been received that contains + * the same token as the request. Check the response + * and send an acknowledgement if necessary. + * + * @param[in,out] client Pointer to a client structure + * @param[in] resp Pointer to the response message + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_handle_sep_response(coap_client_t *client, coap_msg_t *resp) +{ + unsigned op_num = 0; + + if (coap_msg_get_type(resp) == COAP_MSG_CON) + { + printf("Received confirmable response from host %s and port %s\n", client->server_host, client->server_port); + op_num = coap_client_check_options(resp); + if (op_num != 0) + { + printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); + coap_client_reject(client, resp); + return -EBADMSG; + } + return coap_client_send_ack(client, resp); + } + else if (coap_msg_get_type(resp) == COAP_MSG_NON) + { + printf("Received non-confirmable response from host %s and port %s\n", client->server_host, client->server_port); + op_num = coap_client_check_options(resp); + if (op_num != 0) + { + printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); + coap_client_reject(client, resp); + return -EBADMSG; + } + return 0; + } + coap_client_reject(client, resp); + return -EBADMSG; +} + +/** + * @brief Handle a separate response to a confirmable request + * + * An acknowledgement has been received. Receive the + * response and send an acknowledgement back to the server. + * + * @param[in,out] client Pointer to a client structure + * @param[in] req Pointer to the request message + * @param[out] resp Pointer to the response message + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_exchange_sep(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) +{ + int num = 0; + int ret = 0; + + /* wait for a separate response to a confirmable request */ + printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); + while (1) + { + int start_time = getseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + return num; + } + else if(num > 0) + { + break; + } + int stop_time = getseconds(); + if((stop_time - start_time) > COAP_CLIENT_RESP_TIMEOUT_SEC) + { + printf("Timeout no data received\n"); + return -1; + } + } + + if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) + { + if (coap_msg_get_type(resp) == COAP_MSG_ACK) + { + /* message deduplication */ + printf("Received duplicate acknowledgement from host %s and port %s\n", client->server_host, client->server_port); + continue; + } + else if (coap_msg_get_type(resp) == COAP_MSG_RST) + { + return -ECONNRESET; + } + coap_client_reject(client, resp); + return -EBADMSG; + } + if (coap_client_match_token(req, resp)) + { + return coap_client_handle_sep_response(client, resp); + } + /* message deduplication */ + /* we might have received a duplicate message that was already received from the same server */ + /* reject the message and continue listening */ + ret = coap_client_reject(client, resp); + if (ret < 0 ) + { + return ret; + } + } + return 0; +} + +/** + * @brief Handle the response to a confirmable request + * + * A confirmable request has been sent to the server. + * Receive the acknowledgement and response. Send an + * acknowledgement if necessary. + * + * @param[in,out] client Pointer to a client structure + * @param[in] req Pointer to the request message + * @param[out] resp Pointer to the response message + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_client_exchange_con(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) +{ + int num = 0; + int ret = 0; + + /* wait for piggy-backed response in ack message + * or ack message and separate response message + */ + printf("Expecting acknowledgement from host %s and port %s\n", client->server_host, client->server_port); + while (1) + { + int start_time = getseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + return num; + } + else if(num > 0) + { + break; + } + int stop_time = getseconds(); + if((stop_time - start_time) > COAP_CLIENT_ACK_TIMEOUT_SEC) + { + printf("Timeout no data received\n"); + return -1; + } + } + + if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) + { + if (coap_msg_get_type(resp) == COAP_MSG_ACK) + { + if (coap_msg_is_empty(resp)) + { + /* received ack message, wait for separate response message */ + printf("Received acknowledgement from host %s and port %s\n", client->server_host, client->server_port); + return coap_client_exchange_sep(client, req, resp); + } + else if (coap_client_match_token(req, resp)) + { + return coap_client_handle_piggybacked_response(client, resp); + } + } + else if (coap_msg_get_type(resp) == COAP_MSG_RST) + { + return -ECONNRESET; + } + coap_client_reject(client, resp); + return -EBADMSG; + } + else if (coap_client_match_token(req, resp)) + { + /* RFC7252 + * as the underlying datagram transport may not be sequence-preserving, + * the Confirmable message carrying the response may actually arrive + * before or after the Acknowledgement message for the request; for + * the purposes of terminating the retransmission sequence, this also + * serves as an acknowledgement. + */ + return coap_client_handle_sep_response(client, resp); + } + /* message deduplication */ + /* we might have received a duplicate message that was already received from the same server */ + /* reject the message and continue listening */ + ret = coap_client_reject(client, resp); + if (ret < 0 ) + { + return ret; + } + } + return 0; +} + +/** + * @brief Handle the response to a non-confirmable request + * + * A non-confirmable request has been sent to the server. + * Receive the response. + * + * @param[in,out] client Pointer to a client structure + * @param[in] req Pointer to the request message + * @param[out] resp Pointer to the response message + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + **/ +static int coap_client_exchange_non(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) +{ + int num = 0; + int ret = 0; + + printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); + while (1) + { + int start_time = getseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + return num; + } + else if(num > 0) + { + break; + } + int stop_time = getseconds(); + if((stop_time - start_time) > COAP_CLIENT_RESP_TIMEOUT_SEC) + { + printf("Timeout no data received\n"); + return -1; + } + } + + if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) + { + if (coap_msg_get_type(resp) == COAP_MSG_RST) + { + return -ECONNRESET; + } + coap_client_reject(client, resp); + return -EBADMSG; + } + if (coap_client_match_token(req, resp)) + { + return coap_client_handle_sep_response(client, resp); + } + /* message deduplication */ + /* we might have received a duplicate message that was already received from the same server */ + /* reject the message and continue listening */ + ret = coap_client_reject(client, resp); + if (ret < 0 ) + { + return ret; + } + } + return 0; +} + +int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) +{ + unsigned char msg_id_buf[2] = {0}; + unsigned msg_id = 0; + int num = 0; + char token[4] = {0}; + int ret = 0; + + /* check for a valid request */ + if ((coap_msg_get_type(req) == COAP_MSG_ACK) + || (coap_msg_get_type(req) == COAP_MSG_RST) + || (coap_msg_get_code_class(req) != COAP_MSG_REQ)) + { + return -EINVAL; + } + + /* generate the message ID */ + coap_msg_gen_rand_str((char *)msg_id_buf, sizeof(msg_id_buf)); + msg_id = (((unsigned)msg_id_buf[1]) << 8) | (unsigned)msg_id_buf[0]; + ret = coap_msg_set_msg_id(req, msg_id); + if (ret < 0) + { + return ret; + } + + /* generate the token */ + coap_msg_gen_rand_str(token, sizeof(token)); + ret = coap_msg_set_token(req, token, sizeof(token)); + if (ret < 0) + { + return ret; + } + + if (coap_msg_get_type(req) == COAP_MSG_CON) + { + printf("Sending confirmable request to host %s and port %s\n", client->server_host, client->server_port); + } + else if (coap_msg_get_type(req) == COAP_MSG_NON) + { + printf("Sending non-confirmable request to host %s and port %s\n", client->server_host, client->server_port); + } + + num = coap_client_send(client, req); + if (num < 0) + { + return num; + } + + if (coap_msg_get_type(req) == COAP_MSG_CON) + { + return coap_client_exchange_con(client, req, resp); + } + else if (coap_msg_get_type(req) == COAP_MSG_NON) + { + return coap_client_exchange_non(client, req, resp); + } + return -EINVAL; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Test an exchange with the server + * + * @param[in] data Pointer to a client test data structure + * + * @returns Test result + */ +test_result_t test_exchange_func(char* buf,int buf_len) +{ + printf("\n----------------------------------------\n"); + test_result_t result = PASS; + coap_client_t client = {0}; + coap_msg_t resp = {0}; + coap_msg_t req = {0}; + int ret = 0; + + test_coap_client_msg_op_t req_ops; + req_ops.num = COAP_MSG_URI_PATH; + req_ops.len = 8; + req_ops.val = (char*)"resource"; + + test_coap_client_msg_op_t resp_ops; + resp_ops.num = 0; + resp_ops.len = 0; + resp_ops.val = 0; + + test_coap_client_msg_t test1_req; + test1_req.type = COAP_MSG_CON; + test1_req.code_class = COAP_MSG_REQ; + test1_req.code_detail = COAP_MSG_GET; + test1_req.ops = req_ops; + test1_req.num_ops = 1; + test1_req.payload = buf; + test1_req.payload_len = buf_len; + + test_coap_client_msg_t test1_resp; + test1_resp.type = COAP_MSG_ACK; + test1_resp.code_class = COAP_MSG_SUCCESS; + test1_resp.code_detail = COAP_MSG_CONTENT; + test1_resp.ops = resp_ops; + test1_resp.num_ops = 0; + test1_resp.payload = (char*)"Hello Client!"; + test1_resp.payload_len = 13; + + test_coap_client_data_t test1_data; + test1_data.desc = "test 1: send a confirmable request and expect a piggy-backed response"; + test1_data.host = HOST; + test1_data.port = PORT; + test1_data.common_name = (char*)"dummy/server"; + test1_data.test_req = test1_req; + test1_data.test_resp = test1_resp; + test1_data.num_msg = 1; + + printf("%s\n", test1_data.desc); + + ret = coap_client_create(&client, + test1_data.host, + test1_data.port); + + if (ret < 0) + { + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + + coap_msg_create(&req); + coap_msg_create(&resp); + + ret = exchange(&client, &test1_data.test_req, &req, &resp); + printf("exchange function\n"); + if (ret != PASS) + { + printf("exchange function fail\n"); + coap_msg_destroy(&resp); + coap_msg_destroy(&req); + coap_client_destroy(&client); + return FAIL; + } + + ret = compare_ver_token(&req, &resp); + if (ret != PASS) + { + coap_msg_destroy(&resp); + coap_msg_destroy(&req); + coap_client_destroy(&client); + return FAIL; + } + + ret = check_resp(&test1_data.test_resp, &resp); + if (ret != PASS) + { + coap_msg_destroy(&resp); + coap_msg_destroy(&req); + coap_client_destroy(&client); + return FAIL; + } + + coap_msg_destroy(&resp); + coap_msg_destroy(&req); + coap_client_destroy(&client); + + return result; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Print a CoAP message + * + * @param[in] str String to be printed before the message + * @param[in] msg Pointer to a message structure + */ +void print_coap_msg(const char *str, coap_msg_t *msg) +{ + coap_msg_op_t *op = NULL; + unsigned num = 0; + unsigned len = 0; + unsigned i = 0; + unsigned j = 0; + char *payload = NULL; + char *token = NULL; + char *val = NULL; + + printf("%s\n", str); + printf("ver: 0x%02x\n", coap_msg_get_ver(msg)); + printf("type: 0x%02x\n", coap_msg_get_type(msg)); + printf("token_len: %d\n", coap_msg_get_token_len(msg)); + printf("code_class: %d\n", coap_msg_get_code_class(msg)); + printf("code_detail: %d\n", coap_msg_get_code_detail(msg)); + printf("msg_id: 0x%04x\n", coap_msg_get_msg_id(msg)); + printf("token: "); + token = coap_msg_get_token(msg); + for (i = 0; i < coap_msg_get_token_len(msg); i++) + { + printf(" 0x%02x", (unsigned char)token[i]); + } + printf("\n"); + op = coap_msg_get_first_op(msg); + while (op != NULL) + { + num = coap_msg_op_get_num(op); + len = coap_msg_op_get_len(op); + val = coap_msg_op_get_val(op); + printf("op[%u].num: %u\n", j, num); + printf("op[%u].len: %u\n", j, len); + printf("op[%u].val: ", j); + for (i = 0; i < len; i++) + { + printf(" 0x%02x", (unsigned char)val[i]); + } + printf("\n"); + op = coap_msg_op_get_next(op); + j++; + } + printf("payload: "); + payload = coap_msg_get_payload(msg); + for (i = 0; i < coap_msg_get_payload_len(msg); i++) + { + printf("%c", payload[i]); + } + printf("\n"); + printf("payload_len: %zu\n", coap_msg_get_payload_len(msg)); +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Populate a request message with details from a test request message structure + * + * @param[in] test_req Pointer to a test request message structure + * @param[out] req Pointer to a request message structure + * + * @returns Test result + */ +test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req) +{ + int ret = 0; + + ret = coap_msg_set_type(req, test_req->type); + if (ret < 0) + { + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + ret = coap_msg_set_code(req, test_req->code_class, test_req->code_detail); + if (ret < 0) + { + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + ret = coap_msg_add_op(req, test_req->ops.num, test_req->ops.len, test_req->ops.val); + if (ret < 0) + { + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + if (test_req->payload) + { + ret = coap_msg_set_payload(req, test_req->payload, test_req->payload_len); + if (ret < 0) + { + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + } + return PASS; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Send a request to the server and receive the response + * + * @param[in,out] client Pointer to a client structure + * @param[in] test_req Pointer to a test request message structure + * @param[out] req Pointer to a request message structure + * @param[out] resp Pointer to a response message structure + * + * @returns Test result + */ +test_result_t exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp) +{ + test_result_t result = PASS; + int ret = 0; + + result = populate_req(test_req, req); + if (result != PASS) + { + printf("populate_req FAIL\n"); + return result; + } + ret = coap_client_exchange(client, req, resp); + if (ret < 0) + { + printf("coap_client_exchange FAIL\n"); + printf("Error : %s\n",strerror(-ret)); + return FAIL; + } + printf("coap_client_exchange PASS\n"); + print_coap_msg("Sent:", req); + print_coap_msg("Received:", resp); + + return PASS; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Compare the version and token fields in a request message and a response message + * + * @param[out] req Pointer to a request message structure + * @param[out] resp Pointer to a response message structure + * + * @returns Test result + */ +test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp) +{ + if (coap_msg_get_ver(req) != coap_msg_get_ver(resp)) + { + return FAIL; + } + if (coap_msg_get_token_len(req) != coap_msg_get_token_len(resp)) + { + return FAIL; + } + else if (memcmp(coap_msg_get_token(req), coap_msg_get_token(resp), coap_msg_get_token_len(req)) != 0) + { + return FAIL; + } + return PASS; +} +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +/** + * @brief Check the fields in a response message against the expected values + * + * @param[out] test_resp Pointer to a test response message structure + * @param[out] resp Pointer to a response message structure + * + * @returns Test result + */ +test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp) +{ + if (test_resp->type != coap_msg_get_type(resp)) + { + return FAIL; + } + if (test_resp->code_class != coap_msg_get_code_class(resp)) + { + return FAIL; + } + if (test_resp->code_detail != coap_msg_get_code_detail(resp)) + { + return FAIL; + } + if (test_resp->payload_len != coap_msg_get_payload_len(resp)) + { + return FAIL; + } + else if (memcmp(test_resp->payload, coap_msg_get_payload(resp), test_resp->payload_len)) + { + return FAIL; + } + return PASS; +}