text: /*
   * Copyright (C) 2019 Daniele Lacamera
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @ingroup     examples
   * @{
   *
   * @file
   * @brief       Demonstrating DTLS 1.2 client using wolfSSL
   *
   * @author      Daniele Lacamera <daniele@wolfssl.com>
   * @}
   */
  
  #include <wolfssl/ssl.h>
  #include <wolfssl/error-ssl.h>
  #include <sock_tls.h>
  #include <net/sock.h>
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  
  #include "log.h"
  
  #define SERVER_PORT 11111
  #define APP_DTLS_BUF_SIZE 64
  
  extern const unsigned char server_cert[];
  extern const unsigned long server_cert_len;
  
  static sock_tls_t skv;
  static sock_tls_t *sk = &skv;
  
  static void usage(const char *cmd_name)
  {
      LOG(LOG_ERROR, "Usage: %s <server-address>\n", cmd_name);
  }
  
  #ifdef MODULE_WOLFSSL_PSK
  /* identity is OpenSSL testing default for openssl s_client, keep same */
  static const char* kIdentityStr = "Client_identity";
  
  static inline unsigned int my_psk_client_cb(WOLFSSL* ssl, const char* hint,
          char* identity, unsigned int id_max_len, unsigned char* key,
          unsigned int key_max_len)
  {
      (void)ssl;
      (void)hint;
      (void)key_max_len;
  
      /* see internal.h MAX_PSK_ID_LEN for PSK identity limit */
      strncpy(identity, kIdentityStr, id_max_len);
  
      if (wolfSSL_GetVersion(ssl) < WOLFSSL_TLSV1_3) {
          /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
             unsigned binary */
          key[0] = 0x1a;
          key[1] = 0x2b;
          key[2] = 0x3c;
          key[3] = 0x4d;
  
          return 4;   /* length of key in octets or 0 for error */
      }
      else {
          int i;
          int b = 0x01;
  
          for (i = 0; i < 32; i++, b += 0x22) {
              if (b >= 0x100)
                  b = 0x01;
              key[i] = b;
          }
  
          return 32;   /* length of key in octets or 0 for error */
      }
  }
  #endif
  
  int dtls_client(int argc, char **argv)
  {
      int ret = 0;
      char buf[APP_DTLS_BUF_SIZE] = "Hello from DTLS client!";
      char *iface;
      char *addr_str;
      int connect_timeout = 0;
      const int max_connect_timeouts = 5;
  
      if (argc != 2) {
          usage(argv[0]);
          return -1;
      }
  
      addr_str = argv[1];
      sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
      sock_udp_ep_t remote = SOCK_IPV6_EP_ANY;
  
      /* Parsing <address> */
      iface = ipv6_addr_split_iface(addr_str);
      if (!iface) {
          if (gnrc_netif_numof() == 1) {
              /* assign the single interface found in gnrc_netif_numof() */
              remote.netif = (uint16_t)gnrc_netif_iter(NULL)->pid;
          }
      }
      else {
          gnrc_netif_t *netif = gnrc_netif_get_by_pid(atoi(iface));
          if (netif == NULL) {
              LOG(LOG_ERROR, "ERROR: interface not valid\n");
              usage(argv[0]);
              return -1;
          }
          remote.netif = (uint16_t)netif->pid;
      }
      if (ipv6_addr_from_str((ipv6_addr_t *)remote.addr.ipv6, addr_str) == NULL) {
          LOG(LOG_ERROR, "ERROR: unable to parse destination address\n");
          usage(argv[0]);
          return -1;
      }
      remote.port = SERVER_PORT;
      if (sock_dtls_create(sk, &local, &remote, 0, wolfDTLSv1_2_client_method()) != 0) {
          LOG(LOG_ERROR, "ERROR: Unable to create DTLS sock\n");
          return -1;
      }
  
  #ifndef MODULE_WOLFSSL_PSK
      /* Disable certificate validation from the client side */
      wolfSSL_CTX_set_verify(sk->ctx, SSL_VERIFY_NONE, 0);
  
      /* Load certificate file for the DTLS client */
      if (wolfSSL_CTX_use_certificate_buffer(sk->ctx, server_cert,
                  server_cert_len, SSL_FILETYPE_ASN1 ) != SSL_SUCCESS)
      {
          LOG(LOG_ERROR, "Error loading cert buffer\n");
          return -1;
      }
  
  #else /* !def MODULE_WOLFSSL_PSK */
      wolfSSL_CTX_set_psk_client_callback(sk->ctx, my_psk_client_cb);
  #endif
  
      if (sock_dtls_session_create(sk) < 0)
          return -1;
      wolfSSL_dtls_set_timeout_init(sk->ssl, 5);
      LOG(LOG_INFO, "connecting to server...\n");
      /* attempt to connect until the connection is successful */
      do {
          ret = wolfSSL_connect(sk->ssl);
          if ((ret != SSL_SUCCESS)) {
              if(wolfSSL_get_error(sk->ssl, ret) == SOCKET_ERROR_E) {
                  LOG(LOG_WARNING, "Socket error: reconnecting...\n");
                  sock_dtls_session_destroy(sk);
                  connect_timeout = 0;
                  if (sock_dtls_session_create(sk) < 0)
                      return -1;
              }
              if ((wolfSSL_get_error(sk->ssl, ret) == WOLFSSL_ERROR_WANT_READ) &&
                      (connect_timeout++ >= max_connect_timeouts)) {
                  LOG(LOG_WARNING, "Server not responding: reconnecting...\n");
                  sock_dtls_session_destroy(sk);
                  connect_timeout = 0;
                  if (sock_dtls_session_create(sk) < 0)
                      return -1;
              }
          }
      } while(ret != SSL_SUCCESS);
  
      /* set remote endpoint */
      sock_dtls_set_endpoint(sk, &remote);
  
      /* send the hello message */
      wolfSSL_write(sk->ssl, buf, strlen(buf));
  
      /* wait for a reply, indefinitely */
      do {
          ret = wolfSSL_read(sk->ssl, buf, APP_DTLS_BUF_SIZE - 1);
          LOG(LOG_INFO, "wolfSSL_read returned %d\n", ret);
      } while (ret <= 0);
      buf[ret] = (char)0;
      LOG(LOG_INFO, "Received: '%s'\n", buf);
  
      /* Clean up and exit. */
      LOG(LOG_INFO, "Closing connection.\n");
      sock_dtls_session_destroy(sk);
      sock_dtls_close(sk);
      return 0;
  }
  