Patrick Barrett / libexositecoap
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers client_dtls.c Source File

client_dtls.c

00001 #include <stdio.h>
00002 #include <string.h>
00003 #include <errno.h>
00004 #include <unistd.h>
00005 #include <ctype.h>
00006 #include <netinet/in.h>
00007 #include <sys/types.h>
00008 #include <sys/socket.h>
00009 #include <sys/time.h>
00010 #include <arpa/inet.h>
00011 #include <netdb.h>
00012 
00013 #include <stdlib.h>
00014 #include <time.h>
00015 
00016 #include "coap.h"
00017 #include "dtls.h"
00018 
00019 #define COAPS_SRV "173.255.243.158"
00020 #define COAPS_SRV_PORT 20220
00021 
00022 #define BUFSIZE 2048
00023 #define MAX_DOWNLOAD_SIZE 102400 // 100k
00024 #define MAX_RETRY 3
00025 #define TIMEOUT 5
00026 
00027 #define PRINTF(...) printf(__VA_ARGS__);fflush(stdout);
00028 
00029 #define TEST_READ 0x02
00030 #define TEST_WRITE 0x04
00031 #define TEST_UPLOAD_FILE 0x08
00032 #define TEST_ACTIVATE 0x10
00033 #define TEST_DOWNLOAD_CONTENT 0x20
00034 
00035 #define block_size 5 // Range: 1 - 6
00036  
00037 void hex_dump(uint8_t* bytes, size_t len);
00038 void coap_pretty_print(uint8_t* pkt, size_t len);
00039 
00040 int main(void)
00041 {
00042   char alias[] = "temp";
00043   char cik[] = "a32c85ba9dda45823be416246cf8b433baa068d7";
00044 
00045   char host[] = "coap.exosite.com";
00046   char port[] = "5683";
00047 
00048   srand(time(NULL));
00049 
00050   // CoAP Message Setup
00051   #define MSG_BUF_LEN 64
00052   uint8_t msg_send[MSG_BUF_LEN];
00053   size_t  msg_send_len = 0;
00054   uint8_t msg_recv[MSG_BUF_LEN];
00055   size_t  msg_recv_len = 0;
00056 
00057   uint16_t message_id_counter = rand();
00058 
00059   // Socket to Exosite
00060   int localsock, remotesock;
00061   size_t bytes_sent;
00062   int rv;
00063 
00064   struct addrinfo exohints, *servinfo, *p, *q;
00065 
00066   memset(&exohints, 0, sizeof exohints);
00067   exohints.ai_family = AF_UNSPEC;
00068   exohints.ai_socktype = SOCK_DGRAM;
00069   exohints.ai_flags = AI_PASSIVE;
00070 
00071   if ((rv = getaddrinfo(NULL, port, &exohints, &servinfo)) != 0) {
00072     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
00073     return 1;
00074   }
00075 
00076   // loop through all the results and make a socket
00077   for(p = servinfo; p != NULL; p = p->ai_next) {
00078     if ((localsock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
00079       perror("bad socket");
00080       continue;
00081     }
00082 
00083     if (bind(localsock, p->ai_addr, p->ai_addrlen) == -1) {
00084       close(localsock);
00085       perror("bad bind");
00086       continue;
00087     }
00088 
00089     break;
00090   }
00091 
00092   if (p == NULL) {
00093       fprintf(stderr, "Failed to Bind Socket\n");
00094       return 2;
00095   }
00096 
00097   if ((rv = getaddrinfo(host, port, &exohints, &servinfo)) != 0) {
00098     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
00099     return 1;
00100   }
00101 
00102 
00103   // loop through all the results and make a socket
00104   for(q = servinfo; q != NULL; q = q->ai_next) {
00105     if ((remotesock = socket(q->ai_family, q->ai_socktype, q->ai_protocol)) == -1) {
00106       perror("bad socket");
00107       continue;
00108     }
00109 
00110     break;
00111   }
00112 
00113   if (q == NULL) {
00114       fprintf(stderr, "Failed to Bind Socket\n");
00115       return 2;
00116   }
00117  
00118   for (;;) 
00119   {
00120     printf("--------------------------------------------------------------------------------\n");
00121 
00122     // Build Message
00123     msg_send_len = 0; // Clear Message Buffer
00124     memset(msg_send, 0, msg_send_len);
00125     coap_set_version(msg_send, &msg_send_len, MSG_BUF_LEN, COAP_V1);
00126     coap_set_type(msg_send, &msg_send_len, MSG_BUF_LEN, CT_CON);
00127     coap_set_code(msg_send, &msg_send_len, MSG_BUF_LEN, CC_GET); //or POST
00128     coap_set_mid(msg_send, &msg_send_len, MSG_BUF_LEN, message_id_counter++);
00129     coap_set_token(msg_send, &msg_send_len, MSG_BUF_LEN, rand(), 2);
00130     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)"1a", 2);
00131     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
00132     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_QUERY, (uint8_t*)cik, strlen(cik));
00133     //coap_set_payload(msg_send, &msg_send_len, MSG_BUF_LEN, (uint8_t*)"99", 2);
00134 
00135     // Send Message
00136     if ((bytes_sent = sendto(remotesock, msg_send, msg_send_len, 0, q->ai_addr, q->ai_addrlen)) == -1){
00137       fprintf(stderr, "Failed to Send Message\n");
00138       return 2;
00139     }
00140 
00141     printf("Sent.\n");
00142     coap_pretty_print(msg_send, msg_send_len);
00143 
00144     // Wait for Response
00145     msg_recv_len = recvfrom(remotesock, (void *)msg_recv, sizeof(msg_recv), 0, q->ai_addr, &q->ai_addrlen);
00146     if (msg_recv_len < 0) {
00147       fprintf(stderr, "%s\n", strerror(errno));
00148       exit(EXIT_FAILURE);
00149     }
00150 
00151 
00152     if(coap_validate_pkt(msg_recv, msg_recv_len) == CS_OK)
00153     {
00154       printf("Got Valid CoAP Packet\n");
00155       if(coap_get_mid(msg_recv, msg_recv_len) == coap_get_mid(msg_send, msg_send_len) &&
00156          coap_get_token(msg_recv, msg_recv_len, 0) == coap_get_token(msg_send, msg_send_len, 0)) //this is only actually checking token length, should check token.
00157       {
00158         printf("Is Response to Last Message\n");
00159         coap_pretty_print(msg_recv, msg_recv_len);
00160       }
00161     }else{
00162       printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv_len);
00163       hex_dump(msg_recv, msg_recv_len);
00164     }
00165 
00166     usleep(1000000); // One Second
00167   }
00168 }
00169 
00170 // TEST_READ , TEST_WRITE
00171 static char alias[] = "temp";
00172 static char cik[] = "a32c85ba9dda45823be416246cf8b433baa068d7";
00173 static char value_to_write[] = "56";
00174 
00175 // dtls setup
00176 static size_t dtls_connected = 0;
00177 static size_t ready_to_recv = 0;
00178 static dtls_context_t *dtls_context = NULL;
00179 static session_t session;
00180 
00181 typedef struct trans_data {
00182     int out;
00183     int ack;
00184     uint8* data;
00185     int retry;
00186 } trans_data;
00187 
00188 struct trans_data last_sent = {.retry=0};
00189 
00190 #define SET_SEND_TIMESTAMP() {last_sent.out = (int)time(NULL); \
00191                               last_sent.data = (uint8*)sent_pdu->hdr; \
00192                               last_sent.ack = 0; \
00193                               last_sent.retry++;}
00194 #define SET_ACK_TIMESTAMP() {last_sent.ack = (int)time(NULL); last_sent.retry = 0;}
00195 
00196 int order_opts(void *a, void *b)
00197 {
00198     if (!a || !b)
00199         return a < b ? -1 : 1;
00200 
00201     if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option *)b))
00202         return -1;
00203 
00204     return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option *)b);
00205 }
00206 
00207 coap_pdu_t* coap_new_request(coap_context_t *ctx,  unsigned char method, coap_list_t *options, str payload )
00208 {
00209     coap_pdu_t *pdu;
00210     coap_list_t *opt;
00211 
00212     if ( ! ( pdu = coap_new_pdu() ) )
00213         return NULL;
00214 
00215     pdu->hdr->type = COAP_MESSAGE_CON;
00216     pdu->hdr->id = coap_new_message_id(ctx);
00217     pdu->hdr->code = method;
00218     pdu->hdr->token_length = the_token.length;
00219     if ( !coap_add_token(pdu, the_token.length, the_token.s)) {
00220         debug("cannot add token to request\n");
00221     }
00222     for (opt = options; opt; opt = opt->next) {
00223         coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)opt->data),
00224                         COAP_OPTION_LENGTH(*(coap_option *)opt->data),
00225                         COAP_OPTION_DATA(*(coap_option *)opt->data));
00226     }
00227     if (payload.length) {
00228         if (block_flag)
00229             coap_add_block(pdu, payload.length, payload.s, block.num, block.szx);
00230         else
00231             coap_add_data(pdu, payload.length, payload.s);
00232     }
00233 
00234     //coap_show_pdu(pdu);
00235 
00236     return pdu;
00237 }
00238 
00239 coap_list_t* new_option_node(unsigned short key, unsigned int length, unsigned char *data)
00240 {
00241     coap_option *option;
00242     coap_list_t *node;
00243 
00244     option = coap_malloc(sizeof(coap_option) + length);
00245     if ( !option )
00246         goto error;
00247 
00248     COAP_OPTION_KEY(*option) = key;
00249     COAP_OPTION_LENGTH(*option) = length;
00250     memcpy(COAP_OPTION_DATA(*option), data, length);
00251     /* we can pass NULL here as delete function since option is released automatically  */
00252     node = coap_new_listnode(option, NULL);
00253 
00254     if ( node )
00255         return node;
00256 
00257 error:
00258     perror("new_option_node: malloc");
00259     coap_free( option );
00260     return NULL;
00261 }
00262 
00263 coap_context_t* get_context(const char *node, const char *port)
00264 {
00265     coap_context_t *ctx = NULL;
00266     int s;
00267     struct addrinfo hints;
00268     struct addrinfo *result, *rp;
00269 
00270     memset(&hints, 0, sizeof(struct addrinfo));
00271     hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
00272     hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
00273     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
00274 
00275     s = getaddrinfo(node, port, &hints, &result);
00276     if ( s != 0 ) {
00277         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
00278         return NULL;
00279     }
00280     /* iterate through results until success */
00281     for (rp = result; rp != NULL; rp = rp->ai_next) {
00282         coap_address_t addr;
00283         if (rp->ai_addrlen <= sizeof(addr.addr)) {
00284             coap_address_init(&addr);
00285             addr.size = rp->ai_addrlen;
00286             memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
00287 
00288             ctx = coap_new_context(&addr);
00289             if (ctx) {
00290                 goto finish;
00291             }
00292         }
00293     }
00294 
00295     fprintf(stderr, "no context available for interface '%s'\n", node);
00296 
00297 finish:
00298     freeaddrinfo(result);
00299     return ctx;
00300 }
00301 
00302 coap_pdu_t* get_pdu(char* url, unsigned char method, str payload)
00303 {
00304     coap_pdu_t  *pdu;
00305     size_t buflen;
00306     int res;
00307     optlist=NULL;
00308 
00309     coap_split_uri((unsigned char *)url, strlen(url), &uri );
00310     if (uri.path.length) {
00311         buflen = BUFSIZE;
00312         unsigned char _buf[BUFSIZE];
00313         unsigned char *buf = _buf;
00314         res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
00315         while (res--) {
00316             coap_insert(&optlist,
00317                         new_option_node(
00318                             COAP_OPTION_URI_PATH,
00319                             COAP_OPT_LENGTH(buf),
00320                             COAP_OPT_VALUE(buf)),
00321                         order_opts);
00322             buf += COAP_OPT_SIZE(buf);
00323         }
00324     }
00325     if (uri.query.length) {
00326         buflen = BUFSIZE;
00327         unsigned char _buf[BUFSIZE];
00328         unsigned char *buf = _buf;
00329         res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
00330         while (res--) {
00331             coap_insert(&optlist,
00332                         new_option_node(
00333                             COAP_OPTION_URI_QUERY,
00334                             COAP_OPT_LENGTH(buf),
00335                             COAP_OPT_VALUE(buf)),
00336                         order_opts);
00337             buf += COAP_OPT_SIZE(buf);
00338         }
00339     }
00340     if (NULL == coap_ctx)
00341         coap_ctx = get_context("0.0.0.0", "0");
00342 
00343     if (block_flag) {
00344         static unsigned char tmp[4];
00345         unsigned short opt;
00346         opt = method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1;
00347         char more;
00348         if (coap_more_blocks(payload.length, block.num, block.szx))
00349             more = 0x08;
00350         else
00351             more = 0x00;
00352         //printf(" more:%d block num:%d\n", more, block.num);
00353         coap_insert(&optlist,
00354                     new_option_node(
00355                         opt,
00356                         coap_encode_var_bytes(tmp, (block.num << 4 | block.szx | more)),
00357                         tmp),
00358                     order_opts);
00359     }
00360     if (! (pdu = coap_new_request(coap_ctx, method, optlist, payload)))
00361         return NULL;
00362     return pdu;
00363 
00364 }
00365 
00366 coap_pdu_t* get_pdu_activate(char* vendor, char* model, char* serial_number)
00367 {
00368     char dest[BUFSIZE];
00369     strcpy(dest, "coap://0.0.0.0/provision/activate/"); //address is virtual
00370     strcat(dest, vendor);
00371     strcat(dest, "/");
00372     strcat(dest, model);
00373     strcat(dest, "/");
00374     strcat(dest, serial_number);
00375     str payload = { 0, NULL };
00376     return get_pdu(dest, COAP_REQUEST_POST, payload);
00377 
00378 
00379     msg_send_len = 0; // Clear Message Buffer
00380     memset(msg_send, 0, msg_send_len);
00381     coap_set_version(msg_send, &msg_send_len, MSG_BUF_LEN, COAP_V1);
00382     coap_set_type(msg_send, &msg_send_len, MSG_BUF_LEN, CT_CON);
00383     coap_set_code(msg_send, &msg_send_len, MSG_BUF_LEN, CC_POST);
00384     coap_set_mid(msg_send, &msg_send_len, MSG_BUF_LEN, message_id_counter++);
00385     coap_set_token(msg_send, &msg_send_len, MSG_BUF_LEN, rand(), 2);
00386     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)"provision", 9);
00387     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)"activate", 8);
00388     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)vendor, strlen(vendor));
00389     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)model, strlen(model));
00390     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)serial_number, strlen(serial_number));
00391 }
00392 
00393 coap_pdu_t* get_pdu_download_content()
00394 {
00395     char dest[BUFSIZE];
00396     strcpy(dest, "coap://0.0.0.0/provision/download/"); //address is virtual
00397     strcat(dest, vendor);
00398     strcat(dest, "/");
00399     strcat(dest, model);
00400     strcat(dest, "/");
00401     strcat(dest, content_id);
00402     strcat(dest, "?");
00403     strcat(dest, client_model_cik);
00404     str payload = { 0, NULL };
00405     block_flag = 1;
00406     return get_pdu(dest, COAP_REQUEST_GET, payload);
00407 
00408     msg_send_len = 0; // Clear Message Buffer
00409     memset(msg_send, 0, msg_send_len);
00410     coap_set_version(msg_send, &msg_send_len, MSG_BUF_LEN, COAP_V1);
00411     coap_set_type(msg_send, &msg_send_len, MSG_BUF_LEN, CT_CON);
00412     coap_set_code(msg_send, &msg_send_len, MSG_BUF_LEN, CC_POST);
00413     coap_set_mid(msg_send, &msg_send_len, MSG_BUF_LEN, message_id_counter++);
00414     coap_set_token(msg_send, &msg_send_len, MSG_BUF_LEN, rand(), 2);
00415     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)"provision", 9);
00416     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)"download", 8);
00417     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)vendor, strlen(vendor));
00418     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)model, strlen(model));
00419     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)serial_number, strlen(serial_number));
00420     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
00421     coap_add_option(msg_send, &msg_send_len, MSG_BUF_LEN, CON_URI_QUERY, (uint8_t*)cik, strlen(cik));
00422 
00423     return EXO_OK;
00424 }
00425 
00426 coap_pdu_t* get_pdu_read1p(char* cik, char* alias)
00427 {
00428     char dest[BUFSIZE];
00429     strcpy(dest, "coap://0.0.0.0/1a/"); //address is virtual
00430     strcat(dest, alias);
00431     strcat(dest, "?");
00432     strcat(dest, cik);
00433     str payload = { 0, NULL };
00434     return get_pdu(dest, COAP_REQUEST_GET, payload);
00435 }
00436 
00437 coap_pdu_t* get_pdu_write1p(char* cik, char* alias, char* value)
00438 {
00439     char dest[BUFSIZE];
00440     strcpy(dest, "coap://0.0.0.0/1a/"); //address is virtual
00441     strcat(dest, alias);
00442     strcat(dest, "?");
00443     strcat(dest, cik);
00444     str payload = { strlen(value), (unsigned char*)value };
00445     return get_pdu(dest, COAP_REQUEST_POST, payload);
00446 }
00447 
00448 coap_pdu_t* get_pdu_block_upload(char* cik, char* alias, int length, unsigned char* data)
00449 {
00450     char dest[BUFSIZE];
00451     strcpy(dest, "coap://0.0.0.0/1a/"); //address is virtual
00452     strcat(dest, alias);
00453     strcat(dest, "?");
00454     strcat(dest, cik);
00455     str payload = { length, data };
00456     block_flag = 1;
00457     return get_pdu(dest, COAP_REQUEST_PUT, payload);
00458 }
00459 
00460 static inline coap_opt_t * get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter)
00461 {
00462     coap_opt_filter_t f;
00463 
00464     assert(pdu);
00465     memset(f, 0, sizeof(coap_opt_filter_t));
00466     coap_option_setb(f, COAP_OPTION_BLOCK1);
00467     coap_option_setb(f, COAP_OPTION_BLOCK2);
00468 
00469     coap_option_iterator_init(pdu, opt_iter, f);
00470     return coap_option_next(opt_iter);
00471 }
00472 
00473 inline int check_token(coap_pdu_t *received)
00474 {
00475     return received->hdr->token_length == the_token.length &&
00476            memcmp(received->hdr->token, the_token.s, the_token.length) == 0;
00477 }
00478 
00479 void message_handler(coap_pdu_t *received)
00480 {
00481     size_t len;
00482     unsigned char *databuf = NULL;
00483     coap_opt_t *block_opt;
00484     coap_opt_iterator_t opt_iter;
00485 
00486     PRINTF("Receive %d.%02d response.\n\n",
00487            (received->hdr->code >> 5), received->hdr->code & 0x1F);
00488     /* check if this is a response to our original request */
00489     if (!check_token(received)) {
00490         return;
00491     }
00492 
00493     coap_get_data(received, &len, &databuf);
00494     block_opt = get_block(received, &opt_iter);
00495     coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter);
00496 
00497     if ( received->hdr->code == COAP_RESPONSE_CODE(205) ) {
00498         if (block_opt) {  // block option
00499             download_size +=  len;
00500             if (COAP_OPT_BLOCK_MORE(block_opt)) { // has more
00501                 PRINTF("found the M bit, block size is %u, block nr. %u\n",
00502                        COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt));
00503                 strcat(download_content, (char*)databuf);
00504                 SET_ACK_TIMESTAMP();
00505                 block.num += 1;
00506                 sent_pdu = get_pdu_download_content(vendor, model, content_id);
00507                 dtls_write(dtls_context, &session, (uint8*)sent_pdu->hdr, sent_pdu->length);
00508                 SET_SEND_TIMESTAMP();
00509             } else {
00510                 strcat(download_content, (char*)databuf);
00511                 FILE *fp;
00512                 fp=fopen(download_save_file, "wb");
00513                 fwrite(download_content, 1, download_size, fp);
00514                 fclose(fp);
00515                 PRINTF("Downloaded content is saved to file '%s'.\n", download_save_file);
00516                 ready_to_recv = 0;
00517             }
00518         } else {   // no block option
00519             if (databuf)
00520                 PRINTF("payload: '%s'\n", databuf);
00521             ready_to_recv = 0;
00522             return;
00523         }
00524     } else if ( received->hdr->code == COAP_RESPONSE_CODE(204)) {
00525         if (databuf)
00526             PRINTF("payload: '%s'\n", databuf);
00527         ready_to_recv = 0;
00528     } else {                   //  other than 2.05, 2.04//
00529         if (block_opt && received->hdr->code == COAP_RESPONSE_CODE(231)) { // block option
00530             if (COAP_OPT_BLOCK_MORE(block_opt)) { // has more
00531                 PRINTF("found the M bit, block size is %u, block nr. %u\n",
00532                        COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt));
00533                 SET_ACK_TIMESTAMP();
00534                 block.num += 1;
00535                 sent_pdu = get_pdu_block_upload(cik, alias, file_size, file_data);
00536                 dtls_write(dtls_context, &session, (uint8*)sent_pdu->hdr, sent_pdu->length);
00537                 SET_SEND_TIMESTAMP();
00538             }
00539         } else { //not block option
00540             if (databuf)
00541                 PRINTF("payload: '%s'\n", databuf);
00542             ready_to_recv = 0;
00543         }
00544     }
00545 }
00546 
00547 /* This function is the "key store" for tinyDTLS. It is called to
00548  * retrieve a key for the given identiy within this particular
00549  * session. */
00550 int get_key(struct dtls_context_t *ctx,
00551             const session_t *session,
00552             const unsigned char *id, size_t id_len,
00553             const dtls_key_t **result)
00554 {
00555     static const dtls_key_t psk = {
00556         .type = DTLS_KEY_PSK,
00557         .key.psk.id = (unsigned char *)"Client_identity",
00558         .key.psk.id_length = 15,
00559         .key.psk.key = (unsigned char *)"ex0CoAPs",
00560         .key.psk.key_length = 9
00561     };
00562     *result = &psk;
00563     return 0;
00564 }
00565 
00566 int handle_event(struct dtls_context_t *ctx, session_t *session,
00567                  dtls_alert_level_t level, unsigned short code)
00568 {
00569     if  (code == DTLS_EVENT_CONNECTED)
00570         dtls_connected = 1;
00571     return 0;
00572 }
00573 
00574 int read_from_server(struct dtls_context_t *ctx,
00575                      session_t *session, uint8 *data, size_t len)
00576 {
00577     //printf ("Server message:\n");
00578     //size_t i;
00579     //for (i = 0; i < len; i++)
00580     //    printf("%02x ", data[i]);
00581     //printf("\n");
00582     coap_pdu_t* received_pdu = coap_new_pdu();
00583     if (coap_pdu_parse(data, len, received_pdu)) {
00584         message_handler(received_pdu);
00585     } else
00586         PRINTF("Invalid CoAP message!");
00587 
00588     return 0;
00589 }
00590 
00591 int send_to_peer(struct dtls_context_t *ctx,
00592                  session_t *session, uint8 *data, size_t len)
00593 {
00594     int fd = *(int *)dtls_get_app_data(ctx);
00595     return sendto(fd, data, len, MSG_DONTWAIT,
00596                   &session->addr.sa, session->size);
00597 }
00598 
00599 int dtls_handle_read(struct dtls_context_t *ctx)
00600 {
00601     int fd;
00602     session_t session;
00603     static uint8 buf[BUFSIZE];
00604     int len;
00605 
00606     fd = *(int *)dtls_get_app_data(ctx);
00607 
00608     if (!fd)
00609         return -1;
00610 
00611     memset(&session, 0, sizeof(session_t));
00612     session.size = sizeof(session.addr);
00613     len = recvfrom(fd, buf, BUFSIZE, 0,
00614                    &session.addr.sa, &session.size);
00615     if (len < 0) {
00616         perror("recvfrom");
00617         return -1;
00618     } else {
00619     }
00620     return dtls_handle_message(ctx, &session, buf, len);
00621 }
00622 
00623 int resolve_address(const char *server, struct sockaddr *dst)
00624 {
00625     struct addrinfo *res, *ainfo;
00626     struct addrinfo hints;
00627     static char addrstr[256];
00628     int error;
00629 
00630     memset(addrstr, 0, sizeof(addrstr));
00631     if (server && strlen(server) > 0)
00632         memcpy(addrstr, server, strlen(server));
00633     else
00634         memcpy(addrstr, "localhost", 9);
00635 
00636     memset ((char *)&hints, 0, sizeof(hints));
00637     hints.ai_socktype = SOCK_DGRAM;
00638     hints.ai_family = AF_UNSPEC;
00639 
00640     error = getaddrinfo(addrstr, "", &hints, &res);
00641 
00642     if (error != 0) {
00643         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
00644         return error;
00645     }
00646     for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
00647 
00648         switch (ainfo->ai_family) {
00649         case AF_INET6:
00650         case AF_INET:
00651             memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
00652             return ainfo->ai_addrlen;
00653         default:
00654             ;
00655         }
00656     }
00657     freeaddrinfo(res);
00658     return -1;
00659 }
00660 
00661 /*---------------------------------------------------------------------------*/
00662 
00663 static dtls_handler_t cb = {
00664     .write = send_to_peer,
00665     .read  = read_from_server,
00666     .event = handle_event,
00667     .get_key = get_key
00668 };
00669 void get_file_content(char* file_name, unsigned int* size, unsigned char** content)
00670 {
00671     FILE *fh = fopen(file_name, "rw");
00672     if ( fh == NULL ) {
00673         perror(file_name);
00674         return;
00675     }
00676     fseek(fh, 0, SEEK_END);
00677     *size = ftell(fh);
00678     rewind(fh);
00679     *content = NULL;
00680     *content = (unsigned char*)malloc(*size);
00681     if ( *size != fread(*content, *size, 1, fh) )
00682         return;
00683     fclose(fh);
00684     return;
00685 }
00686 
00687 int main(int argc, char **argv)
00688 {
00689     //dtls_context_t *dtls_context = NULL;
00690     fd_set rfds;
00691     struct timeval timeout;
00692     int sock, result;
00693     int on = 1;
00694     int res;
00695 
00696     dtls_init();
00697     memset(&session, 0, sizeof(session_t));
00698 
00699     /* resolve destination address where server should be sent */
00700     res = resolve_address(COAPS_SRV, &session.addr.sa);
00701 
00702     if (res < 0) {
00703         PRINTF("failed to resolve address\n");
00704         exit(-1);
00705     }
00706     session.size = res;
00707     session.addr.sin.sin_port = htons(COAPS_SRV_PORT);
00708 
00709     sock = socket(session.addr.sa.sa_family, SOCK_DGRAM, 0);
00710     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
00711 
00712     dtls_context = dtls_new_context(&sock);
00713 
00714     if (!dtls_context) {
00715         PRINTF("cannot create context\n");
00716         exit(-1);
00717     }
00718 
00719     dtls_set_handler(dtls_context, &cb);
00720     dtls_connect(dtls_context, &session);
00721 
00722     while (1) {
00723         FD_ZERO(&rfds);
00724         FD_SET(sock, &rfds);
00725 
00726         timeout.tv_sec = 2;
00727         timeout.tv_usec = 0;
00728 
00729         result = select(sock+1, &rfds, 0, 0, &timeout);
00730 
00731         if (result < 0) {   // error
00732             if (errno != EINTR)
00733                 perror("select");
00734         } else if (result == 0) { // timeout
00735             if (last_sent.out > 0 && last_sent.ack == 0) {
00736                 if ((int)time(NULL) - last_sent.out > TIMEOUT) { // TIMEOUT
00737                     if (last_sent.retry <= MAX_RETRY) {
00738                         dtls_write(dtls_context, &session, last_sent.data, sent_pdu->length);
00739                         SET_SEND_TIMESTAMP();
00740                     } else {
00741                         PRINTF("Failed: reach retry limit");
00742                         break;
00743                     }
00744                 }
00745             }
00746         } else {      // ok
00747             if (FD_ISSET(sock, &rfds)) {
00748                 dtls_handle_read(dtls_context);
00749             }
00750         }
00751         if (dtls_connected && !ready_to_recv) {
00752             if (test_cases & TEST_WRITE) {
00753                 sent_pdu = get_pdu_write1p(cik ,alias, value_to_write);
00754                 PRINTF("Write data '%s' to '%s'..\n", value_to_write, alias);
00755                 dtls_write(dtls_context, &session, (uint8*)sent_pdu->hdr, sent_pdu->length);
00756                 test_cases -= TEST_WRITE;
00757                 ready_to_recv = 1;
00758                 continue;
00759             }
00760             if (test_cases & TEST_READ) {
00761                 sent_pdu = get_pdu_read1p(cik ,alias);
00762                 PRINTF("Read data from alias '%s'..\n", alias);
00763                 dtls_write(dtls_context, &session, (uint8*)sent_pdu->hdr, sent_pdu->length);
00764                 test_cases -= TEST_READ;
00765                 ready_to_recv = 1;
00766                 continue;
00767             }
00768         }
00769         if (!test_cases && !ready_to_recv)
00770             break;
00771     }
00772     dtls_free_context(dtls_context);
00773     exit(0);
00774 }
00775 
00776 
00777 void hex_dump(uint8_t* bytes, size_t len)
00778 {
00779   size_t i, j;
00780   for (i = 0; i < len; i+=16){
00781     printf("  0x%.3zx    ", i);
00782     for (j = 0; j < 16; j++){
00783       if (i+j < len)
00784         printf("%02hhx ", bytes[i+j]);
00785       else
00786         printf("%s ", "--");
00787     }
00788     printf("   %.*s\n", (int)(16 > len-i ? len-i : 16), bytes+i);
00789   }
00790 }
00791 
00792 void coap_pretty_print(uint8_t* pkt, size_t len)
00793 {
00794   size_t i;
00795   uint8_t *ptr;
00796   int32_t opt_num, j, k;
00797 
00798   if(coap_validate_pkt(pkt, len) == CS_OK){
00799       printf(" ------ Valid CoAP Packet (%zi) ------ \n", len);
00800       printf("Type: %i\n",coap_get_type(pkt, len));
00801       printf("Code: %i.%02i\n", coap_get_code_class(pkt, len), coap_get_code_detail(pkt, len));
00802       j = coap_get_option_count(pkt, len);
00803       for(i = 0; i < j; i++){
00804         k = coap_get_option(pkt, len, i, &opt_num, &ptr);
00805 
00806         printf("Option: %i\n", opt_num);
00807         printf(" Value: %.*s (%i)\n", k, ptr, k);
00808       }
00809       j = coap_get_payload(pkt, len, &ptr);
00810       printf("Value: %.*s (%i)\n", j, ptr, j);
00811     }else{
00812       printf(" ------ Non-CoAP Message (%zi) ------ \n", len);
00813       hex_dump(pkt, len);
00814     }
00815 }