Beispiel #1
0
static int main_handle(
                          short*        cs
                        , CYASSL*       cya_obj
                        , Conn_t*       conn
                        , const char*   data
                        , const size_t  data_size )
{
    assert( cya_obj != 0 && conn != 0 && "cya_obj and conn must not be null at the same time!" );

    // locals that must exist through yields
    static int      state               = 0;
    static size_t   data_sent           = 0;
    static size_t   data_recv           = 0;
    static char     recv_buffer[ 256 ]  = { '\0' };
    int valopt                          = 0;
    socklen_t lon                       = sizeof( int );

    BEGIN_CORO( *cs )

    // restarted
    state = SSL_SUCCESS;

    // first part of the coroutine is about connecting to the endpoint
    {
        if( connect( conn->sock_fd, ( struct sockaddr* ) &conn->endpoint_addr, sizeof( conn->endpoint_addr ) ) == 0 )
        {
            EXIT( *cs, -1 );
        }
    }

    debug_log( "Connecting..." );
    int errval = errno;

    if( errval != EINPROGRESS )
    {
        debug_log( "Connection failed" );
        return -1;
    }

    YIELD( *cs, ( int ) WANT_WRITE );

    if( getsockopt( conn->sock_fd, SOL_SOCKET, SO_ERROR, ( void* )( &valopt ), &lon ) < 0 )
    {
        debug_fmt( "Error while getsockopt %s", strerror( errno ) );
        return -1;
    }

    if ( valopt )
    {
         debug_fmt( "Error while connecting %s", strerror( valopt ) );
         return -1;
    }

    debug_fmt( "Connected! state = %d", state );

    // part two is actually to do the ssl handshake
    {
        do
        {
            if( state == SSL_ERROR_WANT_READ )
            {
                YIELD( *cs, ( int ) WANT_READ );
            }

            if( state == SSL_ERROR_WANT_WRITE )
            {
                YIELD( *cs, ( int ) WANT_WRITE );
            }

            debug_log( "Connecting SSL..." );
            int ret = CyaSSL_connect( cya_obj );

            state = ret <= 0 ? CyaSSL_get_error( cya_obj, ret ) : ret;
            debug_fmt( "Connecting SSL state [%d][%d][%d]", state, ret, ( int ) SSL_SUCCESS );

        } while( state != SSL_SUCCESS && ( state == SSL_ERROR_WANT_READ || state == SSL_ERROR_WANT_WRITE ) );

        // we've connected or failed
        if( state != SSL_SUCCESS )
        {
            // something went wrong
            EXIT( *cs, -1 );
        }
    }

    // part three sending a message
    {
        data_sent = 0;

        do
        {
            do
            {
                if( state == SSL_ERROR_WANT_READ )
                {
                    YIELD( *cs, ( int ) WANT_READ );
                }

                if( state == SSL_ERROR_WANT_WRITE )
                {
                    YIELD( *cs, ( int ) WANT_WRITE );
                }

                size_t offset       = data_sent;
                size_t size_left    = data_size - data_sent;

                debug_fmt( "Sending SSL... data_size = [%zu], data_sent = [%zu]", data_size, data_sent );
                int ret             = CyaSSL_write( cya_obj, data + offset, size_left );
                state               = ret <= 0 ? CyaSSL_get_error( cya_obj, ret ) : SSL_SUCCESS;
                debug_fmt( "Sending SSL state state = [%d], ret = [%d]", state, ret );

                if( ret > 0 ) { data_sent += ret; }
            } while( data_sent < data_size && state == SSL_SUCCESS );
        } while( state != SSL_SUCCESS && ( state == SSL_ERROR_WANT_READ || state == SSL_ERROR_WANT_WRITE ) );

        if( state != SSL_SUCCESS )
        {
            debug_log( "Exiting" );
            EXIT( *cs, -1 );
        }
    }

    // part four receive
    {
        do
        {
            do
            {
                if( state == SSL_ERROR_WANT_READ )
                {
                    YIELD( *cs, ( int ) WANT_READ );
                }

                if( state == SSL_ERROR_WANT_WRITE )
                {
                    YIELD( *cs, ( int ) WANT_WRITE );
                }

                int ret     = CyaSSL_read( cya_obj, recv_buffer, sizeof( recv_buffer ) - 1 );
                state       = ret <= 0 ? CyaSSL_get_error( cya_obj, ret ) : SSL_SUCCESS;

                if( ret > 0 )
                {
                    recv_buffer[ ret ] = '\0';
                    debug_fmt( "<<<%s>>>", recv_buffer );
                    debug_fmt( "Received SSL... size = [%d], state = [%d]", ret, state );
                    data_recv = ret;
                }
            } while( data_recv == sizeof( recv_buffer ) - 1 && state == SSL_SUCCESS );
        } while( state != SSL_SUCCESS && ( state == SSL_ERROR_WANT_READ || state == SSL_ERROR_WANT_WRITE ) );

        if( state != SSL_SUCCESS )
        {
            EXIT( *cs, -1 );
        }
    }

    RESTART( *cs, 0 );

    END_CORO()
}
layer_state_t posix_asynch_io_layer_connect(
      layer_connectivity_t* context
    , const void* data
    , const layer_hint_t hint )
{
    XI_UNUSED( hint );

    static uint16_t cs = 0; // local coroutine prereserved state

    xi_connection_data_t* connection_data   = ( xi_connection_data_t* ) data;
    layer_t* layer                          = ( layer_t* ) context->self;
    posix_asynch_data_t* posix_asynch_data  = ( posix_asynch_data_t* ) layer->user_data;

    BEGIN_CORO( cs )

    xi_debug_format( "Connecting layer [%d] to the endpoint", layer->layer_type_id );

    // socket specific data
    struct sockaddr_in name;
    struct hostent* hostinfo;

    // get the hostaddress
    hostinfo = gethostbyname( connection_data->address );

    // if null it means that the address has not been founded
    if( hostinfo == NULL )
    {
        xi_debug_logger( "Getting Host by name [failed]" );
        xi_set_err( XI_SOCKET_GETHOSTBYNAME_ERROR );
        goto err_handling;
    }

    xi_debug_logger( "Getting Host by name [ok]" );

    // set the address and the port for further connection attempt
    memset( &name, 0, sizeof( struct sockaddr_in ) );
    name.sin_family     = AF_INET;
    name.sin_addr       = *( ( struct in_addr* ) hostinfo->h_addr );
    name.sin_port       = htons( connection_data->port );

    xi_debug_logger( "Connecting to the endpoint..." );

    if( connect( posix_asynch_data->socket_fd, ( struct sockaddr* ) &name, sizeof( struct sockaddr ) ) == -1 )
    {
        if( errno != EINPROGRESS )
        {
            xi_debug_printf( "errno: %d", errno );
            xi_debug_logger( "Connecting to the endpoint [failed]" );
            xi_set_err( XI_SOCKET_CONNECTION_ERROR );
            goto err_handling;
        }
        else
        {
            YIELD( cs, LAYER_STATE_WANT_WRITE ); // return here whenever we can write
        }
    }

    EXIT( cs, LAYER_STATE_OK );

err_handling:
    // cleanup the memory
    if( posix_asynch_data )     { close( posix_asynch_data->socket_fd ); }
    if( layer->user_data )      { XI_SAFE_FREE( layer->user_data ); }

    EXIT( cs, LAYER_STATE_ERROR );

    END_CORO()
}