/* * Copyright (C) 2008-2012 NEC Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "ruby.h" #include "trema-ruby-utils.h" #include "trema.h" extern VALUE mTrema; VALUE cError; static VALUE error_alloc( VALUE klass ) { buffer *error = create_error( 0, 0, 0, NULL ); return Data_Wrap_Struct( klass, NULL, free_buffer, error ); } /* * @overload initialize(options) * @example * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * ) * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * :transcation_id => 123 * ) * Error.new( * :type => OFPET_BAD_REQUEST, * :code => OFPBRC_BAD_TYPE, * :transcation_id => 123 * :data => "Error!!" * ) * @param [Hash] options * the options to create a message with. * @option options [Number] :type * a command or action that failed. * @option options [Number] :code * the reason of the failed type error. * @option options [String] :data * a more user friendly explanation of the error. Defaults to nil * if not specified. * @option options [Number] :xid * @option options [Number] :transaction_id * An unsigned 32bit integer number associated with this message. * If not specified, an auto-generated value is set. * @raise [ArgumentError] if transaction ID is not an unsigned 32bit integer. * @raise [ArgumentError] if type and code are not supplied. * @raise [ArgumentError] if user data is not a string. * @raise [TypeError] if options is not a hash. * @return [Error] */ static VALUE error_init( int argc, VALUE *argv, VALUE self ) { buffer *error = NULL; Data_Get_Struct( self, buffer, error ); VALUE options; if ( rb_scan_args( argc, argv, "01", &options ) == 1 ) { Check_Type( options, T_HASH ); VALUE tmp = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "type" ) ) ); if ( tmp != Qnil ) { ( ( struct ofp_error_msg * ) error->data )->type = htons( ( uint16_t ) NUM2UINT( tmp ) ); } else { rb_raise( rb_eArgError, "Type is a mandatory option" ); } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "code" ) ) ); if ( tmp != Qnil ) { ( ( struct ofp_error_msg * ) error->data )->code = htons( ( uint16_t ) NUM2UINT( tmp ) ); } else { rb_raise( rb_eArgError, "Code is a mandatory option" ); } VALUE xid = Qnil; tmp = rb_hash_aref( options, ID2SYM( rb_intern( "transaction_id" ) ) ); if ( tmp != Qnil ) { xid = tmp; } tmp = rb_hash_aref( options, ID2SYM( rb_intern( "xid" ) ) ); if ( tmp != Qnil ) { xid = tmp; } if ( xid != Qnil ) { validate_xid( xid ); set_xid( error, ( uint32_t ) NUM2UINT( xid ) ); } else { set_xid( error, get_transaction_id() ); } VALUE data = rb_hash_aref( options, ID2SYM( rb_intern( "data" ) ) ); if ( data != Qnil ) { Check_Type( data, T_STRING ); uint16_t length = ( u_int16_t ) RSTRING_LEN( data ); append_back_buffer( error, length ); ( ( struct ofp_header * ) ( error->data ) )->length = htons( ( uint16_t ) ( offsetof( struct ofp_error_msg, data ) + length ) ); memcpy( ( char * ) error->data + offsetof( struct ofp_error_msg, data ), RSTRING_PTR( data ), length ); } } else { rb_raise( rb_eArgError, "Type and code are mandatory options" ); } return self; } static struct ofp_error_msg * get_error( VALUE self ) { buffer *error; Data_Get_Struct( self, buffer, error ); return ( struct ofp_error_msg * ) error->data; } /* * Transaction ids, message sequence numbers matching requests to replies. * * @return [Number] the value of transaction id. */ static VALUE error_transaction_id( VALUE self ) { struct ofp_error_msg *error = get_error( self ); uint32_t xid = ntohl( error->header.xid ); return UINT2NUM( xid ); } /* * An optional user data payload field, possibly detailed explanation of the error. * * @return [String] user data payload is set. * @return [nil] user data payload is not set. */ static VALUE error_data( VALUE self ) { struct ofp_error_msg *error = get_error( self ); long length = ( long ) ( ntohs( error->header.length ) - sizeof( struct ofp_error_msg ) ); if ( length > 0 ) { return rb_str_new( ( char * ) error->data, length ); } else { return Qnil; } } /* * Indicates the command or action that failed. * * @return [Number] the value of error type. */ static VALUE error_type( VALUE self ) { struct ofp_error_msg *error = get_error( self ); return UINT2NUM( ntohs( error->type ) ); } /* * Reason of the failed type error. * * @return [Number] the value of error code. */ static VALUE error_code( VALUE self ) { struct ofp_error_msg *error = get_error( self ); return UINT2NUM( ntohs( error->code ) ); } void Init_error() { rb_define_const( mTrema, "OFPET_HELLO_FAILED", INT2NUM( OFPET_HELLO_FAILED ) ); rb_define_const( mTrema, "OFPHFC_INCOMPATIBLE", INT2NUM( OFPHFC_INCOMPATIBLE ) ); rb_define_const( mTrema, "OFPHFC_EPERM", INT2NUM( OFPHFC_EPERM ) ); rb_define_const( mTrema, "OFPET_BAD_REQUEST", INT2NUM( OFPET_BAD_REQUEST ) ); rb_define_const( mTrema, "OFPBRC_BAD_VERSION", INT2NUM( OFPBRC_BAD_VERSION ) ); rb_define_const( mTrema, "OFPBRC_BAD_TYPE", INT2NUM( OFPBRC_BAD_TYPE ) ); rb_define_const( mTrema, "OFPBRC_BAD_STAT", INT2NUM( OFPBRC_BAD_STAT ) ); rb_define_const( mTrema, "OFPBRC_BAD_VENDOR", INT2NUM( OFPBRC_BAD_VENDOR ) ); rb_define_const( mTrema, "OFPBRC_BAD_SUBTYPE", INT2NUM( OFPBRC_BAD_SUBTYPE ) ); rb_define_const( mTrema, "OFPBRC_EPERM", INT2NUM( OFPBRC_EPERM ) ); rb_define_const( mTrema, "OFPBRC_BAD_LEN", INT2NUM( OFPBRC_BAD_LEN ) ); rb_define_const( mTrema, "OFPBRC_BUFFER_EMPTY", INT2NUM( OFPBRC_BUFFER_EMPTY ) ); rb_define_const( mTrema, "OFPBRC_BUFFER_UNKNOWN", INT2NUM( OFPBRC_BUFFER_UNKNOWN ) ); rb_define_const( mTrema, "OFPET_BAD_ACTION", INT2NUM( OFPET_BAD_ACTION ) ); rb_define_const( mTrema, "OFPBAC_BAD_TYPE", INT2NUM( OFPBAC_BAD_TYPE ) ); rb_define_const( mTrema, "OFPBAC_BAD_LEN", INT2NUM( OFPBAC_BAD_LEN ) ); rb_define_const( mTrema, "OFPBAC_BAD_VENDOR", INT2NUM( OFPBAC_BAD_VENDOR ) ); rb_define_const( mTrema, "OFPBAC_BAD_VENDOR_TYPE", INT2NUM( OFPBAC_BAD_VENDOR_TYPE ) ); rb_define_const( mTrema, "OFPBAC_BAD_OUT_PORT", INT2NUM( OFPBAC_BAD_OUT_PORT ) ); rb_define_const( mTrema, "OFPBAC_BAD_ARGUMENT", INT2NUM( OFPBAC_BAD_ARGUMENT ) ); rb_define_const( mTrema, "OFPBAC_EPERM", INT2NUM( OFPBAC_EPERM ) ); rb_define_const( mTrema, "OFPBAC_TOO_MANY", INT2NUM( OFPBAC_TOO_MANY ) ); rb_define_const( mTrema, "OFPBAC_BAD_QUEUE", INT2NUM( OFPBAC_BAD_QUEUE ) ); rb_define_const( mTrema, "OFPET_FLOW_MOD_FAILED", INT2NUM( OFPET_FLOW_MOD_FAILED ) ); rb_define_const( mTrema, "OFPFMFC_ALL_TABLES_FULL", INT2NUM( OFPFMFC_ALL_TABLES_FULL ) ); rb_define_const( mTrema, "OFPFMFC_OVERLAP", INT2NUM( OFPFMFC_OVERLAP ) ); rb_define_const( mTrema, "OFPFMFC_EPERM", INT2NUM( OFPFMFC_EPERM ) ); rb_define_const( mTrema, "OFPFMFC_BAD_EMERG_TIMEOUT", INT2NUM( OFPFMFC_BAD_EMERG_TIMEOUT ) ); rb_define_const( mTrema, "OFPFMFC_BAD_COMMAND", INT2NUM( OFPFMFC_BAD_COMMAND ) ); rb_define_const( mTrema, "OFPFMFC_UNSUPPORTED", INT2NUM( OFPFMFC_UNSUPPORTED ) ); rb_define_const( mTrema, "OFPET_PORT_MOD_FAILED", INT2NUM( OFPET_PORT_MOD_FAILED ) ); rb_define_const( mTrema, "OFPPMFC_BAD_PORT", INT2NUM( OFPPMFC_BAD_PORT ) ); rb_define_const( mTrema, "OFPPMFC_BAD_HW_ADDR", INT2NUM( OFPPMFC_BAD_HW_ADDR ) ); rb_define_const( mTrema, "OFPET_QUEUE_OP_FAILED", INT2NUM( OFPET_QUEUE_OP_FAILED ) ); rb_define_const( mTrema, "OFPQOFC_BAD_PORT", INT2NUM(OFPQOFC_BAD_PORT)); rb_define_const( mTrema, "OFPQOFC_BAD_QUEUE", INT2NUM(OFPQOFC_BAD_QUEUE)); rb_define_const( mTrema, "OFPQOFC_EPERM", INT2NUM(OFPQOFC_EPERM)); cError = rb_define_class_under( mTrema, "Error", rb_cObject ); rb_define_alloc_func( cError, error_alloc ); rb_define_method( cError, "initialize", error_init, -1 ); rb_define_method( cError, "transaction_id", error_transaction_id, 0 ); rb_alias( cError, rb_intern( "xid" ), rb_intern( "transaction_id" ) ); rb_define_method( cError, "data", error_data, 0 ); rb_define_method( cError, "error_type", error_type, 0 ); rb_define_method( cError, "code", error_code, 0 ); } /* * Local variables: * c-basic-offset: 2 * indent-tabs-mode: nil * End: */