static int conn_link_mbedtls_initialize(void)
{
  if (g_https_data.initialized)
    return 0;

  g_https_data.mbedtls = calloc(1, sizeof(*g_https_data.mbedtls));
  if (!g_https_data.mbedtls)
    return -1;

  mbedtls_platform_set_calloc_free(conn_link_mbedtls_calloc,
                                   conn_link_mbedtls_free);

  mbedtls_ssl_config_init(&g_https_data.mbedtls->conf);
  mbedtls_ssl_session_init(&g_https_data.mbedtls->saved_session);
  mbedtls_entropy_init(&g_https_data.mbedtls->entropy);

#ifdef CONFIG_MBEDTLS_ENABLE_CTR_DRBG
  mbedtls_ctr_drbg_init(&g_https_data.mbedtls->drbg);

  if (mbedtls_ctr_drbg_seed(&g_https_data.mbedtls->drbg,
                            mbedtls_entropy_func,
                            &g_https_data.mbedtls->entropy,
                            (const void *)"sfx", 3) != 0)
    {
      goto err_free;
    }
#else
  const mbedtls_md_info_t *md_info = NULL;

#ifdef MBEDTLS_SHA1_C
  md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
#elif defined(MBEDTLS_SHA256_C)
  md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
#elif defined(MBEDTLS_SHA512_C)
  md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
#endif

  DEBUGASSERT(md_info != NULL);

  mbedtls_hmac_drbg_init(&g_https_data.mbedtls->drbg);

  if (mbedtls_hmac_drbg_seed(&g_https_data.mbedtls->drbg,
                             md_info,
                             mbedtls_entropy_func,
                             &g_https_data.mbedtls->entropy,
                             (const void *)"sfx", 3) != 0)
    {
      goto err_free;
    }
#endif

  if (mbedtls_ssl_config_defaults(&g_https_data.mbedtls->conf,
                                  MBEDTLS_SSL_IS_CLIENT,
                                  MBEDTLS_SSL_TRANSPORT_STREAM,
                                  MBEDTLS_SSL_PRESET_DEFAULT) != 0)
    {
      goto err_free;
    }

#ifdef CONFIG_MBEDTLS_ENABLE_CTR_DRBG
  mbedtls_ssl_conf_rng(&g_https_data.mbedtls->conf,
                       mbedtls_ctr_drbg_random,
                       &g_https_data.mbedtls->drbg);
#else
  mbedtls_ssl_conf_rng(&g_https_data.mbedtls->conf,
                       mbedtls_hmac_drbg_random,
                       &g_https_data.mbedtls->drbg);
#endif

  mbedtls_ssl_conf_authmode(&g_https_data.mbedtls->conf,
                            MBEDTLS_SSL_VERIFY_NONE);

#ifdef CONFIG_MBEDTLS_MAX_FRAGMENT
  mbedtls_ssl_conf_max_frag_len(&g_https_data.mbedtls->conf,
                                MBEDTLS_SSL_MAX_FRAG_LEN_512);
#endif

#ifdef CONFIG_MBEDTLS_TRUNCATED_HMAC
  mbedtls_ssl_conf_truncated_hmac(&g_https_data.mbedtls->conf,
                                  MBEDTLS_SSL_TRUNC_HMAC_ENABLED);
#endif

#ifdef CONFIG_MBEDTLS_SESSION_TICKET
  /* Use SSL out-fragment buffer of at least 384 bytes with session tickets,
   * preferably at least 512 bytes. */
  mbedtls_ssl_conf_session_tickets(&g_https_data.mbedtls->conf,
                                   MBEDTLS_SSL_SESSION_TICKETS_ENABLED);
#endif

  g_https_data.initialized = true;
  return 0;

err_free:
#ifdef CONFIG_MBEDTLS_ENABLE_CTR_DRBG
  mbedtls_ctr_drbg_free(&g_https_data.mbedtls->drbg);
#else
  mbedtls_hmac_drbg_free(&g_https_data.mbedtls->drbg);
#endif
  mbedtls_ssl_session_free(&g_https_data.mbedtls->saved_session);
  mbedtls_ssl_config_free(&g_https_data.mbedtls->conf);

  free(g_https_data.mbedtls);
  g_https_data.mbedtls = NULL;

  mbedtls_platform_set_calloc_free(calloc, free);
  g_https_data.initialized = false;
  return -1;
}
int main(void)
{
    struct addrinfo hints;
    struct addrinfo *ai;
    struct sockaddr_in server;
    int sock;
    int res;

    char server_name[] = "www.eff.org";
    char http_get[200] =
        "GET /index.html HTTP/1.1\r\n"
        "Host: www.eff.org\r\n"
        "\r\n";
    char http_get_resp[200];
    int cipher_list[] = { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, 0};

    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt cacert;

    printf("Press any key to continue...");
    getchar();
    printf("\n");

    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_x509_crt_init( &cacert );

    res = mbedtls_ssl_config_defaults(
            &conf,
            MBEDTLS_SSL_IS_CLIENT,
            MBEDTLS_SSL_TRANSPORT_STREAM,
            MBEDTLS_SSL_PRESET_DEFAULT);
    if( res != 0 )
    {
        mbedtls_printerr(res, "mbedtls_ssl_config_defaults");
        return 1;
    }
#if 0
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_NONE);
#endif
    mbedtls_ssl_conf_ciphersuites( &conf, cipher_list);
