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() }