Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 39:4f3f7463e55f, committed 2017-05-25
- Comitter:
- ranaumarnaeem
- Date:
- Thu May 25 11:53:45 2017 +0000
- Parent:
- 38:f1bc6e867fcf
- Commit message:
- mbed 5.4 with sleep mode
Changed in this revision
--- a/Coap/coap_client.c Wed May 24 07:51:33 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1021 +0,0 @@ -/* - * 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 * - ****************************************************************************************************/ -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; - } - - 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; - } - 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 Server\n"); - 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; - int starttimeout,endtimeout; - - /* 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) - { - starttimeout = readseconds(); - while(1) - { - num = coap_client_recv(client, resp); - if (num < 0) - { - return num; - } - else if(num > 0) - { - break; - } - endtimeout = readseconds(); - if((endtimeout - starttimeout) > 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; - int starttimeout,endtimeout; - /* wait for piggy-backed response in ack message - * or ack message and separate response message - */ - //printf("Expecting acknowledgement from server\r\n"); - client->num_retrans = 0; - while (1) - { - int doubletimeout = COAP_CLIENT_ACK_TIMEOUT_SEC; - starttimeout = readseconds(); - while(1) - { - num = coap_client_recv(client, resp); - if (num < 0) - { - //return num; - } - else if(num > 0) - { - break; - } - endtimeout = readseconds(); - if((endtimeout - starttimeout) > doubletimeout) - { - printf("Timeout no data received after %d seconds\n",endtimeout - starttimeout); - - if (client->num_retrans >= COAP_CLIENT_MAX_RETRANSMIT) - { - printf("Maximum retries reached no ack from server!\r\n"); - return -ETIMEDOUT; - } - - doubletimeout = 2 * doubletimeout; - starttimeout = readseconds(); - client->num_retrans++; - - printf("Retransmitting to server...\r\n"); - num = coap_client_send(client, req); - if (num < 0) - { - printf("Resending Failed to server...\r\n"); - return num; - } - } - } - - 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; - int starttimeout,endtimeout; - - printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); - while (1) - { - starttimeout = readseconds(); - while(1) - { - num = coap_client_recv(client, resp); - if (num < 0) - { - return num; - } - else if(num > 0) - { - break; - } - endtimeout = readseconds(); - if((endtimeout - starttimeout) > 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; - } - - 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"); - 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 = "Send a confirmable request to server 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); - - 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]); - //ucReturnCode[i] = payload[i]; - } - //ucReturnCode[i] = '\0'; - 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; - } - return PASS; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coap/coap_client.cpp Thu May 25 11:53:45 2017 +0000 @@ -0,0 +1,1026 @@ +/* + * 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 * + ****************************************************************************************************/ +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; + } + + 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; + } + 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 Server\n"); + 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; + int starttimeout,endtimeout; + + /* 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) + { + starttimeout = readseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + return num; + } + else if(num > 0) + { + break; + } + endtimeout = readseconds(); + if((endtimeout - starttimeout) > 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; + int starttimeout,endtimeout; + /* wait for piggy-backed response in ack message + * or ack message and separate response message + */ + //printf("Expecting acknowledgement from server\r\n"); + client->num_retrans = 0; + while (1) + { + int doubletimeout = COAP_CLIENT_ACK_TIMEOUT_SEC; + starttimeout = readseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + //return num; + } + else if(num > 0) + { + break; + } + endtimeout = readseconds(); + if((endtimeout - starttimeout) > doubletimeout) + { + printf("Timeout no data received after %d seconds\n",endtimeout - starttimeout); + + if (client->num_retrans >= COAP_CLIENT_MAX_RETRANSMIT) + { + printf("Maximum retries reached no ack from server!\r\n"); + return -ETIMEDOUT; + } + + doubletimeout = 2 * doubletimeout; + starttimeout = readseconds(); + client->num_retrans++; + + printf("Retransmitting to server...\r\n"); + num = coap_client_send(client, req); + if (num < 0) + { + printf("Resending Failed to server...\r\n"); + return num; + } + } + } + + 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; + int starttimeout,endtimeout; + + printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); + while (1) + { + starttimeout = readseconds(); + while(1) + { + num = coap_client_recv(client, resp); + if (num < 0) + { + return num; + } + else if(num > 0) + { + break; + } + endtimeout = readseconds(); + if((endtimeout - starttimeout) > 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; + } + + 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,char* returncode) +{ + printf("----------------------------------------\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 = "Send a confirmable request to server 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); + + 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,returncode); + //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,char* returncode) +{ + //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); + + if(strcmp(str,"Received:") == 0) + { + for (i = 0; i < coap_msg_get_payload_len(msg); i++) + { + printf("%c", payload[i]); + returncode[i] = payload[i]; + } + returncode[i] = '\0'; + } + 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,char* returncode) +{ + 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,returncode); + print_coap_msg("Received:", resp,returncode); + + 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; + } + return PASS; +}
--- a/Coap/coap_client.h Wed May 24 07:51:33 2017 +0000 +++ b/Coap/coap_client.h Thu May 25 11:53:45 2017 +0000 @@ -45,8 +45,6 @@ #define COAP_CLIENT_HOST_BUF_LEN 128 /* Buffer length for host addresses */ #define COAP_CLIENT_PORT_BUF_LEN 8 /* Buffer length for port numbers */ -//unsigned char ucReturnCode[10]; //Return code array - /** * @brief Test result enumeration */ @@ -158,12 +156,12 @@ **/ int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp); -test_result_t test_exchange_func(char* buf,int buf_len); +test_result_t test_exchange_func(char* buf,int buf_len,char* returncode); test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp); test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp); -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 exchange(coap_client_t *client, test_coap_client_msg_t *test_req, coap_msg_t *req, coap_msg_t *resp,char* returncode); test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req); -void print_coap_msg(const char *str, coap_msg_t *msg); +void print_coap_msg(const char *str, coap_msg_t *msg,char* returncode);
--- a/Coap/coap_msg.c Wed May 24 07:51:33 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1024 +0,0 @@ -/* - * 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_msg.c - * - * @brief Source file for the FreeCoAP message parser/formatter library - */ - -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <time.h> -#include <errno.h> -#include "coap_msg.h" -#include "coap_client.h" - -#define coap_msg_op_list_get_first(list) ((list)->first) /**< Get the first option from an option linked-list */ -#define coap_msg_op_list_get_last(list) ((list)->last) /**< Get the last option in an option linked-list */ -#define coap_msg_op_list_is_empty(list) ((list)->first == NULL) /**< Indicate whether or not an option linked-list is empty */ - -static int coap_msg_rand_init = 0; /**< Indicates whether or not the random number generator has been initialised */ - -void coap_msg_gen_rand_str(char *buf, size_t len) -{ - size_t i = 0; - - if (!coap_msg_rand_init) - { - srand(time(NULL)); - coap_msg_rand_init = 1; - } - for (i = 0; i < len; i++) - { - buf[i] = rand() & 0x000000ff; - } -} - -int coap_msg_op_num_is_recognized(unsigned num) -{ - switch (num) - { - case COAP_MSG_IF_MATCH: - case COAP_MSG_URI_HOST: - case COAP_MSG_ETAG: - case COAP_MSG_IF_NONE_MATCH: - case COAP_MSG_URI_PORT: - case COAP_MSG_LOCATION_PATH: - case COAP_MSG_URI_PATH: - case COAP_MSG_CONTENT_FORMAT: - case COAP_MSG_MAX_AGE: - case COAP_MSG_URI_QUERY: - case COAP_MSG_ACCEPT: - case COAP_MSG_LOCATION_QUERY: - case COAP_MSG_PROXY_URI: - case COAP_MSG_PROXY_SCHEME: - case COAP_MSG_SIZE1: - return 1; - } - return 0; -} - -/** - * @brief Allocate an option structure - * - * @param[in] num Option number - * @param[in] len Option length - * @param[in] val Pointer to the option value - * - * @returns Pointer to the option structure - * @retval NULL Out-of-memory - */ -static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val) -{ - coap_msg_op_t *op = NULL; - - op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t)); - if (op == NULL) - { - return NULL; - } - op->num = num; - op->len = len; - op->val = (char *)malloc(len); - if (op->val == NULL) - { - free(op); - return NULL; - } - memcpy(op->val, val, len); - op->next = NULL; - return op; -} - -/** - * @brief Free an option structure that was allocated by coap_msg_op_new - * - * @param[in,out] op Pointer to the option structure - */ -static void coap_msg_op_delete(coap_msg_op_t *op) -{ - free(op->val); - free(op); -} - -/** - * @brief Initialise an option linked-list structure - * - * @param[out] list Pointer to an option linked-list structure - */ -static void coap_msg_op_list_create(coap_msg_op_list_t *list) -{ - memset(list, 0, sizeof(coap_msg_op_list_t)); -} - -/** - * @brief Deinitialise an option linked-list structure - * - * @param[in,out] list Pointer to an option linked-list structure - */ -static void coap_msg_op_list_destroy(coap_msg_op_list_t *list) -{ - coap_msg_op_t *prev = NULL; - coap_msg_op_t *op = NULL; - - op = list->first; - while (op != NULL) - { - prev = op; - op = op->next; - coap_msg_op_delete(prev); - } - memset(list, 0, sizeof(coap_msg_op_list_t)); -} - -/** - * @brief Allocate an option structure and add it to the end of an option linked-list structure - * - * @param[in,out] list Pointer to an option linked-list structure - * @param[in] num Option number - * @param[in] len Option length - * @param[in] val Pointer to a buffer containing the option value - * - * @returns Operation status - * @retval 0 Success - * @retval <0 Error - */ -static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) -{ - coap_msg_op_t *op = NULL; - - op = coap_msg_op_new(num, len, val); - if (op == NULL) - { - return -ENOMEM; - } - if (list->first == NULL) - { - list->first = op; - list->last = op; - } - else - { - list->last->next = op; - list->last = op; - } - return 0; -} - -/** - * @brief Allocate an option structure and add it to an option linked-list structure - * - * The option is added to the list at a position determined by the option number. - * - * @param[in,out] list Pointer to an option linked-list structure - * @param[in] num Option number - * @param[in] len Option length - * @param[in] val Pointer to a buffer containing the option value - * - * @returns Operation status - * @retval 0 Success - * @retval <0 Error - */ -static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) -{ - coap_msg_op_t *prev = NULL; - coap_msg_op_t *op = NULL; - - op = coap_msg_op_new(num, len, val); - if (op == NULL) - { - return -ENOMEM; - } - if (list->first == NULL) - { - /* empty list */ - list->first = op; - list->last = op; - return 0; - } - if (op->num < list->first->num) - { - /* start of the list */ - op->next = list->first; - list->first = op; - return 0; - } - prev = list->first; - while (prev != list->last) - { - /* middle of the list */ - if ((prev->num <= op->num) && (op->num < prev->next->num)) - { - op->next = prev->next; - prev->next = op; - return 0; - } - prev = prev->next; - } - /* end of the list */ - list->last->next = op; - list->last = op; - return 0; -} - -void coap_msg_create(coap_msg_t *msg) -{ - memset(msg, 0, sizeof(coap_msg_t)); - msg->ver = COAP_MSG_VER; - coap_msg_op_list_create(&msg->op_list); -} - -void coap_msg_destroy(coap_msg_t *msg) -{ - coap_msg_op_list_destroy(&msg->op_list); - if (msg->payload != NULL) - { - free(msg->payload); - } - memset(msg, 0, sizeof(coap_msg_t)); -} - -void coap_msg_reset(coap_msg_t *msg) -{ - coap_msg_destroy(msg); - coap_msg_create(msg); -} - -/** - * @brief Check a message for correctness - * - * The following checks from RFC7252 are performed: - * - * An Empty message has the Code field set to 0.00. The Token Length - * field MUST be set to 0 and bytes of data MUST NOT be present after - * the Message ID field. If there are any bytes, they MUST be processed - * as a message format error. - * - * The Reset message MUST echo the Message ID of the Confirmable message - * and MUST be Empty. - * - * A Non-confirmable message always carries either a request or response - * and MUST NOT be Empty. - * - * @param[in] msg Pointer to a message structure - * @returns Operation status - * @retval 0 Success - * @retval <0 Error - */ -static int coap_msg_check(coap_msg_t *msg) -{ - if ((msg->code_class == 0) && (msg->code_detail == 0)) - { - /* empty message */ - if ((msg->type == COAP_MSG_NON) - || (msg->token_len != 0) - || (!coap_msg_op_list_is_empty(&msg->op_list)) - || (msg->payload_len != 0)) - { - return -EBADMSG; - } - } - else - { - /* non-empty message */ - if (msg->type == COAP_MSG_RST) - { - return -EBADMSG; - } - } - return 0; -} - -unsigned coap_msg_check_critical_ops(coap_msg_t *msg) -{ - coap_msg_op_t *op = NULL; - unsigned num = 0; - - op = coap_msg_get_first_op(msg); - while (op != NULL) - { - num = coap_msg_op_get_num(op); - if ((coap_msg_op_num_is_critical(num)) - && (!coap_msg_op_num_is_recognized(num))) - { - return num; /* fail */ - } - op = coap_msg_op_get_next(op); - } - return 0; /* pass */ -} - -unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg) -{ - coap_msg_op_t *op = NULL; - unsigned num = 0; - - op = coap_msg_get_first_op(msg); - while (op != NULL) - { - num = coap_msg_op_get_num(op); - if ((coap_msg_op_num_is_unsafe(num)) - && (!coap_msg_op_num_is_recognized(num))) - { - return num; /* fail */ - } - op = coap_msg_op_get_next(op); - } - return 0; /* pass */ -} - -int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id) -{ - if (len < 4) - { - return -EBADMSG; - } - *type = (buf[0] >> 4) & 0x03; - *msg_id = ntohs(*((uint16_t *)(&buf[2]))); - return 0; -} - -/** - * @brief Parse the header in a message - * - * @param[out] msg Pointer to a message structure - * @param[in] buf Pointer to a buffer containing the message - * @param[in] len Length of the buffer - * - * @returns Number of bytes parsed or error code - * @retval >0 Number of bytes parsed - * @retval <0 Error - */ -static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len) -{ - char *p = buf; - - if (len < 4) - { - return -EBADMSG; - } - msg->ver = (p[0] >> 6) & 0x03; - if (msg->ver != COAP_MSG_VER) - { - return -EINVAL; - } - msg->type = (p[0] >> 4) & 0x03; - msg->token_len = p[0] & 0x0f; - if (msg->token_len > sizeof(msg->token)) - { - return -EBADMSG; - } - msg->code_detail = p[1] & 0x1f; - msg->code_class = (p[1] >> 5) & 0x07; - if ((msg->code_class != COAP_MSG_REQ) - && (msg->code_class != COAP_MSG_SUCCESS) - && (msg->code_class != COAP_MSG_CLIENT_ERR) - && (msg->code_class != COAP_MSG_SERVER_ERR)) - { - return -EBADMSG; - } - msg->msg_id = ntohs(*((uint16_t *)(&p[2]))); - p += 4; - len -= 4; - return p - buf; -} - -/** - * @brief Parse the token in a message - * - * @param[out] msg Pointer to a message structure - * @param[in] buf Pointer to a buffer containing the message - * @param[in] len Length of the buffer - * - * @returns Number of bytes parsed or error code - * @retval >0 Number of bytes parsed - * @retval <0 Error - */ -static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len) -{ - if (len < msg->token_len) - { - return -EBADMSG; - } - memcpy(msg->token, buf, msg->token_len); - return msg->token_len; -} - -/** - * @brief Parse an option in a message - * - * @param[in,out] msg Pointer to a message structure - * @param[in] buf Pointer to a buffer containing the message - * @param[in] len Length of the buffer - * - * @returns Number of bytes parsed or error code - * @retval >0 Number of bytes parsed - * @retval <0 Error - */ -static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len) -{ - coap_msg_op_t *prev = NULL; - unsigned op_delta = 0; - unsigned op_len = 0; - unsigned op_num = 0; - char *p = buf; - int ret = 0; - - if (len < 1) - { - return -EBADMSG; - } - op_delta = (p[0] >> 4) & 0x0f; - op_len = p[0] & 0x0f; - if ((op_delta == 15) || (op_len == 15)) - { - return -EBADMSG; - } - p++; - len--; - if (op_delta == 13) - { - if (len < 1) - { - return -EBADMSG; - } - op_delta += p[0]; - p++; - len--; - } - else if (op_delta == 14) - { - if (len < 2) - { - return -EBADMSG; - } - op_delta = 269 + ntohs(*((uint16_t *)(&p[0]))); - p += 2; - len -= 2; - } - if (op_len == 13) - { - if (len < 1) - { - return -EBADMSG; - } - op_len += p[0]; - p++; - len--; - } - else if (op_len == 14) - { - if (len < 2) - { - return -EBADMSG; - } - op_len = 269 + ntohs(*((uint16_t *)(&p[0]))); - p += 2; - len -= 2; - } - if (len < op_len) - { - return -EBADMSG; - } - prev = coap_msg_op_list_get_last(&msg->op_list); - if (prev == NULL) - { - op_num = op_delta; - } - else - { - op_num = coap_msg_op_get_num(prev) + op_delta; - } - ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p); - if (ret < 0) - { - return ret; - } - p += op_len; - return p - buf; -} - -/** - * @brief Parse the options in a message - * - * @param[in,out] msg Pointer to a message structure - * @param[in] buf Pointer to a buffer containing the message - * @param[in] len Length of the buffer - * - * @returns Number of bytes parsed or error code - * @retval >0 Number of bytes parsed - * @retval <0 Error - */ -static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len) -{ - int num = 0; - char *p = buf; - - while (1) - { - if (((p[0] & 0xff) == 0xff) || (len == 0)) - { - break; - } - num = coap_msg_parse_op(msg, p, len); - if (num < 0) - { - return num; - } - p += num; - len -= num; - } - return p - buf; -} - -/** - * @brief Parse the payload in a message - * - * @param[out] msg Pointer to a message structure - * @param[in] buf Pointer to a buffer containing the message - * @param[in] len Length of the buffer - * - * @returns Number of bytes parsed or error code - * @retval >0 Number of bytes parsed - * @retval <0 Error - */ -static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len) -{ - char *p = buf; - - if (len == 0) - { - return 0; - } - if ((p[0] & 0xff) != 0xff) - { - return -EBADMSG; - } - p++; - len--; - if (len == 0) - { - return -EBADMSG; - } - msg->payload = (char *)malloc(len); - if (msg->payload == NULL) - { - return -ENOMEM; - } - memcpy(msg->payload, p, len); - msg->payload_len = len; - p += len; - return p - buf; -} - -int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len) -{ - int num = 0; - char *p = buf; - - coap_msg_reset(msg); - num = coap_msg_parse_hdr(msg, p, len); - if (num < 0) - { - coap_msg_destroy(msg); - return num; - } - p += num; - len -= num; - num = coap_msg_parse_token(msg, p, len); - if (num < 0) - { - coap_msg_destroy(msg); - return num; - } - p += num; - len -= num; - num = coap_msg_parse_ops(msg, p, len); - if (num < 0) - { - coap_msg_destroy(msg); - return num; - } - p += num; - len -= num; - num = coap_msg_parse_payload(msg, p, len); - if (num < 0) - { - coap_msg_destroy(msg); - return num; - } - return coap_msg_check(msg); -} - -int coap_msg_set_type(coap_msg_t *msg, unsigned type) -{ - if ((type != COAP_MSG_CON) - && (type != COAP_MSG_NON) - && (type != COAP_MSG_ACK) - && (type != COAP_MSG_RST)) - { - return -EINVAL; - } - msg->type = type; - return 0; -} - -int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail) -{ - if (code_class > COAP_MSG_MAX_CODE_CLASS) - { - return -EINVAL; - } - if (code_detail > COAP_MSG_MAX_CODE_DETAIL) - { - return -EINVAL; - } - msg->code_class = code_class; - msg->code_detail = code_detail; - return 0; -} - -int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id) -{ - if (msg_id > COAP_MSG_MAX_MSG_ID) - { - return -EINVAL; - } - msg->msg_id = msg_id; - return 0; -} - -int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len) -{ - if (len > COAP_MSG_MAX_TOKEN_LEN) - { - return -EINVAL; - } - memcpy(msg->token, buf, len); - msg->token_len = len; - return 0; -} - -int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val) -{ - return coap_msg_op_list_add(&msg->op_list, num, len, val); -} - -int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len) -{ - msg->payload_len = 0; - if (msg->payload != NULL) - { - free(msg->payload); - msg->payload = NULL; - } - if (len > 0) - { - msg->payload = (char *)malloc(len); - if (msg->payload == NULL) - { - return -ENOMEM; - } - memcpy(msg->payload, buf, len); - msg->payload_len = len; - } - return 0; -} - -/** - * @brief Format the header in a message - * - * @param[in] msg Pointer to a message structure - * @param[out] buf Pointer to a buffer to contain the formatted message - * @param[in] len Length of the buffer - * - * @returns Length of the formatted message or error code - * @retval >0 Length of the formatted message - * @retval <0 Error - */ -static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len) -{ - uint16_t msg_id = 0; - - if (len < 4) - { - return -ENOSPC; - } - buf[0] = (char)((COAP_MSG_VER << 6) - | ((msg->type & 0x03) << 4) - | (msg->token_len & 0x0f)); - buf[1] = (char)(((msg->code_class & 0x07) << 5) - | (msg->code_detail & 0x1f)); - msg_id = htons(msg->msg_id); - memcpy(&buf[2], &msg_id, 2); - return 4; -} - -/** - * @brief Format the token in a message - * - * @param[in] msg Pointer to a message structure - * @param[out] buf Pointer to a buffer to contain the formatted message - * @param[in] len Length of the buffer - * - * @returns Length of the formatted message or error code - * @retval >0 Length of the formatted message - * @retval <0 Error - */ -static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len) -{ - if (len < msg->token_len) - { - return -ENOSPC; - } - memcpy(buf, msg->token, msg->token_len); - return msg->token_len; -} - -/** - * @brief Format an option in a message - * - * @param[in] op Pointer to an option structure - * @param[in] prev_num option number of the previous option - * @param[out] buf Pointer to a buffer to contain the formatted message - * @param[in] len Length of the buffer - * - * @returns Length of the formatted message or error code - * @retval >0 Length of the formatted message - * @retval <0 Error - */ -static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len) -{ - unsigned op_delta = 0; - unsigned num = 0; - uint16_t val = 0; - char *p = buf; - - op_delta = op->num - prev_num; - num++; - - /* option delta */ - if (op_delta >= 269) - { - num += 2; - } - else if (op_delta >= 13) - { - num += 1; - } - - /* option length */ - if (op->len >= 269) - { - num += 2; - } - else if (op->num >= 13) - { - num += 1; - } - - /* option value */ - num += op->len; - if (num > len) - { - return -ENOSPC; - } - - /* option delta */ - if (op_delta >= 269) - { - p[0] = 14 << 4; - } - else if (op_delta >= 13) - { - p[0] = 13 << 4; - } - else - { - p[0] = op_delta << 4; - } - - /* option length */ - if (op->len >= 269) - { - p[0] |= 14; - } - else if (op->len >= 13) - { - p[0] |= 13; - } - else - { - p[0] |= op->len; - } - p++; - len--; - - /* option delta extended */ - if (op_delta >= 269) - { - val = htons(op_delta - 269); - memcpy(p, &val, 2); - p += 2; - len -= 2; - } - else if (op_delta >= 13) - { - p[0] = op_delta - 13; - p++; - len--; - } - - /* option length extended */ - if (op->len >= 269) - { - val = htons(op->len - 269); - memcpy(p, &val, 2); - p += 2; - len -= 2; - } - else if (op->len >= 13) - { - p[0] = op->len - 13; - p++; - len--; - } - - /* option value */ - memcpy(p, op->val, op->len); - p += op->len; - - return p - buf; -} - -/** - * @brief Format the options in a message - * - * @param[in] msg Pointer to a message structure - * @param[out] buf Pointer to a buffer to contain the formatted message - * @param[in] len Length of the buffer - * - * @returns Length of the formatted message or error code - * @retval >0 Length of the formatted message - * @retval <0 Error - */ -static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len) -{ - coap_msg_op_t *op = NULL; - unsigned prev_num = 0; - int num = 0; - char *p = buf; - - op = coap_msg_op_list_get_first(&msg->op_list); - while (op != NULL) - { - num = coap_msg_format_op(op, prev_num, p, len); - if (num < 0) - { - return num; - } - p += num; - len -= num; - prev_num = coap_msg_op_get_num(op); - op = coap_msg_op_get_next(op); - } - return p - buf; -} - -/** - * @brief Format the payload in a message - * - * @param[in] msg Pointer to a message structure - * @param[out] buf Pointer to a buffer to contain the formatted message - * @param[in] len Length of the buffer - * - * @returns Length of the formatted message or error code - * @retval >0 Length of the formatted message - * @retval <0 Error - */ -static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len) -{ - if (msg->payload_len == 0) - { - return 0; - } - if (msg->payload_len + 1 > len) - { - return -ENOSPC; - } - buf[0] = 0xff; - memcpy(&buf[1], msg->payload, msg->payload_len); - return msg->payload_len + 1; -} - -int coap_msg_format(coap_msg_t *msg, char *buf, size_t len) -{ - int num = 0; - char *p = buf; - int ret = 0; - - ret = coap_msg_check(msg); - if (ret != 0) - { - return ret; - } - num = coap_msg_format_hdr(msg, p, len); - if (num < 0) - { - return num; - } - p += num; - len -= num; - num = coap_msg_format_token(msg, p, len); - if (num < 0) - { - return num; - } - p += num; - len -= num; - num = coap_msg_format_ops(msg, p, len); - if (num < 0) - { - return num; - } - p += num; - len -= num; - num = coap_msg_format_payload(msg, p, len); - if (num < 0) - { - return num; - } - p += num; - return p - buf; -} - -int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src) -{ - coap_msg_op_t *op = NULL; - int ret = 0; - - dst->ver = src->ver; - ret = coap_msg_set_type(dst, coap_msg_get_type(src)); - if (ret < 0) - { - return ret; - } - ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src)); - if (ret < 0) - { - return ret; - } - ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src)); - if (ret < 0) - { - return ret; - } - ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src)); - if (ret < 0) - { - return ret; - } - op = coap_msg_get_first_op(src); - while (op != NULL) - { - ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op)); - if (ret < 0) - { - return ret; - } - op = coap_msg_op_get_next(op); - } - ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src)); - if (ret < 0) - { - return ret; - } - return 0; -} -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Coap/coap_msg.cpp Thu May 25 11:53:45 2017 +0000 @@ -0,0 +1,1024 @@ +/* + * 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_msg.c + * + * @brief Source file for the FreeCoAP message parser/formatter library + */ + +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <time.h> +#include <errno.h> +#include "coap_msg.h" +#include "coap_client.h" + +#define coap_msg_op_list_get_first(list) ((list)->first) /**< Get the first option from an option linked-list */ +#define coap_msg_op_list_get_last(list) ((list)->last) /**< Get the last option in an option linked-list */ +#define coap_msg_op_list_is_empty(list) ((list)->first == NULL) /**< Indicate whether or not an option linked-list is empty */ + +static int coap_msg_rand_init = 0; /**< Indicates whether or not the random number generator has been initialised */ + +void coap_msg_gen_rand_str(char *buf, size_t len) +{ + size_t i = 0; + + if (!coap_msg_rand_init) + { + srand(time(NULL)); + coap_msg_rand_init = 1; + } + for (i = 0; i < len; i++) + { + buf[i] = rand() & 0x000000ff; + } +} + +int coap_msg_op_num_is_recognized(unsigned num) +{ + switch (num) + { + case COAP_MSG_IF_MATCH: + case COAP_MSG_URI_HOST: + case COAP_MSG_ETAG: + case COAP_MSG_IF_NONE_MATCH: + case COAP_MSG_URI_PORT: + case COAP_MSG_LOCATION_PATH: + case COAP_MSG_URI_PATH: + case COAP_MSG_CONTENT_FORMAT: + case COAP_MSG_MAX_AGE: + case COAP_MSG_URI_QUERY: + case COAP_MSG_ACCEPT: + case COAP_MSG_LOCATION_QUERY: + case COAP_MSG_PROXY_URI: + case COAP_MSG_PROXY_SCHEME: + case COAP_MSG_SIZE1: + return 1; + } + return 0; +} + +/** + * @brief Allocate an option structure + * + * @param[in] num Option number + * @param[in] len Option length + * @param[in] val Pointer to the option value + * + * @returns Pointer to the option structure + * @retval NULL Out-of-memory + */ +static coap_msg_op_t *coap_msg_op_new(unsigned num, unsigned len, const char *val) +{ + coap_msg_op_t *op = NULL; + + op = (coap_msg_op_t *)malloc(sizeof(coap_msg_op_t)); + if (op == NULL) + { + return NULL; + } + op->num = num; + op->len = len; + op->val = (char *)malloc(len); + if (op->val == NULL) + { + free(op); + return NULL; + } + memcpy(op->val, val, len); + op->next = NULL; + return op; +} + +/** + * @brief Free an option structure that was allocated by coap_msg_op_new + * + * @param[in,out] op Pointer to the option structure + */ +static void coap_msg_op_delete(coap_msg_op_t *op) +{ + free(op->val); + free(op); +} + +/** + * @brief Initialise an option linked-list structure + * + * @param[out] list Pointer to an option linked-list structure + */ +static void coap_msg_op_list_create(coap_msg_op_list_t *list) +{ + memset(list, 0, sizeof(coap_msg_op_list_t)); +} + +/** + * @brief Deinitialise an option linked-list structure + * + * @param[in,out] list Pointer to an option linked-list structure + */ +static void coap_msg_op_list_destroy(coap_msg_op_list_t *list) +{ + coap_msg_op_t *prev = NULL; + coap_msg_op_t *op = NULL; + + op = list->first; + while (op != NULL) + { + prev = op; + op = op->next; + coap_msg_op_delete(prev); + } + memset(list, 0, sizeof(coap_msg_op_list_t)); +} + +/** + * @brief Allocate an option structure and add it to the end of an option linked-list structure + * + * @param[in,out] list Pointer to an option linked-list structure + * @param[in] num Option number + * @param[in] len Option length + * @param[in] val Pointer to a buffer containing the option value + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_msg_op_list_add_last(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) +{ + coap_msg_op_t *op = NULL; + + op = coap_msg_op_new(num, len, val); + if (op == NULL) + { + return -ENOMEM; + } + if (list->first == NULL) + { + list->first = op; + list->last = op; + } + else + { + list->last->next = op; + list->last = op; + } + return 0; +} + +/** + * @brief Allocate an option structure and add it to an option linked-list structure + * + * The option is added to the list at a position determined by the option number. + * + * @param[in,out] list Pointer to an option linked-list structure + * @param[in] num Option number + * @param[in] len Option length + * @param[in] val Pointer to a buffer containing the option value + * + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_msg_op_list_add(coap_msg_op_list_t *list, unsigned num, unsigned len, const char *val) +{ + coap_msg_op_t *prev = NULL; + coap_msg_op_t *op = NULL; + + op = coap_msg_op_new(num, len, val); + if (op == NULL) + { + return -ENOMEM; + } + if (list->first == NULL) + { + /* empty list */ + list->first = op; + list->last = op; + return 0; + } + if (op->num < list->first->num) + { + /* start of the list */ + op->next = list->first; + list->first = op; + return 0; + } + prev = list->first; + while (prev != list->last) + { + /* middle of the list */ + if ((prev->num <= op->num) && (op->num < prev->next->num)) + { + op->next = prev->next; + prev->next = op; + return 0; + } + prev = prev->next; + } + /* end of the list */ + list->last->next = op; + list->last = op; + return 0; +} + +void coap_msg_create(coap_msg_t *msg) +{ + memset(msg, 0, sizeof(coap_msg_t)); + msg->ver = COAP_MSG_VER; + coap_msg_op_list_create(&msg->op_list); +} + +void coap_msg_destroy(coap_msg_t *msg) +{ + coap_msg_op_list_destroy(&msg->op_list); + if (msg->payload != NULL) + { + free(msg->payload); + } + memset(msg, 0, sizeof(coap_msg_t)); +} + +void coap_msg_reset(coap_msg_t *msg) +{ + coap_msg_destroy(msg); + coap_msg_create(msg); +} + +/** + * @brief Check a message for correctness + * + * The following checks from RFC7252 are performed: + * + * An Empty message has the Code field set to 0.00. The Token Length + * field MUST be set to 0 and bytes of data MUST NOT be present after + * the Message ID field. If there are any bytes, they MUST be processed + * as a message format error. + * + * The Reset message MUST echo the Message ID of the Confirmable message + * and MUST be Empty. + * + * A Non-confirmable message always carries either a request or response + * and MUST NOT be Empty. + * + * @param[in] msg Pointer to a message structure + * @returns Operation status + * @retval 0 Success + * @retval <0 Error + */ +static int coap_msg_check(coap_msg_t *msg) +{ + if ((msg->code_class == 0) && (msg->code_detail == 0)) + { + /* empty message */ + if ((msg->type == COAP_MSG_NON) + || (msg->token_len != 0) + || (!coap_msg_op_list_is_empty(&msg->op_list)) + || (msg->payload_len != 0)) + { + return -EBADMSG; + } + } + else + { + /* non-empty message */ + if (msg->type == COAP_MSG_RST) + { + return -EBADMSG; + } + } + return 0; +} + +unsigned coap_msg_check_critical_ops(coap_msg_t *msg) +{ + coap_msg_op_t *op = NULL; + unsigned num = 0; + + op = coap_msg_get_first_op(msg); + while (op != NULL) + { + num = coap_msg_op_get_num(op); + if ((coap_msg_op_num_is_critical(num)) + && (!coap_msg_op_num_is_recognized(num))) + { + return num; /* fail */ + } + op = coap_msg_op_get_next(op); + } + return 0; /* pass */ +} + +unsigned coap_msg_check_unsafe_ops(coap_msg_t *msg) +{ + coap_msg_op_t *op = NULL; + unsigned num = 0; + + op = coap_msg_get_first_op(msg); + while (op != NULL) + { + num = coap_msg_op_get_num(op); + if ((coap_msg_op_num_is_unsafe(num)) + && (!coap_msg_op_num_is_recognized(num))) + { + return num; /* fail */ + } + op = coap_msg_op_get_next(op); + } + return 0; /* pass */ +} + +int coap_msg_parse_type_msg_id(char *buf, size_t len, unsigned *type, unsigned *msg_id) +{ + if (len < 4) + { + return -EBADMSG; + } + *type = (buf[0] >> 4) & 0x03; + *msg_id = ntohs(*((uint16_t *)(&buf[2]))); + return 0; +} + +/** + * @brief Parse the header in a message + * + * @param[out] msg Pointer to a message structure + * @param[in] buf Pointer to a buffer containing the message + * @param[in] len Length of the buffer + * + * @returns Number of bytes parsed or error code + * @retval >0 Number of bytes parsed + * @retval <0 Error + */ +static int coap_msg_parse_hdr(coap_msg_t *msg, char *buf, size_t len) +{ + char *p = buf; + + if (len < 4) + { + return -EBADMSG; + } + msg->ver = (p[0] >> 6) & 0x03; + if (msg->ver != COAP_MSG_VER) + { + return -EINVAL; + } + msg->type = (coap_msg_type_t)((p[0] >> 4) & 0x03); + msg->token_len = p[0] & 0x0f; + if (msg->token_len > sizeof(msg->token)) + { + return -EBADMSG; + } + msg->code_detail = p[1] & 0x1f; + msg->code_class = (p[1] >> 5) & 0x07; + if ((msg->code_class != COAP_MSG_REQ) + && (msg->code_class != COAP_MSG_SUCCESS) + && (msg->code_class != COAP_MSG_CLIENT_ERR) + && (msg->code_class != COAP_MSG_SERVER_ERR)) + { + return -EBADMSG; + } + msg->msg_id = ntohs(*((uint16_t *)(&p[2]))); + p += 4; + len -= 4; + return p - buf; +} + +/** + * @brief Parse the token in a message + * + * @param[out] msg Pointer to a message structure + * @param[in] buf Pointer to a buffer containing the message + * @param[in] len Length of the buffer + * + * @returns Number of bytes parsed or error code + * @retval >0 Number of bytes parsed + * @retval <0 Error + */ +static int coap_msg_parse_token(coap_msg_t *msg, char *buf, size_t len) +{ + if (len < msg->token_len) + { + return -EBADMSG; + } + memcpy(msg->token, buf, msg->token_len); + return msg->token_len; +} + +/** + * @brief Parse an option in a message + * + * @param[in,out] msg Pointer to a message structure + * @param[in] buf Pointer to a buffer containing the message + * @param[in] len Length of the buffer + * + * @returns Number of bytes parsed or error code + * @retval >0 Number of bytes parsed + * @retval <0 Error + */ +static int coap_msg_parse_op(coap_msg_t *msg, char *buf, size_t len) +{ + coap_msg_op_t *prev = NULL; + unsigned op_delta = 0; + unsigned op_len = 0; + unsigned op_num = 0; + char *p = buf; + int ret = 0; + + if (len < 1) + { + return -EBADMSG; + } + op_delta = (p[0] >> 4) & 0x0f; + op_len = p[0] & 0x0f; + if ((op_delta == 15) || (op_len == 15)) + { + return -EBADMSG; + } + p++; + len--; + if (op_delta == 13) + { + if (len < 1) + { + return -EBADMSG; + } + op_delta += p[0]; + p++; + len--; + } + else if (op_delta == 14) + { + if (len < 2) + { + return -EBADMSG; + } + op_delta = 269 + ntohs(*((uint16_t *)(&p[0]))); + p += 2; + len -= 2; + } + if (op_len == 13) + { + if (len < 1) + { + return -EBADMSG; + } + op_len += p[0]; + p++; + len--; + } + else if (op_len == 14) + { + if (len < 2) + { + return -EBADMSG; + } + op_len = 269 + ntohs(*((uint16_t *)(&p[0]))); + p += 2; + len -= 2; + } + if (len < op_len) + { + return -EBADMSG; + } + prev = coap_msg_op_list_get_last(&msg->op_list); + if (prev == NULL) + { + op_num = op_delta; + } + else + { + op_num = coap_msg_op_get_num(prev) + op_delta; + } + ret = coap_msg_op_list_add_last(&msg->op_list, op_num, op_len, p); + if (ret < 0) + { + return ret; + } + p += op_len; + return p - buf; +} + +/** + * @brief Parse the options in a message + * + * @param[in,out] msg Pointer to a message structure + * @param[in] buf Pointer to a buffer containing the message + * @param[in] len Length of the buffer + * + * @returns Number of bytes parsed or error code + * @retval >0 Number of bytes parsed + * @retval <0 Error + */ +static int coap_msg_parse_ops(coap_msg_t *msg, char *buf, size_t len) +{ + int num = 0; + char *p = buf; + + while (1) + { + if (((p[0] & 0xff) == 0xff) || (len == 0)) + { + break; + } + num = coap_msg_parse_op(msg, p, len); + if (num < 0) + { + return num; + } + p += num; + len -= num; + } + return p - buf; +} + +/** + * @brief Parse the payload in a message + * + * @param[out] msg Pointer to a message structure + * @param[in] buf Pointer to a buffer containing the message + * @param[in] len Length of the buffer + * + * @returns Number of bytes parsed or error code + * @retval >0 Number of bytes parsed + * @retval <0 Error + */ +static int coap_msg_parse_payload(coap_msg_t *msg, char *buf, size_t len) +{ + char *p = buf; + + if (len == 0) + { + return 0; + } + if ((p[0] & 0xff) != 0xff) + { + return -EBADMSG; + } + p++; + len--; + if (len == 0) + { + return -EBADMSG; + } + msg->payload = (char *)malloc(len); + if (msg->payload == NULL) + { + return -ENOMEM; + } + memcpy(msg->payload, p, len); + msg->payload_len = len; + p += len; + return p - buf; +} + +int coap_msg_parse(coap_msg_t *msg, char *buf, size_t len) +{ + int num = 0; + char *p = buf; + + coap_msg_reset(msg); + num = coap_msg_parse_hdr(msg, p, len); + if (num < 0) + { + coap_msg_destroy(msg); + return num; + } + p += num; + len -= num; + num = coap_msg_parse_token(msg, p, len); + if (num < 0) + { + coap_msg_destroy(msg); + return num; + } + p += num; + len -= num; + num = coap_msg_parse_ops(msg, p, len); + if (num < 0) + { + coap_msg_destroy(msg); + return num; + } + p += num; + len -= num; + num = coap_msg_parse_payload(msg, p, len); + if (num < 0) + { + coap_msg_destroy(msg); + return num; + } + return coap_msg_check(msg); +} + +int coap_msg_set_type(coap_msg_t *msg, unsigned type) +{ + if ((type != COAP_MSG_CON) + && (type != COAP_MSG_NON) + && (type != COAP_MSG_ACK) + && (type != COAP_MSG_RST)) + { + return -EINVAL; + } + msg->type = (coap_msg_type_t)type; + return 0; +} + +int coap_msg_set_code(coap_msg_t *msg, unsigned code_class, unsigned code_detail) +{ + if (code_class > COAP_MSG_MAX_CODE_CLASS) + { + return -EINVAL; + } + if (code_detail > COAP_MSG_MAX_CODE_DETAIL) + { + return -EINVAL; + } + msg->code_class = code_class; + msg->code_detail = code_detail; + return 0; +} + +int coap_msg_set_msg_id(coap_msg_t *msg, unsigned msg_id) +{ + if (msg_id > COAP_MSG_MAX_MSG_ID) + { + return -EINVAL; + } + msg->msg_id = msg_id; + return 0; +} + +int coap_msg_set_token(coap_msg_t *msg, char *buf, size_t len) +{ + if (len > COAP_MSG_MAX_TOKEN_LEN) + { + return -EINVAL; + } + memcpy(msg->token, buf, len); + msg->token_len = len; + return 0; +} + +int coap_msg_add_op(coap_msg_t *msg, unsigned num, unsigned len, const char *val) +{ + return coap_msg_op_list_add(&msg->op_list, num, len, val); +} + +int coap_msg_set_payload(coap_msg_t *msg, char *buf, size_t len) +{ + msg->payload_len = 0; + if (msg->payload != NULL) + { + free(msg->payload); + msg->payload = NULL; + } + if (len > 0) + { + msg->payload = (char *)malloc(len); + if (msg->payload == NULL) + { + return -ENOMEM; + } + memcpy(msg->payload, buf, len); + msg->payload_len = len; + } + return 0; +} + +/** + * @brief Format the header in a message + * + * @param[in] msg Pointer to a message structure + * @param[out] buf Pointer to a buffer to contain the formatted message + * @param[in] len Length of the buffer + * + * @returns Length of the formatted message or error code + * @retval >0 Length of the formatted message + * @retval <0 Error + */ +static int coap_msg_format_hdr(coap_msg_t *msg, char *buf, size_t len) +{ + uint16_t msg_id = 0; + + if (len < 4) + { + return -ENOSPC; + } + buf[0] = (char)((COAP_MSG_VER << 6) + | ((msg->type & 0x03) << 4) + | (msg->token_len & 0x0f)); + buf[1] = (char)(((msg->code_class & 0x07) << 5) + | (msg->code_detail & 0x1f)); + msg_id = htons(msg->msg_id); + memcpy(&buf[2], &msg_id, 2); + return 4; +} + +/** + * @brief Format the token in a message + * + * @param[in] msg Pointer to a message structure + * @param[out] buf Pointer to a buffer to contain the formatted message + * @param[in] len Length of the buffer + * + * @returns Length of the formatted message or error code + * @retval >0 Length of the formatted message + * @retval <0 Error + */ +static int coap_msg_format_token(coap_msg_t *msg, char *buf, size_t len) +{ + if (len < msg->token_len) + { + return -ENOSPC; + } + memcpy(buf, msg->token, msg->token_len); + return msg->token_len; +} + +/** + * @brief Format an option in a message + * + * @param[in] op Pointer to an option structure + * @param[in] prev_num option number of the previous option + * @param[out] buf Pointer to a buffer to contain the formatted message + * @param[in] len Length of the buffer + * + * @returns Length of the formatted message or error code + * @retval >0 Length of the formatted message + * @retval <0 Error + */ +static int coap_msg_format_op(coap_msg_op_t *op, unsigned prev_num, char *buf, size_t len) +{ + unsigned op_delta = 0; + unsigned num = 0; + uint16_t val = 0; + char *p = buf; + + op_delta = op->num - prev_num; + num++; + + /* option delta */ + if (op_delta >= 269) + { + num += 2; + } + else if (op_delta >= 13) + { + num += 1; + } + + /* option length */ + if (op->len >= 269) + { + num += 2; + } + else if (op->num >= 13) + { + num += 1; + } + + /* option value */ + num += op->len; + if (num > len) + { + return -ENOSPC; + } + + /* option delta */ + if (op_delta >= 269) + { + p[0] = 14 << 4; + } + else if (op_delta >= 13) + { + p[0] = 13 << 4; + } + else + { + p[0] = op_delta << 4; + } + + /* option length */ + if (op->len >= 269) + { + p[0] |= 14; + } + else if (op->len >= 13) + { + p[0] |= 13; + } + else + { + p[0] |= op->len; + } + p++; + len--; + + /* option delta extended */ + if (op_delta >= 269) + { + val = htons(op_delta - 269); + memcpy(p, &val, 2); + p += 2; + len -= 2; + } + else if (op_delta >= 13) + { + p[0] = op_delta - 13; + p++; + len--; + } + + /* option length extended */ + if (op->len >= 269) + { + val = htons(op->len - 269); + memcpy(p, &val, 2); + p += 2; + len -= 2; + } + else if (op->len >= 13) + { + p[0] = op->len - 13; + p++; + len--; + } + + /* option value */ + memcpy(p, op->val, op->len); + p += op->len; + + return p - buf; +} + +/** + * @brief Format the options in a message + * + * @param[in] msg Pointer to a message structure + * @param[out] buf Pointer to a buffer to contain the formatted message + * @param[in] len Length of the buffer + * + * @returns Length of the formatted message or error code + * @retval >0 Length of the formatted message + * @retval <0 Error + */ +static int coap_msg_format_ops(coap_msg_t *msg, char *buf, size_t len) +{ + coap_msg_op_t *op = NULL; + unsigned prev_num = 0; + int num = 0; + char *p = buf; + + op = coap_msg_op_list_get_first(&msg->op_list); + while (op != NULL) + { + num = coap_msg_format_op(op, prev_num, p, len); + if (num < 0) + { + return num; + } + p += num; + len -= num; + prev_num = coap_msg_op_get_num(op); + op = coap_msg_op_get_next(op); + } + return p - buf; +} + +/** + * @brief Format the payload in a message + * + * @param[in] msg Pointer to a message structure + * @param[out] buf Pointer to a buffer to contain the formatted message + * @param[in] len Length of the buffer + * + * @returns Length of the formatted message or error code + * @retval >0 Length of the formatted message + * @retval <0 Error + */ +static int coap_msg_format_payload(coap_msg_t *msg, char *buf, size_t len) +{ + if (msg->payload_len == 0) + { + return 0; + } + if (msg->payload_len + 1 > len) + { + return -ENOSPC; + } + buf[0] = 0xff; + memcpy(&buf[1], msg->payload, msg->payload_len); + return msg->payload_len + 1; +} + +int coap_msg_format(coap_msg_t *msg, char *buf, size_t len) +{ + int num = 0; + char *p = buf; + int ret = 0; + + ret = coap_msg_check(msg); + if (ret != 0) + { + return ret; + } + num = coap_msg_format_hdr(msg, p, len); + if (num < 0) + { + return num; + } + p += num; + len -= num; + num = coap_msg_format_token(msg, p, len); + if (num < 0) + { + return num; + } + p += num; + len -= num; + num = coap_msg_format_ops(msg, p, len); + if (num < 0) + { + return num; + } + p += num; + len -= num; + num = coap_msg_format_payload(msg, p, len); + if (num < 0) + { + return num; + } + p += num; + return p - buf; +} + +int coap_msg_copy(coap_msg_t *dst, coap_msg_t *src) +{ + coap_msg_op_t *op = NULL; + int ret = 0; + + dst->ver = src->ver; + ret = coap_msg_set_type(dst, coap_msg_get_type(src)); + if (ret < 0) + { + return ret; + } + ret = coap_msg_set_code(dst, coap_msg_get_code_class(src), coap_msg_get_code_detail(src)); + if (ret < 0) + { + return ret; + } + ret = coap_msg_set_msg_id(dst, coap_msg_get_msg_id(src)); + if (ret < 0) + { + return ret; + } + ret = coap_msg_set_token(dst, coap_msg_get_token(src), coap_msg_get_token_len(src)); + if (ret < 0) + { + return ret; + } + op = coap_msg_get_first_op(src); + while (op != NULL) + { + ret = coap_msg_add_op(dst, coap_msg_op_get_num(op), coap_msg_op_get_len(op), coap_msg_op_get_val(op)); + if (ret < 0) + { + return ret; + } + op = coap_msg_op_get_next(op); + } + ret = coap_msg_set_payload(dst, coap_msg_get_payload(src), coap_msg_get_payload_len(src)); + if (ret < 0) + { + return ret; + } + return 0; +} +
--- a/main.cpp Wed May 24 07:51:33 2017 +0000 +++ b/main.cpp Thu May 25 11:53:45 2017 +0000 @@ -7,10 +7,11 @@ #include "GPS.h" #include "MDM.h" #include "main.h" - +#include "coap_msg.h" +#include "coap_client.h" + extern "C" { - #include "coap_msg.h" - #include "coap_client.h" + #include "rtc_api.h" } // @@ -31,7 +32,7 @@ unsigned long ulGSMRxCntr=0, ulGSMTxCntr=0 ; //-- Asset unsigned long ulTotalRxCntr=0,ulTotalTxCntr=0; //-- Asset char caLssFinalAssetMsg[150]; -double dLatitude=0,dLongitude=0; +double dLatitude=31.47691,dLongitude=74.34259; static unsigned int uiWakeupCounter=0,uiWatchdogCounter=0; unsigned char ucBtteryLevel=0; MDMParser::DevStatus devStatus={}; @@ -43,6 +44,9 @@ //unsigned int uiAlarmIntervalCounter = 0; //unsigned int uiHeartBeatCounter = 0; + +char ucReturnCode[10]; //Return code array +int alarmtime = 1495698480;//2017-3-29-11:56:7 //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- /* @@ -50,7 +54,7 @@ { LPC_SC->PCONP |=1<1; //timer0 power on LPC_TIM0->MR0 = sec * 23980000; //1sec * sec - LPC_TIM0->MCR = 3; //interrupt and reset control + LPC_TIM0->MCR = 1; //interrupt and reset control //3 = Interrupt & reset timer0 on match //1 = Interrupt only, no reset of timer0 NVIC_EnableIRQ(TIMER0_IRQn); //enable timer0 interrupt @@ -63,33 +67,34 @@ if((LPC_TIM0->IR & 0x01) == 0x01) // if MR0 interrupt, proceed { LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag - - uiAlarmIntervalCounter++; - if(uiAlarmIntervalCounter >= 10)//20 sec - { - bAlarmIntervalFlag = true; - uiAlarmIntervalCounter = 0; - printf("Alarm Packet time...\r\n"); - } - - uiHeartBeatCounter++; - if(uiHeartBeatCounter >= 60)//2 min - { - bHeartBeatFlag = true; - uiHeartBeatCounter = 0; - printf("Heartbeat Packet time...\r\n"); - } + printf("Timer 0 interrupt generated 10 sec\r\n"); + LPC_TIM0->TCR = 0; } } */ //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- -void rtc_setup(void) +void rtc_setup(time_t t, unsigned int sec) { + struct tm *timeinfo = localtime(&t); + unsigned int min; + rtc_init(); - rtc_write(1490788567);//2017-3-29-11:56:7 + rtc_write(alarmtime);//2017-3-29-11:56:7 + + //min = sec/60; + //sec = sec%60; + //set alarm time + LPC_RTC->ALSEC = timeinfo->tm_sec+sec;//10 sec + //LPC_RTC->ALMIN = timeinfo->tm_min+min;//10 sec + + LPC_RTC->AMR &= (~(1 << 0)) & 0xFF; + + LPC_RTC->ILR = (1 << 0) | (1 << 1); + + printf("RTC Alarm Time Set\r\n"); NVIC_EnableIRQ(RTC_IRQn); @@ -130,7 +135,7 @@ MDMSerial mdm; gmdm = &mdm; us_ticker_init(); - //timer0_init(2); + while(1) { @@ -142,10 +147,8 @@ if(bSendingDataFlag)//&& bAlarmIntervalFlag) { //bAlarmIntervalFlag = false; - unsigned int counter = 50; - while( (ret = gps.getMessage(buf, sizeof(buf))) > 0 || counter > 0) + while( (ret = gps.getMessage(buf, sizeof(buf))) > 0) { - counter--; int len = LENGTH(ret); ulGPSRxCntr = len; if( (PROTOCOL(ret)==GPSParser::NMEA) && (len > 6) ) @@ -200,13 +203,13 @@ sprintf( caLssFinalAssetMsg, "$AQLSS,02,%s,%s*xx",devStatus.imei,devStatus.imsi); printf( "HeartBeat: %s\r\n", caLssFinalAssetMsg ); } - + ssocket = mdm.socketSocket(MDMParser::IPPROTO_UDP, pport); if( ssocket >= 0 ) { mdm.socketSetBlocking(ssocket, 10); ipp = 0x97092263;//0x052753CE; - if (PASS == test_exchange_func(caLssFinalAssetMsg,strlen(caLssFinalAssetMsg))) + if (PASS == test_exchange_func(caLssFinalAssetMsg,strlen(caLssFinalAssetMsg),ucReturnCode)) { printf("\r\n-----------------<pass>-----------------\n"); } @@ -215,22 +218,26 @@ mdm.socketFree(ssocket); responce_checker(); - } + } mdm.disconnect(); - mdm.powerOff(); + /*mdm.powerOff();*/ + if(bSleepModeFlag) { - rtc_setup(); - hal_deepsleep(); - //sleep_mode(); - //uiWakeupCounter++; + rtc_setup(alarmtime,10); + printf("Enter Sleep Mode\r\n"); + hal_sleep(); + printf("Exit Sleep Mode\r\n"); + myled = !myled; + uiWakeupCounter++; } - if(bSendingDataFlag) + + /*if(bSendingDataFlag) wait( 10 ); else wait( 60 ); - myled = !myled; + myled = !myled;*/ } //} } @@ -295,17 +302,9 @@ printf("Ussd Got Answer: \"%s\"\r\n", buffer); } */ -void sleep_mode(void) -{ - /* Deep-Sleep Mode, set SLEEPDEEP bit */ - //SCB->SCR |= 0x4; - LPC_SC->PCON = 0x9; - __WFI(); - //SystemInit(); -} void responce_checker(void) -{/* +{ if(!strcmp((const char*)ucReturnCode,"RC 000")) { printf("Acknowledged RC 000\r\n"); @@ -350,5 +349,5 @@ else if(!strcmp((const char*)ucReturnCode,"EC 002")) { printf("Error Code 002 Received Payload is corrupted\r\n"); - }*/ + } }