static int create_wolfssl_instance(TLS_IO_INSTANCE* tls_io_instance)
{
    int result;

    if (add_certificate_to_store(tls_io_instance) != 0)
    {
        wolfSSL_CTX_free(tls_io_instance->ssl_context);
        result = __LINE__;
    }
    else
    {
        tls_io_instance->ssl = wolfSSL_new(tls_io_instance->ssl_context);
        if (tls_io_instance->ssl == NULL)
        {
            wolfSSL_CTX_free(tls_io_instance->ssl_context);
            result = __LINE__;
        }
        else
        {
            tls_io_instance->socket_io_read_bytes = NULL;
            tls_io_instance->socket_io_read_byte_count = 0;
            tls_io_instance->on_send_complete = NULL;
            tls_io_instance->on_send_complete_callback_context = NULL;

            wolfSSL_set_using_nonblock(tls_io_instance->ssl, 1);
            wolfSSL_SetIOSend(tls_io_instance->ssl_context, on_io_send);
            wolfSSL_SetIORecv(tls_io_instance->ssl_context, on_io_recv);
            wolfSSL_SetHsDoneCb(tls_io_instance->ssl, on_handshake_done, tls_io_instance);
            wolfSSL_SetIOWriteCtx(tls_io_instance->ssl, tls_io_instance);
            wolfSSL_SetIOReadCtx(tls_io_instance->ssl, tls_io_instance);

            tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN;
            result = 0;
        }
    }
    return result;
}
int MqttSocket_Connect(MqttClient *client, const char* host, word16 port,
    int timeout_ms, int use_tls, MqttTlsCb cb)
{
    int rc;

    /* Validate arguments */
    if (client == NULL || client->net == NULL ||
        client->net->connect == NULL) {
        return MQTT_CODE_ERROR_BAD_ARG;
    }

    /* Validate port */
    if (port == 0) {
        port = (use_tls) ? MQTT_SECURE_PORT : MQTT_DEFAULT_PORT;
    }

    /* Connect to host */
    rc = client->net->connect(client->net->context, host, port, timeout_ms);
    if (rc != 0) {
        return rc;
    }
    client->flags |= MQTT_CLIENT_FLAG_IS_CONNECTED;

#ifdef ENABLE_MQTT_TLS
    if (use_tls) {
        /* Setup the WolfSSL library */
        wolfSSL_Init();
        
        /* Issue callback to allow setup of the wolfSSL_CTX and cert 
           verification settings */
        rc = SSL_SUCCESS;
        if (cb) {
            rc = cb(client);
        }
        if (rc == SSL_SUCCESS) {
            /* Create and initialize the WOLFSSL_CTX structure */
            if (client->tls.ctx == NULL) {
                /* Use defaults */
                client->tls.ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
                if (client->tls.ctx) {
                    wolfSSL_CTX_set_verify(client->tls.ctx, SSL_VERIFY_NONE, 0);
                }
            }
            if (client->tls.ctx) {
                /* Seutp the async IO callbacks */
                wolfSSL_SetIORecv(client->tls.ctx,
                    MqttSocket_TlsSocketReceive);
                wolfSSL_SetIOSend(client->tls.ctx,
                    MqttSocket_TlsSocketSend);

                client->tls.ssl = wolfSSL_new(client->tls.ctx);
                if (client->tls.ssl) {
                    wolfSSL_SetIOReadCtx(client->tls.ssl, (void *)client);
                    wolfSSL_SetIOWriteCtx(client->tls.ssl, (void *)client);

                    rc = wolfSSL_connect(client->tls.ssl);
                    if (rc == SSL_SUCCESS) {
                        client->flags |= MQTT_CLIENT_FLAG_IS_TLS;
                        rc = MQTT_CODE_SUCCESS;
                    }
                }
                else {
#ifndef WOLFMQTT_NO_STDIO
                    printf("MqttSocket_TlsConnect: wolfSSL_new error!\n");
#endif
                    rc = -1;
                }
            }
            else {
#ifndef WOLFMQTT_NO_STDIO
                printf("MqttSocket_TlsConnect: wolfSSL_CTX_new error!\n");
#endif
                rc = -1;
            }
        }
        else {
#ifndef WOLFMQTT_NO_STDIO
            printf("MqttSocket_TlsConnect: TLS callback error!\n");
#endif
            rc = -1;
        }

        /* Handle error case */
        if (rc) {
#ifndef WOLFMQTT_NO_STDIO
        	const char* errstr = NULL;
            int errnum = 0;
            if (client->tls.ssl) {
                errnum = wolfSSL_get_error(client->tls.ssl, 0);
                errstr = wolfSSL_ERR_reason_error_string(errnum);
            }

            printf("MqttSocket_TlsConnect Error %d: Num %d, %s\n",
                rc, errnum, errstr);
#endif

            /* Make sure we cleanup on error */
            MqttSocket_Disconnect(client);

            rc = MQTT_CODE_ERROR_TLS_CONNECT;
        }
    }
#else
    (void)cb;
#endif /* ENABLE_MQTT_TLS */

#ifdef WOLFMQTT_DEBUG_SOCKET
    printf("MqttSocket_Connect: Rc=%d\n", rc);
#endif

    /* Check for error */
    if (rc < 0) {
        rc = MQTT_CODE_ERROR_NETWORK;
    }

    return rc;
}
int main (int argc, char** argv)
{
    /* standard variables used in a dtls client */
    int           ret = 0, err;
    int           sockfd = -1;
    WOLFSSL*      ssl = NULL;
    WOLFSSL_CTX*  ctx = NULL;
    const char*   ca_cert  = "../certs/ca-cert.pem";
    char          buff[MSGLEN];
    int           buffLen;
    SharedDtls    shared;

    /* Program argument checking */
    if (argc != 2) {
        printf("usage: udpcli <IP address>\n");
        return 1;
    }

    /* Code for handling signals */
    struct sigaction act, oact;
    act.sa_handler = sig_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    sigaction(SIGINT, &act, &oact);

    wolfSSL_Debugging_ON();

    /* Initialize wolfSSL before assigning ctx */
    wolfSSL_Init();


    if ( (ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method())) == NULL) {
        fprintf(stderr, "wolfSSL_CTX_new error.\n");
        goto exit;
    }

    /* Register callbacks */
    wolfSSL_CTX_SetIORecv(ctx, my_IORecv);
    wolfSSL_CTX_SetIOSend(ctx, my_IOSend);


    /* Load CA certificates into ctx variable */
    if (wolfSSL_CTX_load_verify_locations(ctx, ca_cert, 0)
	    != SSL_SUCCESS) {
        fprintf(stderr, "Error loading %s, please check the file.\n", ca_cert);
        goto exit;
    }

    /* Assign ssl variable */
    ssl = wolfSSL_new(ctx);
    if (ssl == NULL) {
        printf("unable to get ssl object");
        goto exit;
    }
    memset(&shared, 0, sizeof(shared));
    shared.ssl = ssl;


    /* servAddr setup */
    shared.servSz = sizeof(shared.servAddr);
    shared.servAddr.sin_family = AF_INET;
    shared.servAddr.sin_port = htons(SERV_PORT);
    if (inet_pton(AF_INET, argv[1], &shared.servAddr.sin_addr) < 1) {
        printf("Error and/or invalid IP address");
        goto exit;
    }

    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
       printf("cannot create a socket.");
       goto exit;
    }
    shared.sd = sockfd;

    wolfSSL_SetIOWriteCtx(ssl, &shared);
    wolfSSL_SetIOReadCtx(ssl, &shared);

    if (wolfSSL_connect(ssl) != SSL_SUCCESS) {
	    err = wolfSSL_get_error(ssl, 0);
	    printf("err = %d, %s\n", err, wolfSSL_ERR_reason_error_string(err));
	    printf("SSL_connect failed\n");
        goto exit;
    }

    /**************************************************************************/
    /*                  Code for sending datagram to server                   */
    if (fgets(buff, sizeof(buff), stdin) != NULL) {

        /* Send buffer to the server */
        buffLen = strlen(buff);
        if (( wolfSSL_write(ssl, buff, buffLen)) != buffLen) {
            err = wolfSSL_get_error(ssl, 0);
            if (err != SSL_ERROR_WANT_WRITE) {
                printf("err = %d, %s\n", err, wolfSSL_ERR_reason_error_string(err));
                printf("SSL_write failed\n");
                goto exit;
            }
        }

        /* Receive message from server */
        ret = wolfSSL_read(ssl, buff, sizeof(buff)-1);
        if (ret < 0) {
            err = wolfSSL_get_error(ssl, 0);
            if (err != SSL_ERROR_WANT_READ) {
                printf("err = %d, %s\n", err, wolfSSL_ERR_reason_error_string(err));
                printf("SSL_read failed\n");
                goto exit;
            }
        }
        buffLen = ret;
        ret = 0;

        /* Add a terminating character to the generic server message */
        buff[buffLen] = '\0';
        fputs(buff, stdout);
    }
    /*                End code for sending datagram to server                 */
    /**************************************************************************/

exit:
    /* Housekeeping */
    if (ssl) {
        wolfSSL_shutdown(ssl);
        wolfSSL_free(ssl);
    }
    if (sockfd != -1) {
        close(sockfd);
    }
    if (ctx) {
        wolfSSL_CTX_free(ctx);
    }
    wolfSSL_Cleanup();

    return ret;
}