#if 0
    res = mbedtls_ssl_conf_max_frag_len( &conf, MBEDTLS_SSL_MAX_FRAG_LEN_512);
    if( res != 0 )
    {
        mbedtls_printerr(res, "mbedtls_ssl_conf_max_frag_len");
        return 1;
    }
#endif
    mbedtls_ssl_conf_rng(&conf, wrap_rng, NULL);
    res = mbedtls_ssl_setup( &ssl, &conf);
    if( res != 0 )
    {
        mbedtls_printerr(res, "mbedtls_ssl_setup");
        return 1;
    }
    res = mbedtls_x509_crt_parse(&cacert, digicert_der, digicert_der_len);
    if( res != 0 )
    {
        mbedtls_printerr(res, "mbedtls_x509_crt_parse");
        return 1;
    }
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
    res = mbedtls_ssl_set_hostname( &ssl, server_name);
    if( res != 0 )
    {
        mbedtls_printerr(res, "mbedtls_ssl_set_hostname");
        return 1;
    }

    hints.ai_flags = 0;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    res = getaddrinfo(server_name, NULL, &hints, &ai);
    if (res != 0)
    {
        if (res == EAI_SYSTEM)
        {
            perror("getaddrinfo");
        }
        else
        {
            fprintf(stderr, "error: getaddrinfo: %d\n", res);
        }
        return 1;
    }
    if (ai == NULL)
    {
        fprintf(stderr, "error: getaddrinfo : output is NULL\n");
        return 1;
    }

    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        perror("socket creation failed");
        return 1;
    }
#if 1
    server = *((const struct sockaddr_in *)ai->ai_addr);
    server.sin_port = htons( 443 ); /* HTTPS */
#else
    /* 
     * nslookup www.eff.org -> 69.50.225.155
     * socat TCP-LISTEN:44333 TCP:69.50.225.155:443
     */
    server.sin_family = AF_INET;
    server.sin_port = htons(44333);
    server.sin_addr.s_addr = inet_addr("192.168.1.173"); /* my PC */
#endif
    freeaddrinfo(ai);
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        perror("connect failed");
        close(sock);
        return 1;
    }
    
    /* TLS connect */
    mbedtls_ssl_set_bio( &ssl, &sock, wrap_send, wrap_recv, NULL);
    res = mbedtls_ssl_handshake( &ssl );
    do
    {
        const mbedtls_x509_crt *peer_cert;

        peer_cert = mbedtls_ssl_get_peer_cert(&ssl);
        if (peer_cert == NULL)
        {
            fprintf(stderr, "no peer cert.\n");
        }
        else
        {
            int n;
            char info_str[200];

            n = mbedtls_x509_crt_info(info_str, sizeof(info_str), "", peer_cert);
            fputs("Certificate:\n", stderr);
            fputs(info_str, stderr);
            fputs("\n", stderr);
        }
    } while(0);
    if (res != 0)
    {
        mbedtls_printerr(res, "mbedtls_ssl_handshake");
        close(sock);
        return 1;
    }

    res = mbedtls_ssl_write(&ssl, (unsigned char *)http_get, strlen(http_get));
    if (res <= 0)
    {
        mbedtls_printerr(res, "mbedtls_ssl_write");
        close(sock);
        return 1;
    }
    do
    {
        res = mbedtls_ssl_read(&ssl, (unsigned char *)http_get_resp, sizeof(http_get_resp));
        if (res <= 0)
        {
            mbedtls_printerr(res, "mbedtls_ssl_read");
            close(sock);
            return 1;
        }
        fwrite(http_get_resp, res, 1, stdout);
    } while(res == sizeof(http_get_resp)); //TODO: cleaner

    /* TLS disconnect */
    mbedtls_ssl_free(&ssl);
    mbedtls_ssl_config_free(&conf);
    close(sock);

    return 0;
}