static void flush_send_queue( int fd, void *user_data ) { UNUSED( fd ); UNUSED( user_data ); assert( send_queue != NULL ); assert( connection.fd >= 0 ); debug( "Flushing send queue ( length = %u ).", send_queue->length ); set_writable( connection.fd, false ); buffer *buf = NULL; while ( ( buf = peek_message( send_queue ) ) != NULL ) { ssize_t write_length = write( connection.fd, buf->data, buf->length ); if ( write_length < 0 ) { if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) { set_writable( connection.fd, true ); return; } error( "Failed to send a message to secure channel ( errno = %s [%d] ).", strerror( errno ), errno ); return; } if ( ( size_t ) write_length < buf->length ) { remove_front_buffer( buf, ( size_t ) write_length ); set_writable( connection.fd, true ); return; } buf = dequeue_message( send_queue ); free_buffer( buf ); } }
int openssl_check_connect(struct connection *conn) { int rc = mbedtls_ssl_handshake(conn->ssl); switch (rc) { case 0: /* success */ conn->connected = 1; set_writable(conn); if (verbose) printf("Ciphersuite is %s\n", mbedtls_ssl_get_ciphersuite(conn->ssl)); return 0; case MBEDTLS_ERR_SSL_WANT_READ: set_readable(conn); return 0; case MBEDTLS_ERR_SSL_WANT_WRITE: set_writable(conn); return 0; case MBEDTLS_ERR_NET_CONN_RESET: reset_connection(conn); return 1; default: printf("Not read or write 0x%x\n", rc); return 1; } }
int flush_secure_channel( struct switch_info *sw_info ) { assert( sw_info != NULL ); assert( sw_info->send_queue != NULL ); assert( sw_info->secure_channel_fd >= 0 ); buffer *buf; ssize_t write_length; if ( sw_info->send_queue->length == 0 ) { return 0; } set_writable( sw_info->secure_channel_fd, false ); writev_args args; args.iov = xmalloc( sizeof( struct iovec ) * ( size_t ) sw_info->send_queue->length ); args.iovcnt = 0; foreach_message_queue( sw_info->send_queue, append_to_writev_args, &args ); if ( args.iovcnt == 0 ) { xfree( args.iov ); return 0; } write_length = writev( sw_info->secure_channel_fd, args.iov, args.iovcnt ); xfree( args.iov ); if ( write_length < 0 ) { if ( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) { set_writable( sw_info->secure_channel_fd, true ); return 0; } error( "Failed to send a message to secure channel ( errno = %s [%d] ).", strerror( errno ), errno ); return -1; } if ( write_length == 0 ) { return 0; } while ( ( buf = peek_message( sw_info->send_queue ) ) != NULL ) { if ( write_length == 0 ) { set_writable( sw_info->secure_channel_fd, true ); return 0; } if ( ( size_t ) write_length < buf->length ) { remove_front_buffer( buf, ( size_t ) write_length ); set_writable( sw_info->secure_channel_fd, true ); return 0; } write_length -= ( ssize_t ) buf->length; buf = dequeue_message( sw_info->send_queue ); free_buffer( buf ); } return 0; }
static void notify_http_client_actually( int fd, void *user_data ) { uint64_t *count = user_data; debug( "Notifying HTTP client from main thread ( fd = %d, count = %" PRIu64 " ).", fd, count != NULL ? *count : 0 ); assert( fd >= 0 ); assert( user_data != NULL ); ssize_t ret = write( fd, count, sizeof( uint64_t ) ); if ( ret < 0 ) { if ( errno == EAGAIN || errno == EINTR ) { return; } char buf[ 256 ]; memset( buf, '\0', sizeof( buf ) ); char *error_string = strerror_r( errno, buf, sizeof( buf ) - 1 ); error( "Failed to notify an event to HTTP client ( count = %" PRIu64 ", fd = %d, ret = %zd, errno = %s [%d] ).", *count, fd, ret, error_string, errno ); return; } else if ( ret != sizeof( uint64_t ) ) { error( "Failed to notify an event to HTTP client ( count = %" PRIu64 ", fd = %d, ret = %zd ).", *count, fd, ret ); } set_writable( fd, false ); *count = 0; debug( "Notification completed." ); }
bool init_http_client() { debug( "Initializaing HTTP client." ); assert( http_client_thread == NULL ); assert( http_client_efd == -1 ); assert( main_efd == -1 ); assert( transactions == NULL ); http_client_efd = create_event_fd(); assert( http_client_efd >= 0 ); http_client_notify_count = 0; set_fd_handler( http_client_efd, NULL, NULL, notify_http_client_actually, &http_client_notify_count ); set_writable( http_client_efd, false ); main_efd = create_event_fd(); assert( main_efd >= 0 ); set_fd_handler( main_efd, retrieve_http_transactions_from_http_client, NULL, NULL, NULL ); set_readable( main_efd, true ); assert( main_to_http_client_queue == NULL ); assert( http_client_to_main_queue == NULL ); main_to_http_client_queue = create_queue(); assert( main_to_http_client_queue != NULL ); http_client_to_main_queue = create_queue(); assert( http_client_to_main_queue != NULL ); create_http_transaction_db(); debug( "Initialization completed." ); return true; }
static void check_connected( void *user_data ) { UNUSED( user_data ); debug( "Checking a connection ( fd = %d, ip = %#x, port = %u ).", connection.fd, connection.ip, connection.port ); assert( secure_channel_initialized ); assert( connection.fd >= 0 ); set_writable( connection.fd, false ); delete_fd_handler( connection.fd ); int err = 0; socklen_t length = sizeof( error ); int ret = getsockopt( connection.fd, SOL_SOCKET, SO_ERROR, &err, &length ); if ( ret < 0 ) { error( "Failed to retrieve error code ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); return; } switch ( err ) { case 0: connected(); break; case EINTR: case EAGAIN: case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: warn( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err ); backoff(); return; case EINPROGRESS: set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL ); set_writable( connection.fd, true ); break; default: error( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err ); clear_connection(); return; } }
static bool notify_http_client() { debug( "Incrementing HTTP client notify count ( %" PRIu64 " ).", http_client_notify_count ); assert( http_client_efd >= 0 ); http_client_notify_count++; set_writable( http_client_efd, true ); return true; }
static void connected() { transit_state( CONNECTED ); set_fd_handler( connection.fd, recv_from_secure_channel, NULL, flush_send_queue, NULL ); set_readable( connection.fd, true ); set_writable( connection.fd, false ); if ( connection.connected_callback != NULL ) { connection.connected_callback(); } }
static void clear_connection() { if ( connection.fd >= 0 ) { close( connection.fd ); set_readable( connection.fd, false ); set_writable( connection.fd, false ); delete_fd_handler( connection.fd ); } connection.fd = -1; connection.state = INIT; }
static int flush_secure_channel_tls( struct switch_info *sw_info ) { assert( sw_info != NULL ); assert( sw_info->tls ); assert( sw_info->ssl != NULL ); assert( sw_info->send_queue->length > 0 ); buffer *buf = NULL; while ( ( buf = peek_message( sw_info->send_queue ) ) != NULL ) { int write_length = SSL_write( sw_info->ssl, buf->data, ( int ) buf->length ); if ( write_length < 0 ) { int error_no = SSL_get_error( sw_info->ssl, write_length ); switch ( error_no ) { case SSL_ERROR_WANT_READ: set_readable( sw_info->secure_channel_fd, true ); case SSL_ERROR_WANT_WRITE: set_writable( sw_info->secure_channel_fd, true ); return 0; default: error( "Failed to send a message to secure channel ( error = %d ).", error_no ); return -1; } } if ( write_length == 0 ) { set_writable( sw_info->secure_channel_fd, true ); return 0; } if ( ( size_t ) write_length < buf->length ) { remove_front_buffer( buf, ( size_t ) write_length ); set_writable( sw_info->secure_channel_fd, true ); return 0; } buf = dequeue_message( sw_info->send_queue ); free_buffer( buf ); } return 0; }
int send_to_secure_channel( struct switch_info *sw_info, buffer *buf ) { assert( sw_info != NULL ); assert( buf != NULL ); assert( buf->length > 0 ); if ( sw_info->send_queue == NULL ) { return -1; } bool res = enqueue_message( sw_info->send_queue, buf ); if ( res ) { set_writable( sw_info->secure_channel_fd, true ); } return res ? 0 : -1; }
int switch_event_disconnected( struct switch_info *sw_info ) { int old_state = sw_info->state; sw_info->state = SWITCH_STATE_DISCONNECTED; if ( old_state == SWITCH_STATE_COMPLETED ) { delete_timer_event( echo_request_interval, sw_info ); } if ( sw_info->fragment_buf != NULL ) { free_buffer( sw_info->fragment_buf ); sw_info->fragment_buf = NULL; } if ( sw_info->send_queue != NULL ) { delete_message_queue( sw_info->send_queue ); sw_info->send_queue = NULL; } if ( sw_info->recv_queue != NULL ) { delete_message_queue( sw_info->recv_queue ); sw_info->recv_queue = NULL; } if ( sw_info->secure_channel_fd >= 0 ) { set_readable( switch_info.secure_channel_fd, false ); set_writable( switch_info.secure_channel_fd, false ); delete_fd_handler( switch_info.secure_channel_fd ); close( sw_info->secure_channel_fd ); sw_info->secure_channel_fd = -1; } if ( old_state != SWITCH_STATE_COMPLETED ) { service_send_state( sw_info, &sw_info->datapath_id, MESSENGER_OPENFLOW_FAILD_TO_CONNECT ); } else { // send secure channle disconnect state to application service_send_state( sw_info, &sw_info->datapath_id, MESSENGER_OPENFLOW_DISCONNECTED ); } flush_messenger(); stop_trema(); return 0; }
bool send_message_to_secure_channel( buffer *message ) { assert( send_queue != NULL ); assert( message != NULL ); assert( message->length > 0 ); assert( connection.state == CONNECTED ); assert( connection.fd >= 0 ); debug( "Enqueuing a message to send queue ( queue length = %u, message length = %zu ).", send_queue->length, message->length ); if ( send_queue->length == 0 ) { set_writable( connection.fd, true ); } buffer *duplicated = duplicate_buffer( message ); enqueue_message( send_queue, duplicated ); return true; }
int flush_secure_channel( struct switch_info *sw_info ) { assert( sw_info != NULL ); assert( sw_info->send_queue != NULL ); assert( sw_info->secure_channel_fd >= 0 ); if ( sw_info->send_queue->length == 0 ) { return 0; } set_writable( sw_info->secure_channel_fd, false ); int ret = -1; if ( sw_info->tls ) { ret = flush_secure_channel_tls( sw_info ); } else { ret = flush_secure_channel_tcp( sw_info ); } return ret; }
int switch_event_disconnected( struct switch_info *sw_info ) { sw_info->state = SWITCH_STATE_DISCONNECTED; if ( sw_info->fragment_buf != NULL ) { free_buffer( sw_info->fragment_buf ); sw_info->fragment_buf = NULL; } if ( sw_info->send_queue != NULL ) { delete_message_queue( sw_info->send_queue ); sw_info->send_queue = NULL; } if ( sw_info->recv_queue != NULL ) { delete_message_queue( sw_info->recv_queue ); sw_info->recv_queue = NULL; } if ( sw_info->secure_channel_fd >= 0 ) { set_readable( switch_info.secure_channel_fd, false ); set_writable( switch_info.secure_channel_fd, false ); delete_fd_handler( switch_info.secure_channel_fd ); close( sw_info->secure_channel_fd ); sw_info->secure_channel_fd = -1; } // send secure channle disconnect state to application service_send_state( sw_info, &sw_info->datapath_id, MESSENGER_OPENFLOW_DISCONNECTED ); flush_messenger(); debug( "send disconnected state" ); stop_event_handler(); stop_messenger(); return 0; }
bool finalize_http_client() { debug( "Finalizaing HTTP client ( transactions = %p ).", transactions ); assert( transactions != NULL ); if ( http_client_thread != NULL ) { pthread_cancel( *http_client_thread ); xfree( http_client_thread ); http_client_thread = NULL; } if ( http_client_efd >= 0 ) { set_writable( http_client_efd, false ); delete_fd_handler( http_client_efd ); close( http_client_efd ); http_client_efd = -1; } http_client_notify_count = 0; if ( main_efd >= 0 ) { set_readable( main_efd, false ); delete_fd_handler( main_efd ); close( main_efd ); main_efd = -1; } delete_queue( main_to_http_client_queue ); main_to_http_client_queue = NULL; delete_queue( http_client_to_main_queue ); http_client_to_main_queue = NULL; delete_http_transaction_db(); debug( "Finalization completed." ); return true; }
int main( int argc, char *argv[] ) { int ret; int i; char *service_name; init_trema( &argc, &argv ); option_parser( argc, argv ); create_list( &switch_info.vendor_service_name_list ); create_list( &switch_info.packetin_service_name_list ); create_list( &switch_info.portstatus_service_name_list ); create_list( &switch_info.state_service_name_list ); for ( i = optind; i < argc; i++ ) { if ( strncmp( argv[ i ], VENDOR_PREFIX, strlen( VENDOR_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[ i ] + strlen( VENDOR_PREFIX ) ); append_to_tail( &switch_info.vendor_service_name_list, service_name ); } else if ( strncmp( argv[ i ], PACKET_IN_PREFIX, strlen( PACKET_IN_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[ i ] + strlen( PACKET_IN_PREFIX ) ); append_to_tail( &switch_info.packetin_service_name_list, service_name ); } else if ( strncmp( argv[ i ], PORTSTATUS_PREFIX, strlen( PORTSTATUS_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[ i ] + strlen( PORTSTATUS_PREFIX ) ); append_to_tail( &switch_info.portstatus_service_name_list, service_name ); } else if ( strncmp( argv[ i ], STATE_PREFIX, strlen( STATE_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[ i ] + strlen( STATE_PREFIX ) ); append_to_tail( &switch_info.state_service_name_list, service_name ); } } struct sigaction signal_exit; memset( &signal_exit, 0, sizeof( struct sigaction ) ); signal_exit.sa_handler = handle_sigterm; sigaction( SIGINT, &signal_exit, NULL ); sigaction( SIGTERM, &signal_exit, NULL ); fcntl( switch_info.secure_channel_fd, F_SETFL, O_NONBLOCK ); set_fd_handler( switch_info.secure_channel_fd, secure_channel_read, NULL, secure_channel_write, NULL ); set_readable( switch_info.secure_channel_fd, true ); set_writable( switch_info.secure_channel_fd, false ); // default switch configuration switch_info.config_flags = OFPC_FRAG_NORMAL; switch_info.miss_send_len = UINT16_MAX; switch_info.fragment_buf = NULL; switch_info.send_queue = create_message_queue(); switch_info.recv_queue = create_message_queue(); switch_info.running_timer = false; switch_info.echo_request_xid = 0; init_xid_table(); if ( switch_info.cookie_translation ) { init_cookie_table(); } add_message_received_callback( get_trema_name(), service_recv ); set_management_application_request_handler( management_recv, NULL ); ret = switch_event_connected( &switch_info ); if ( ret < 0 ) { error( "Failed to set connected state." ); return -1; } ret = flush_secure_channel( &switch_info ); if ( ret < 0 ) { error( "Failed to flush secure channel. Terminating %s.", argv[ 0 ] ); return -1; } start_trema(); // Note: init_event_forward_interface will be called on feature_reply. finalize_event_forward_interface(); finalize_xid_table(); if ( switch_info.cookie_translation ) { finalize_cookie_table(); } if ( switch_info.secure_channel_fd >= 0 ) { delete_fd_handler( switch_info.secure_channel_fd ); } return 0; }
static bool try_connect() { assert( connection.state != CONNECTED ); int fd = socket( PF_INET, SOCK_STREAM, 0 ); if ( fd < 0 ) { error( "Failed to create a socket ( ret = %d, errno = %s [%d] ).", fd, strerror( errno ), errno ); return false; } int flag = 1; int ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof( flag ) ); if ( ret < 0 ) { error( "Failed to set socket options ( fd = %d, ret = %d, errno = %s [%d] ).", fd, ret, strerror( errno ), errno ); return false; } ret = fcntl( fd, F_SETFL, O_NONBLOCK ); if ( ret < 0 ) { error( "Failed to enable non-blocking mode ( fd = %d, ret = %d, errno = %s [%d] ).", fd, ret, strerror( errno ), errno ); close( fd ); return false; } connection.fd = fd; struct sockaddr_in addr; memset( &addr, 0, sizeof( struct sockaddr_in ) ); addr.sin_family = AF_INET; addr.sin_port = htons( connection.port ); addr.sin_addr.s_addr = htonl( connection.ip ); transit_state( CONNECTING ); ret = connect( connection.fd, ( struct sockaddr * ) &addr, sizeof( struct sockaddr_in ) ); if ( ret < 0 ) { switch ( errno ) { case EINTR: case EAGAIN: case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: warn( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); backoff(); return true; case EINPROGRESS: break; default: error( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); clear_connection(); return false; } } set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL ); set_writable( connection.fd, true ); return true; }
int main( int argc, char *argv[] ) { int ret; int i; char *service_name; char management_service_name[ MESSENGER_SERVICE_NAME_LENGTH ]; init_trema( &argc, &argv ); option_parser( argc, argv ); create_list( &switch_info.vendor_service_name_list ); create_list( &switch_info.packetin_service_name_list ); create_list( &switch_info.portstatus_service_name_list ); create_list( &switch_info.state_service_name_list ); // FIXME #define VENDER_PREFIX "vendor::" #define PACKET_IN_PREFIX "packet_in::" #define PORTSTATUS_PREFIX "port_status::" #define STATE_PREFIX "state_notify::" for ( i = optind; i < argc; i++ ) { if ( strncmp( argv[i], VENDER_PREFIX, strlen( VENDER_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[i] + strlen( VENDER_PREFIX ) ); insert_in_front( &switch_info.vendor_service_name_list, service_name ); } else if ( strncmp( argv[i], PACKET_IN_PREFIX, strlen( PACKET_IN_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[i] + strlen( PACKET_IN_PREFIX ) ); insert_in_front( &switch_info.packetin_service_name_list, service_name ); } else if ( strncmp( argv[i], PORTSTATUS_PREFIX, strlen( PORTSTATUS_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[i] + strlen( PORTSTATUS_PREFIX ) ); insert_in_front( &switch_info.portstatus_service_name_list, service_name ); } else if ( strncmp( argv[i], STATE_PREFIX, strlen( STATE_PREFIX ) ) == 0 ) { service_name = xstrdup( argv[i] + strlen( STATE_PREFIX ) ); insert_in_front( &switch_info.state_service_name_list, service_name ); } } fcntl( switch_info.secure_channel_fd, F_SETFL, O_NONBLOCK ); set_fd_handler( switch_info.secure_channel_fd, secure_channel_read, NULL, secure_channel_write, NULL ); set_readable( switch_info.secure_channel_fd, true ); set_writable( switch_info.secure_channel_fd, false ); // default switch configuration switch_info.config_flags = OFPC_FRAG_NORMAL; switch_info.miss_send_len = UINT16_MAX; switch_info.fragment_buf = NULL; switch_info.send_queue = create_message_queue(); switch_info.recv_queue = create_message_queue(); switch_info.running_timer = false; init_xid_table(); init_cookie_table(); add_message_received_callback( get_trema_name(), service_recv ); snprintf( management_service_name , MESSENGER_SERVICE_NAME_LENGTH, "%s.m", get_trema_name() ); management_service_name[ MESSENGER_SERVICE_NAME_LENGTH - 1 ] = '\0'; add_message_received_callback( management_service_name, management_recv ); ret = switch_event_connected( &switch_info ); if ( ret < 0 ) { error( "Failed to set connected state." ); return -1; } flush_secure_channel( &switch_info ); start_trema(); finalize_xid_table(); finalize_cookie_table(); if ( switch_info.secure_channel_fd >= 0 ) { delete_fd_handler( switch_info.secure_channel_fd ); } return 0; }
int switch_event_disconnected( struct switch_info *sw_info ) { int old_state = sw_info->state; if ( sw_info->state == SWITCH_STATE_DISCONNECTED || sw_info->state == SWITCH_STATE_CONNECTION_FAILED ) { debug( "already disconnected" ); return -1; } if ( sw_info->state == SWITCH_STATE_COMPLETED ) { sw_info->state = SWITCH_STATE_DISCONNECTED; } else { sw_info->state = SWITCH_STATE_CONNECTION_FAILED; } if ( old_state == SWITCH_STATE_COMPLETED ) { switch_unset_timeout( echo_reply_timeout, NULL ); } if ( sw_info->fragment_buf != NULL ) { free_buffer( sw_info->fragment_buf ); sw_info->fragment_buf = NULL; } if ( sw_info->send_queue != NULL ) { delete_message_queue( sw_info->send_queue ); sw_info->send_queue = NULL; } if ( sw_info->recv_queue != NULL ) { delete_message_queue( sw_info->recv_queue ); sw_info->recv_queue = NULL; } if ( sw_info->secure_channel_fd >= 0 ) { set_readable( switch_info.secure_channel_fd, false ); set_writable( switch_info.secure_channel_fd, false ); delete_fd_handler( switch_info.secure_channel_fd ); } uint8_t state = MESSENGER_OPENFLOW_DISCONNECTED; if ( sw_info->state == SWITCH_STATE_CONNECTION_FAILED ) { state = MESSENGER_OPENFLOW_FAILD_TO_CONNECT; } debug( "Notify switch_disconnected to switch manager." ); char switch_manager[] = SWITCH_MANAGER; list_element switch_manager_only_list; switch_manager_only_list.next = NULL; switch_manager_only_list.data = switch_manager; service_send_to_application( &switch_manager_only_list, state, &sw_info->datapath_id, NULL ); // Check switch_manager registration debug( "Checking switch manager's switch list." ); sw_info->retry_count = UNREGISTRATION_RETRY_COUNT; set_list_switches_reply_handler( confirm_self_dpid_is_unregistered ); if ( send_list_switches_request( sw_info ) ) { switch_set_timeout( UNREGISTRATION_TIMEOUT, unregistration_timeout, sw_info ); } else { error( "Failed to send switch list request to switch manager." ); stop_switch(); } return 0; }