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.
Dependencies: C027_Support mbed-dev
Fork of C027_SupportTest_coap by
coap_client.cpp
00001 /* 00002 * Copyright (c) 2015 Keith Cullen. 00003 * All Rights Reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. The name of the author may not be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 00017 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00018 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00019 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00020 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00021 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 00022 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00023 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 00025 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /** 00029 * @file coap_client.c 00030 * 00031 * @brief Source file for the FreeCoAP client library 00032 */ 00033 00034 #include <stdlib.h> 00035 #include <stdio.h> 00036 #include <string.h> 00037 #include <stdint.h> 00038 #include <errno.h> 00039 00040 #include "coap_client.h" 00041 #include "main.h" 00042 00043 #define COAP_CLIENT_ACK_TIMEOUT_SEC 2 /**< Minimum delay to wait before retransmitting a confirmable message */ 00044 #define COAP_CLIENT_MAX_RETRANSMIT 4 /**< Maximum number of times a confirmable message can be retransmitted */ 00045 #define COAP_CLIENT_RESP_TIMEOUT_SEC 30 /**< Maximum amount of time to wait for a response */ 00046 00047 /**************************************************************************************************** 00048 * coap_client * 00049 ****************************************************************************************************/ 00050 void coap_client_destroy(coap_client_t *client) 00051 { 00052 memset(client, 0, sizeof(coap_client_t)); 00053 } 00054 00055 /** 00056 * @brief Send a message to the server 00057 * 00058 * @param[in,out] client Pointer to a client structure 00059 * @param[in] msg Pointer to a message structure 00060 * 00061 * @returns Number of bytes sent or error code 00062 * @retval >0 Number of bytes sent 00063 * @retval <0 Error 00064 */ 00065 static int coap_client_send(coap_client_t *client, coap_msg_t *msg) 00066 { 00067 int num = 0; 00068 char buf[COAP_MSG_MAX_BUF_LEN] = {0}; 00069 00070 num = coap_msg_format(msg, buf, sizeof(buf)); 00071 if (num < 0) 00072 { 00073 return num; 00074 } 00075 num = send(client->sd, buf, num); 00076 if (num < 0) 00077 { 00078 printf("send error\n"); 00079 return -errno; 00080 } 00081 00082 return num; 00083 } 00084 00085 /** 00086 * @brief Handle a format error in a received message 00087 * 00088 * Special handling for the case where a received 00089 * message could not be parsed due to a format error. 00090 * Extract enough information from the received message 00091 * to form a reset message. 00092 * 00093 * @param[in,out] client Pointer to a client structure 00094 * @param[in] buf Buffer containing the message 00095 * @param[in] len length of the buffer 00096 */ 00097 static void coap_client_handle_format_error(coap_client_t *client, char *buf, size_t len) 00098 { 00099 coap_msg_t msg = {0}; 00100 unsigned msg_id = 0; 00101 unsigned type = 0; 00102 int ret = 0; 00103 00104 ret = coap_msg_parse_type_msg_id(buf, len, &type, &msg_id); 00105 if ((ret == 0) && (type == COAP_MSG_CON)) 00106 { 00107 coap_msg_create(&msg); 00108 ret = coap_msg_set_type(&msg, COAP_MSG_RST); 00109 if (ret < 0) 00110 { 00111 coap_msg_destroy(&msg); 00112 return; 00113 } 00114 ret = coap_msg_set_msg_id(&msg, msg_id); 00115 if (ret < 0) 00116 { 00117 coap_msg_destroy(&msg); 00118 return; 00119 } 00120 coap_client_send(client, &msg); 00121 coap_msg_destroy(&msg); 00122 } 00123 } 00124 00125 /** 00126 * @brief Receive a message from the server 00127 * 00128 * @param[in,out] client Pointer to a client structure 00129 * @param[in] msg Pointer to a message structure 00130 * 00131 * @returns Number of bytes received or error code 00132 * @retval >0 Number of bytes received 00133 * @retval <0 Error 00134 */ 00135 static int coap_client_recv(coap_client_t *client, coap_msg_t *msg) 00136 { 00137 int num = 0; 00138 int ret = 0; 00139 char buf[COAP_MSG_MAX_BUF_LEN] = {0}; 00140 00141 num = recv(client->sd, buf, sizeof(buf)); 00142 if (num < 0) 00143 { 00144 return -errno; 00145 } 00146 00147 ret = coap_msg_parse(msg, buf, num); 00148 if (ret < 0) 00149 { 00150 if (ret == -EBADMSG) 00151 { 00152 coap_client_handle_format_error(client, buf, num); 00153 } 00154 return ret; 00155 } 00156 return num; 00157 } 00158 00159 /** 00160 * @brief Reject a received confirmable message 00161 * 00162 * Send a reset message to the server. 00163 * 00164 * @param[in,out] client Pointer to a client structure 00165 * @param[in] msg Pointer to a message structure 00166 * 00167 * @returns Operation status 00168 * @retval 0 Success 00169 * @retval <0 Error 00170 */ 00171 static int coap_client_reject_con(coap_client_t *client, coap_msg_t *msg) 00172 { 00173 coap_msg_t rej = {0}; 00174 int num = 0; 00175 int ret = 0; 00176 00177 printf("Rejecting confirmable message from host %s and port %s\n", client->server_host, client->server_port); 00178 coap_msg_create(&rej); 00179 ret = coap_msg_set_type(&rej, COAP_MSG_RST); 00180 if (ret < 0) 00181 { 00182 coap_msg_destroy(&rej); 00183 return ret; 00184 } 00185 ret = coap_msg_set_msg_id(&rej, coap_msg_get_msg_id(msg)); 00186 if (ret < 0) 00187 { 00188 coap_msg_destroy(&rej); 00189 return ret; 00190 } 00191 num = coap_client_send(client, &rej); 00192 coap_msg_destroy(&rej); 00193 if (num < 0) 00194 { 00195 return num; 00196 } 00197 return 0; 00198 } 00199 00200 /** 00201 * @brief Reject a received non-confirmable message 00202 * 00203 * @param[in] client Pointer to a client structure 00204 * @param[in] msg Pointer to a message structure 00205 * 00206 * @returns Operation status 00207 * @retval 0 Success 00208 */ 00209 static int coap_client_reject_non(coap_client_t *client, coap_msg_t *msg) 00210 { 00211 printf("Rejecting non-confirmable message from host %s and port %s\n", client->server_host, client->server_port); 00212 return 0; 00213 } 00214 00215 /** 00216 * @brief Reject a received acknowledgement message 00217 * 00218 * @param[in] client Pointer to a client structure 00219 * @param[in] msg Pointer to a message structure 00220 * 00221 * @returns Operation status 00222 * @retval 0 Success 00223 */ 00224 static int coap_client_reject_ack(coap_client_t *client, coap_msg_t *msg) 00225 { 00226 printf("Rejecting acknowledgement message from host %s and port %s\n", client->server_host, client->server_port); 00227 return 0; 00228 } 00229 00230 /** 00231 * @brief Reject a received reset message 00232 * 00233 * @param[in] client Pointer to a client structure 00234 * @param[in] msg Pointer to a message structure 00235 * 00236 * @returns Operation status 00237 * @retval 0 Success 00238 */ 00239 static int coap_client_reject_reset(coap_client_t *client, coap_msg_t *msg) 00240 { 00241 printf("Rejecting reset message from host %s and port %s\n", client->server_host, client->server_port); 00242 return 0; 00243 } 00244 00245 /** 00246 * @brief Reject a received message 00247 * 00248 * @param[in,out] client Pointer to a client structure 00249 * @param[in] msg Pointer to a message structure 00250 * 00251 * @returns Operation status 00252 * @retval 0 Success 00253 * @retval <0 Error 00254 */ 00255 static int coap_client_reject(coap_client_t *client, coap_msg_t *msg) 00256 { 00257 if (coap_msg_get_type(msg) == COAP_MSG_CON) 00258 { 00259 return coap_client_reject_con(client, msg); 00260 } 00261 else if (coap_msg_get_type(msg) == COAP_MSG_NON) 00262 { 00263 return coap_client_reject_non(client, msg); 00264 } 00265 else if (coap_msg_get_type(msg) == COAP_MSG_ACK) 00266 { 00267 return coap_client_reject_ack(client, msg); 00268 } 00269 else if (coap_msg_get_type(msg) == COAP_MSG_RST) 00270 { 00271 return coap_client_reject_reset(client, msg); 00272 } 00273 return 0; /* should never arrive here */ 00274 } 00275 00276 /** 00277 * @brief Send an acknowledgement message to the server 00278 * 00279 * @param[in,out] client Pointer to a client structure 00280 * @param[in] msg Pointer to a message structure 00281 * 00282 * @returns Operation status 00283 * @retval 0 Success 00284 * @retval <0 Error 00285 */ 00286 static int coap_client_send_ack(coap_client_t *client, coap_msg_t *msg) 00287 { 00288 coap_msg_t ack = {0}; 00289 int num = 0; 00290 int ret = 0; 00291 00292 printf("Acknowledging confirmable message from host %s and port %s\n", client->server_host, client->server_port); 00293 coap_msg_create(&ack); 00294 ret = coap_msg_set_type(&ack, COAP_MSG_ACK); 00295 if (ret < 0) 00296 { 00297 coap_msg_destroy(&ack); 00298 return ret; 00299 } 00300 ret = coap_msg_set_msg_id(&ack, coap_msg_get_msg_id(msg)); 00301 if (ret < 0) 00302 { 00303 coap_msg_destroy(&ack); 00304 return ret; 00305 } 00306 num = coap_client_send(client, &ack); 00307 coap_msg_destroy(&ack); 00308 if (num < 0) 00309 { 00310 return num; 00311 } 00312 return 0; 00313 } 00314 00315 /** 00316 * @brief Compare the token values in a request message and a response message 00317 * 00318 * @param[in] req Pointer to the request message 00319 * @param[in] resp Pointer to the response message 00320 * 00321 * @returns Comparison value 00322 * @retval 0 the tokens are not equal 00323 * @retval 1 the tokens are equal 00324 */ 00325 static int coap_client_match_token(coap_msg_t *req, coap_msg_t *resp) 00326 { 00327 return ((coap_msg_get_token_len(resp) == coap_msg_get_token_len(req)) 00328 && (memcmp(coap_msg_get_token(resp), coap_msg_get_token(req), coap_msg_get_token_len(req)) == 0)); 00329 } 00330 00331 /** 00332 * @brief Check that all of the options in a message are acceptable 00333 * 00334 * For a proxy, options are acceptable if they are safe to forward or recognized or both. 00335 * For a server, options are acceptable if they are elective or recognized or both. 00336 * 00337 * @param[in] msg Pointer to message structure 00338 * 00339 * @returns Operation status or bad option number 00340 * @retval 0 Success 00341 * @retval >0 Bad option number 00342 */ 00343 static unsigned coap_client_check_options(coap_msg_t *msg) 00344 { 00345 #ifdef COAP_PROXY 00346 return coap_msg_check_unsafe_ops(msg); 00347 #else /* !COAP_PROXY */ 00348 return coap_msg_check_critical_ops(msg); 00349 #endif /* COAP_PROXY */ 00350 } 00351 00352 /** 00353 * @brief Handle a received piggy-backed response message 00354 * 00355 * An acknowledgement has been received that contains 00356 * the same token as the request. Check the response 00357 * contained within it. 00358 * 00359 * @param[in,out] client Pointer to a client structure 00360 * @param[in] resp Pointer to the response message 00361 * 00362 * @returns Operation status 00363 * @retval 0 Success 00364 * @retval <0 Error 00365 */ 00366 static int coap_client_handle_piggybacked_response(coap_client_t *client, coap_msg_t *resp) 00367 { 00368 unsigned op_num = 0; 00369 00370 op_num = coap_client_check_options(resp); 00371 if (op_num != 0) 00372 { 00373 printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); 00374 coap_client_reject(client, resp); 00375 return -EBADMSG; 00376 } 00377 printf("Received acknowledgement and response from Server\n"); 00378 return 0; 00379 } 00380 00381 /** 00382 * @brief Handle a received separate response message 00383 * 00384 * A separate response has been received that contains 00385 * the same token as the request. Check the response 00386 * and send an acknowledgement if necessary. 00387 * 00388 * @param[in,out] client Pointer to a client structure 00389 * @param[in] resp Pointer to the response message 00390 * 00391 * @returns Operation status 00392 * @retval 0 Success 00393 * @retval <0 Error 00394 */ 00395 static int coap_client_handle_sep_response(coap_client_t *client, coap_msg_t *resp) 00396 { 00397 unsigned op_num = 0; 00398 00399 if (coap_msg_get_type(resp) == COAP_MSG_CON) 00400 { 00401 printf("Received confirmable response from host %s and port %s\n", client->server_host, client->server_port); 00402 op_num = coap_client_check_options(resp); 00403 if (op_num != 0) 00404 { 00405 printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); 00406 coap_client_reject(client, resp); 00407 return -EBADMSG; 00408 } 00409 return coap_client_send_ack(client, resp); 00410 } 00411 else if (coap_msg_get_type(resp) == COAP_MSG_NON) 00412 { 00413 printf("Received non-confirmable response from host %s and port %s\n", client->server_host, client->server_port); 00414 op_num = coap_client_check_options(resp); 00415 if (op_num != 0) 00416 { 00417 printf("Found bad option number %u in message from host %s and port %s\n", op_num, client->server_host, client->server_port); 00418 coap_client_reject(client, resp); 00419 return -EBADMSG; 00420 } 00421 return 0; 00422 } 00423 coap_client_reject(client, resp); 00424 return -EBADMSG; 00425 } 00426 00427 /** 00428 * @brief Handle a separate response to a confirmable request 00429 * 00430 * An acknowledgement has been received. Receive the 00431 * response and send an acknowledgement back to the server. 00432 * 00433 * @param[in,out] client Pointer to a client structure 00434 * @param[in] req Pointer to the request message 00435 * @param[out] resp Pointer to the response message 00436 * 00437 * @returns Operation status 00438 * @retval 0 Success 00439 * @retval <0 Error 00440 */ 00441 static int coap_client_exchange_sep(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) 00442 { 00443 int num = 0; 00444 int ret = 0; 00445 int starttimeout,endtimeout; 00446 00447 /* wait for a separate response to a confirmable request */ 00448 printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); 00449 while (1) 00450 { 00451 starttimeout = readseconds(); 00452 while(1) 00453 { 00454 num = coap_client_recv(client, resp); 00455 if (num < 0) 00456 { 00457 return num; 00458 } 00459 else if(num > 0) 00460 { 00461 break; 00462 } 00463 endtimeout = readseconds(); 00464 if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC) 00465 { 00466 printf("Timeout no data received\n"); 00467 return -1; 00468 } 00469 } 00470 00471 if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) 00472 { 00473 if (coap_msg_get_type(resp) == COAP_MSG_ACK) 00474 { 00475 /* message deduplication */ 00476 printf("Received duplicate acknowledgement from host %s and port %s\n", client->server_host, client->server_port); 00477 continue; 00478 } 00479 else if (coap_msg_get_type(resp) == COAP_MSG_RST) 00480 { 00481 return -ECONNRESET; 00482 } 00483 coap_client_reject(client, resp); 00484 return -EBADMSG; 00485 } 00486 if (coap_client_match_token(req, resp)) 00487 { 00488 return coap_client_handle_sep_response(client, resp); 00489 } 00490 /* message deduplication */ 00491 /* we might have received a duplicate message that was already received from the same server */ 00492 /* reject the message and continue listening */ 00493 ret = coap_client_reject(client, resp); 00494 if (ret < 0 ) 00495 { 00496 return ret; 00497 } 00498 } 00499 return 0; 00500 } 00501 00502 /** 00503 * @brief Handle the response to a confirmable request 00504 * 00505 * A confirmable request has been sent to the server. 00506 * Receive the acknowledgement and response. Send an 00507 * acknowledgement if necessary. 00508 * 00509 * @param[in,out] client Pointer to a client structure 00510 * @param[in] req Pointer to the request message 00511 * @param[out] resp Pointer to the response message 00512 * 00513 * @returns Operation status 00514 * @retval 0 Success 00515 * @retval <0 Error 00516 */ 00517 static int coap_client_exchange_con(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) 00518 { 00519 int num = 0; 00520 int ret = 0; 00521 int starttimeout,endtimeout; 00522 /* wait for piggy-backed response in ack message 00523 * or ack message and separate response message 00524 */ 00525 //printf("Expecting acknowledgement from server\r\n"); 00526 client->num_retrans = 0; 00527 while (1) 00528 { 00529 int doubletimeout = COAP_CLIENT_ACK_TIMEOUT_SEC; 00530 starttimeout = readseconds(); 00531 while(1) 00532 { 00533 num = coap_client_recv(client, resp); 00534 if (num < 0) 00535 { 00536 //return num; 00537 } 00538 else if(num > 0) 00539 { 00540 break; 00541 } 00542 endtimeout = readseconds(); 00543 if((endtimeout - starttimeout) > doubletimeout) 00544 { 00545 printf("Timeout no data received after %d seconds\n",endtimeout - starttimeout); 00546 00547 if (client->num_retrans >= COAP_CLIENT_MAX_RETRANSMIT) 00548 { 00549 printf("Maximum retries reached no ack from server!\r\n"); 00550 return -ETIMEDOUT; 00551 } 00552 00553 doubletimeout = 2 * doubletimeout; 00554 starttimeout = readseconds(); 00555 client->num_retrans++; 00556 00557 printf("Retransmitting to server...\r\n"); 00558 num = coap_client_send(client, req); 00559 if (num < 0) 00560 { 00561 printf("Resending Failed to server...\r\n"); 00562 return num; 00563 } 00564 } 00565 } 00566 00567 if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) 00568 { 00569 if (coap_msg_get_type(resp) == COAP_MSG_ACK) 00570 { 00571 if (coap_msg_is_empty(resp)) 00572 { 00573 /* received ack message, wait for separate response message */ 00574 printf("Received acknowledgement from host %s and port %s\n", client->server_host, client->server_port); 00575 return coap_client_exchange_sep(client, req, resp); 00576 } 00577 else if (coap_client_match_token(req, resp)) 00578 { 00579 return coap_client_handle_piggybacked_response(client, resp); 00580 } 00581 } 00582 else if (coap_msg_get_type(resp) == COAP_MSG_RST) 00583 { 00584 return -ECONNRESET; 00585 } 00586 coap_client_reject(client, resp); 00587 return -EBADMSG; 00588 } 00589 else if (coap_client_match_token(req, resp)) 00590 { 00591 /* RFC7252 00592 * as the underlying datagram transport may not be sequence-preserving, 00593 * the Confirmable message carrying the response may actually arrive 00594 * before or after the Acknowledgement message for the request; for 00595 * the purposes of terminating the retransmission sequence, this also 00596 * serves as an acknowledgement. 00597 */ 00598 return coap_client_handle_sep_response(client, resp); 00599 } 00600 /* message deduplication */ 00601 /* we might have received a duplicate message that was already received from the same server */ 00602 /* reject the message and continue listening */ 00603 ret = coap_client_reject(client, resp); 00604 if (ret < 0 ) 00605 { 00606 return ret; 00607 } 00608 } 00609 return 0; 00610 } 00611 00612 /** 00613 * @brief Handle the response to a non-confirmable request 00614 * 00615 * A non-confirmable request has been sent to the server. 00616 * Receive the response. 00617 * 00618 * @param[in,out] client Pointer to a client structure 00619 * @param[in] req Pointer to the request message 00620 * @param[out] resp Pointer to the response message 00621 * 00622 * @returns Operation status 00623 * @retval 0 Success 00624 * @retval <0 Error 00625 **/ 00626 static int coap_client_exchange_non(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) 00627 { 00628 int num = 0; 00629 int ret = 0; 00630 int starttimeout,endtimeout; 00631 00632 printf("Expecting response from host %s and port %s\n", client->server_host, client->server_port); 00633 while (1) 00634 { 00635 starttimeout = readseconds(); 00636 while(1) 00637 { 00638 num = coap_client_recv(client, resp); 00639 if (num < 0) 00640 { 00641 return num; 00642 } 00643 else if(num > 0) 00644 { 00645 break; 00646 } 00647 endtimeout = readseconds(); 00648 if((endtimeout - starttimeout) > COAP_CLIENT_RESP_TIMEOUT_SEC) 00649 { 00650 printf("Timeout no data received\n"); 00651 return -1; 00652 } 00653 } 00654 00655 if (coap_msg_get_msg_id(resp) == coap_msg_get_msg_id(req)) 00656 { 00657 if (coap_msg_get_type(resp) == COAP_MSG_RST) 00658 { 00659 return -ECONNRESET; 00660 } 00661 coap_client_reject(client, resp); 00662 return -EBADMSG; 00663 } 00664 if (coap_client_match_token(req, resp)) 00665 { 00666 return coap_client_handle_sep_response(client, resp); 00667 } 00668 /* message deduplication */ 00669 /* we might have received a duplicate message that was already received from the same server */ 00670 /* reject the message and continue listening */ 00671 ret = coap_client_reject(client, resp); 00672 if (ret < 0 ) 00673 { 00674 return ret; 00675 } 00676 } 00677 return 0; 00678 } 00679 00680 int coap_client_exchange(coap_client_t *client, coap_msg_t *req, coap_msg_t *resp) 00681 { 00682 unsigned char msg_id_buf[2] = {0}; 00683 unsigned msg_id = 0; 00684 int num = 0; 00685 char token[4] = {0}; 00686 int ret = 0; 00687 00688 /* check for a valid request */ 00689 if ((coap_msg_get_type(req) == COAP_MSG_ACK) 00690 || (coap_msg_get_type(req) == COAP_MSG_RST) 00691 || (coap_msg_get_code_class(req) != COAP_MSG_REQ)) 00692 { 00693 return -EINVAL; 00694 } 00695 00696 /* generate the message ID */ 00697 coap_msg_gen_rand_str((char *)msg_id_buf, sizeof(msg_id_buf)); 00698 msg_id = (((unsigned)msg_id_buf[1]) << 8) | (unsigned)msg_id_buf[0]; 00699 ret = coap_msg_set_msg_id(req, msg_id); 00700 if (ret < 0) 00701 { 00702 return ret; 00703 } 00704 00705 /* generate the token */ 00706 coap_msg_gen_rand_str(token, sizeof(token)); 00707 ret = coap_msg_set_token(req, token, sizeof(token)); 00708 if (ret < 0) 00709 { 00710 return ret; 00711 } 00712 00713 num = coap_client_send(client, req); 00714 if (num < 0) 00715 { 00716 return num; 00717 } 00718 00719 if (coap_msg_get_type(req) == COAP_MSG_CON) 00720 { 00721 return coap_client_exchange_con(client, req, resp); 00722 } 00723 else if (coap_msg_get_type(req) == COAP_MSG_NON) 00724 { 00725 return coap_client_exchange_non(client, req, resp); 00726 } 00727 return -EINVAL; 00728 } 00729 //---------------------------------------------------------------------------------------------------------------------- 00730 //---------------------------------------------------------------------------------------------------------------------- 00731 /** 00732 * @brief Test an exchange with the server 00733 * 00734 * @param[in] data Pointer to a client test data structure 00735 * 00736 * @returns Test result 00737 */ 00738 test_result_t test_exchange_func(char* buf,int buf_len,char* returncode) 00739 { 00740 printf("----------------------------------------\n"); 00741 test_result_t result = PASS; 00742 coap_client_t client = {0}; 00743 coap_msg_t resp = {0}; 00744 coap_msg_t req = {0}; 00745 int ret = 0; 00746 00747 test_coap_client_msg_op_t req_ops; 00748 req_ops.num = COAP_MSG_URI_PATH; 00749 req_ops.len = 8; 00750 req_ops.val = (char*)"resource"; 00751 00752 test_coap_client_msg_op_t resp_ops; 00753 resp_ops.num = 0; 00754 resp_ops.len = 0; 00755 resp_ops.val = 0; 00756 00757 test_coap_client_msg_t test1_req; 00758 test1_req.type = COAP_MSG_CON; 00759 test1_req.code_class = COAP_MSG_REQ; 00760 test1_req.code_detail = COAP_MSG_GET; 00761 test1_req.ops = req_ops; 00762 test1_req.num_ops = 1; 00763 test1_req.payload = buf; 00764 test1_req.payload_len = buf_len; 00765 00766 test_coap_client_msg_t test1_resp; 00767 test1_resp.type = COAP_MSG_ACK; 00768 test1_resp.code_class = COAP_MSG_SUCCESS; 00769 test1_resp.code_detail = COAP_MSG_CONTENT; 00770 test1_resp.ops = resp_ops; 00771 test1_resp.num_ops = 0; 00772 test1_resp.payload = (char*)"Hello Client!"; 00773 test1_resp.payload_len = 13; 00774 00775 test_coap_client_data_t test1_data; 00776 test1_data.desc = "Send a confirmable request to server and expect a piggy-backed response"; 00777 test1_data.host = HOST; 00778 test1_data.port = PORT; 00779 test1_data.common_name = (char*)"dummy/server"; 00780 test1_data.test_req = test1_req; 00781 test1_data.test_resp = test1_resp; 00782 test1_data.num_msg = 1; 00783 00784 //printf("%s\n", test1_data.desc); 00785 00786 if (ret < 0) 00787 { 00788 printf("Error : %s\n",strerror(-ret)); 00789 return FAIL; 00790 } 00791 00792 coap_msg_create(&req); 00793 coap_msg_create(&resp); 00794 00795 ret = exchange(&client, &test1_data.test_req, &req, &resp,returncode); 00796 //printf("exchange function\n"); 00797 if (ret != PASS) 00798 { 00799 printf("exchange function fail\n"); 00800 coap_msg_destroy(&resp); 00801 coap_msg_destroy(&req); 00802 coap_client_destroy(&client); 00803 return FAIL; 00804 } 00805 00806 ret = compare_ver_token(&req, &resp); 00807 if (ret != PASS) 00808 { 00809 coap_msg_destroy(&resp); 00810 coap_msg_destroy(&req); 00811 coap_client_destroy(&client); 00812 return FAIL; 00813 } 00814 00815 ret = check_resp(&test1_data.test_resp, &resp); 00816 if (ret != PASS) 00817 { 00818 coap_msg_destroy(&resp); 00819 coap_msg_destroy(&req); 00820 coap_client_destroy(&client); 00821 return FAIL; 00822 } 00823 00824 coap_msg_destroy(&resp); 00825 coap_msg_destroy(&req); 00826 coap_client_destroy(&client); 00827 00828 return result; 00829 } 00830 //---------------------------------------------------------------------------------------------------------------------- 00831 //---------------------------------------------------------------------------------------------------------------------- 00832 /** 00833 * @brief Print a CoAP message 00834 * 00835 * @param[in] str String to be printed before the message 00836 * @param[in] msg Pointer to a message structure 00837 */ 00838 void print_coap_msg(const char *str, coap_msg_t *msg,char* returncode) 00839 { 00840 //coap_msg_op_t *op = NULL; 00841 //unsigned num = 0; 00842 //unsigned len = 0; 00843 unsigned i = 0; 00844 //unsigned j = 0; 00845 char *payload = NULL; 00846 char *token = NULL; 00847 //char *val = NULL; 00848 00849 printf("%s\n", str); 00850 printf("ver: 0x%02x\n", coap_msg_get_ver(msg)); 00851 printf("type: 0x%02x\n", coap_msg_get_type(msg)); 00852 printf("token_len: %d\n", coap_msg_get_token_len(msg)); 00853 printf("code_class: %d\n", coap_msg_get_code_class(msg)); 00854 printf("code_detail: %d\n", coap_msg_get_code_detail(msg)); 00855 printf("msg_id: 0x%04x\n", coap_msg_get_msg_id(msg)); 00856 printf("token: "); 00857 token = coap_msg_get_token(msg); 00858 for (i = 0; i < coap_msg_get_token_len(msg); i++) 00859 { 00860 printf(" 0x%02x", (unsigned char)token[i]); 00861 } 00862 printf("\n"); 00863 /*op = coap_msg_get_first_op(msg); 00864 while (op != NULL) 00865 { 00866 num = coap_msg_op_get_num(op); 00867 len = coap_msg_op_get_len(op); 00868 val = coap_msg_op_get_val(op); 00869 printf("op[%u].num: %u\n", j, num); 00870 printf("op[%u].len: %u\n", j, len); 00871 printf("op[%u].val: ", j); 00872 for (i = 0; i < len; i++) 00873 { 00874 printf(" 0x%02x", (unsigned char)val[i]); 00875 } 00876 printf("\n"); 00877 op = coap_msg_op_get_next(op); 00878 j++; 00879 }*/ 00880 printf("payload: "); 00881 payload = coap_msg_get_payload(msg); 00882 00883 if(strcmp(str,"Received:") == 0) 00884 { 00885 for (i = 0; i < coap_msg_get_payload_len(msg); i++) 00886 { 00887 printf("%c", payload[i]); 00888 returncode[i] = payload[i]; 00889 } 00890 returncode[i] = '\0'; 00891 } 00892 printf("\n"); 00893 00894 printf("payload_len: %zu\n", coap_msg_get_payload_len(msg)); 00895 } 00896 //---------------------------------------------------------------------------------------------------------------------- 00897 //---------------------------------------------------------------------------------------------------------------------- 00898 /** 00899 * @brief Populate a request message with details from a test request message structure 00900 * 00901 * @param[in] test_req Pointer to a test request message structure 00902 * @param[out] req Pointer to a request message structure 00903 * 00904 * @returns Test result 00905 */ 00906 test_result_t populate_req(test_coap_client_msg_t *test_req, coap_msg_t *req) 00907 { 00908 int ret = 0; 00909 00910 ret = coap_msg_set_type(req, test_req->type); 00911 if (ret < 0) 00912 { 00913 printf("Error : %s\n",strerror(-ret)); 00914 return FAIL; 00915 } 00916 ret = coap_msg_set_code(req, test_req->code_class, test_req->code_detail); 00917 if (ret < 0) 00918 { 00919 printf("Error : %s\n",strerror(-ret)); 00920 return FAIL; 00921 } 00922 ret = coap_msg_add_op(req, test_req->ops.num, test_req->ops.len, test_req->ops.val); 00923 if (ret < 0) 00924 { 00925 printf("Error : %s\n",strerror(-ret)); 00926 return FAIL; 00927 } 00928 if (test_req->payload) 00929 { 00930 ret = coap_msg_set_payload(req, test_req->payload, test_req->payload_len); 00931 if (ret < 0) 00932 { 00933 printf("Error : %s\n",strerror(-ret)); 00934 return FAIL; 00935 } 00936 } 00937 return PASS; 00938 } 00939 //---------------------------------------------------------------------------------------------------------------------- 00940 //---------------------------------------------------------------------------------------------------------------------- 00941 /** 00942 * @brief Send a request to the server and receive the response 00943 * 00944 * @param[in,out] client Pointer to a client structure 00945 * @param[in] test_req Pointer to a test request message structure 00946 * @param[out] req Pointer to a request message structure 00947 * @param[out] resp Pointer to a response message structure 00948 * 00949 * @returns Test result 00950 */ 00951 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) 00952 { 00953 test_result_t result = PASS; 00954 int ret = 0; 00955 00956 result = populate_req(test_req, req); 00957 if (result != PASS) 00958 { 00959 printf("populate_req FAIL\n"); 00960 return result; 00961 } 00962 ret = coap_client_exchange(client, req, resp); 00963 if (ret < 0) 00964 { 00965 printf("coap_client_exchange FAIL\n"); 00966 printf("Error : %s\n",strerror(-ret)); 00967 return FAIL; 00968 } 00969 //printf("coap_client_exchange PASS\n"); 00970 print_coap_msg("Sent:", req,returncode); 00971 print_coap_msg("Received:", resp,returncode); 00972 00973 return PASS; 00974 } 00975 //---------------------------------------------------------------------------------------------------------------------- 00976 //---------------------------------------------------------------------------------------------------------------------- 00977 /** 00978 * @brief Compare the version and token fields in a request message and a response message 00979 * 00980 * @param[out] req Pointer to a request message structure 00981 * @param[out] resp Pointer to a response message structure 00982 * 00983 * @returns Test result 00984 */ 00985 test_result_t compare_ver_token(coap_msg_t *req, coap_msg_t *resp) 00986 { 00987 if (coap_msg_get_ver(req) != coap_msg_get_ver(resp)) 00988 { 00989 return FAIL; 00990 } 00991 if (coap_msg_get_token_len(req) != coap_msg_get_token_len(resp)) 00992 { 00993 return FAIL; 00994 } 00995 else if (memcmp(coap_msg_get_token(req), coap_msg_get_token(resp), coap_msg_get_token_len(req)) != 0) 00996 { 00997 return FAIL; 00998 } 00999 return PASS; 01000 } 01001 //---------------------------------------------------------------------------------------------------------------------- 01002 //---------------------------------------------------------------------------------------------------------------------- 01003 /** 01004 * @brief Check the fields in a response message against the expected values 01005 * 01006 * @param[out] test_resp Pointer to a test response message structure 01007 * @param[out] resp Pointer to a response message structure 01008 * 01009 * @returns Test result 01010 */ 01011 test_result_t check_resp(test_coap_client_msg_t *test_resp, coap_msg_t *resp) 01012 { 01013 if (test_resp->type != coap_msg_get_type(resp)) 01014 { 01015 return FAIL; 01016 } 01017 if (test_resp->code_class != coap_msg_get_code_class(resp)) 01018 { 01019 return FAIL; 01020 } 01021 if (test_resp->code_detail != coap_msg_get_code_detail(resp)) 01022 { 01023 return FAIL; 01024 } 01025 return PASS; 01026 }
Generated on Sun Jul 17 2022 00:59:13 by
