HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::SecureConnect___STATIC__VOID__I4__STRING__OBJECT( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_INT32 sslContext     = stack.Arg0().NumericByRef().s4;
    CLR_RT_HeapBlock* hb     = stack.Arg1().DereferenceString();
    CLR_RT_HeapBlock* socket = stack.Arg2().Dereference();
    CLR_INT32         timeout_ms = -1; // wait forever
    CLR_RT_HeapBlock  hbTimeout;
    
    int        result;    
    LPCSTR     szName;
    CLR_INT32  handle;
    bool       fRes = true;
    CLR_INT64 *timeout;

    FAULT_ON_NULL(socket);

    handle = socket[ Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::FIELD__m_Handle ].NumericByRef().s4;

    /* Because we could have been a rescheduled call due to a prior call that would have blocked, we need to see
     * if our handle has been shutdown before continuing. */
    if (handle == Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::DISPOSED_HANDLE)
    {
        ThrowError( stack, CLR_E_OBJECT_DISPOSED );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    FAULT_ON_NULL_ARG(hb);

    szName = hb->StringText();

    hbTimeout.SetInteger( timeout_ms );
        
    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    while(true)
    {
        result = SSL_Connect( handle, szName, sslContext );

        if(result == SOCK_EWOULDBLOCK || result == SOCK_TRY_AGAIN)
        {
            // non-blocking - allow other threads to run while we wait for socket activity
            TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));

            if(result < 0) break;
        }
        else
        {
            break;
        }
    }

    stack.PopValue();       // Timeout

    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, result ));

    TINYCLR_NOCLEANUP();
}
/* Read/write from/to server at the specified socket.
 *
 * ctx      The SSL/TLS connection data.
 * sslConn  The SSL connection.
 * returns EXIT_FAILURE on failure and EXIT_SUCCESS otherwise.
 */
static int SSLConn_ReadWrite(SSLConn_CTX* ctx, SSLConn* sslConn)
{
    int ret = 0;
    int len;

    switch (sslConn->state) {
        case INIT:
        case CLOSE:
            break;

        /* Perform TLS handshake. */
        case CONNECT:
            ret = SSL_Connect(sslConn->ssl, ctx->resume, sslConn->session,
                              &ctx->connTime, &ctx->resumeTime);
            if (ret == 0) {
                sslConn->state = CLOSE;
                return EXIT_FAILURE;
            }

            if (ret == 1) {
                sslConn->state = WRITE;
            }
            break;

        case WRITE:
            len = ctx->replyLen;
            if (ctx->maxBytes > 0) {
                len = min(len, ctx->maxBytes - ctx->totalWriteBytes);
            }
            /* Don't write if we are done. */
            if (len == 0)
                break;

            /* Write application data. */
            ret = SSL_Write(sslConn->ssl, ctx->reply, len,
                            &ctx->totalWriteBytes, &ctx->writeTime);
            if (ret == 0) {
                sslConn->state = CLOSE;
                return EXIT_FAILURE;
            }

            if (ret == 1)
                sslConn->state = READ_WAIT;
            break;

        case READ_WAIT:
            ret = TCP_Select(sslConn->sockfd, 0);
            if (ret != 1)
                break;
            sslConn->state = READ;

        case READ:
            len = ctx->bufferLen;
            if (ctx->maxBytes > 0) {
                len = min(len, ctx->maxBytes - ctx->totalReadBytes);
            }
            /* Don't read if we are done. */
            if (len == 0)
                break;

            /* Read application data. */
            ret = SSL_Read(sslConn->ssl, ctx->buffer, len, &ctx->totalReadBytes,
                           &ctx->readTime);
            if (ret == 0) {
                sslConn->state = CLOSE;
                return EXIT_FAILURE;
            }

            if (ret == 1) {
                if (ctx->maxConnections > 0)
                    sslConn->state = CLOSE;
                else
                    sslConn->state = WRITE;
            }
            break;
    }

    sslConn->err = ret;
    return EXIT_SUCCESS;
}