Umar Naeem / C027_SupportTest_coapp

Dependencies:   C027_Support mbed-dev

Fork of C027_SupportTest_coap by Umar Naeem

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers coap_client.cpp Source File

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 }