0byt3m1n1
Path:
/
home
/
mgatv524
/
php
/
ext
/
zeromq-0.0.2
/
extension
/
[
Home
]
File: socket.c
//----------------------------------------------------------------------------- #include "socket.h" #include "context.h" //----------------------------------------------------------------------------- #define Check_Socket(__socket) \ do {\ if ((__socket->socket) == NULL)\ rb_raise (rb_eIOError, "closed socket");\ } while(0) //----------------------------------------------------------------------------- // ZeroMQ::Socket method declarations static VALUE socket_allocate( VALUE socket_class ); void socket_free( void* instance ); static VALUE socket_initialize( int count, VALUE* arguments, VALUE self ); static VALUE socket_close( VALUE self ); static VALUE socket_getsockopt( VALUE self, VALUE option ); static VALUE socket_setsockopt( VALUE self, VALUE option, VALUE value ); static VALUE socket_bind( VALUE self, VALUE addr_ ); static VALUE socket_connect( VALUE self, VALUE addr_ ); static VALUE socket_recv( int argc_, VALUE* argv_, VALUE self_ ); static VALUE socket_send( int argc_, VALUE* argv_, VALUE self_ ); //----------------------------------------------------------------------------- // zeromq socket helper functions struct zeromq_socket_io_request { void* socket; zmq_msg_t* message; int flags; int result; }; struct zeromq_socket* zeromq_socket_create() //------------------------------------------ { struct zeromq_socket* socket; socket = ALLOC( struct zeromq_socket ); socket->context = NULL; socket->socket = NULL; return socket; } void zeromq_socket_destroy( struct zeromq_socket* zeromq_socket ) //--------------------------------------------------------------- { if ( zeromq_socket->socket != NULL ) { int rc = zmq_close( zeromq_socket->socket ); assert( rc == 0 ); } if ( zeromq_socket->context != NULL ) { zeromq_context_release( zeromq_socket->context ); } xfree( zeromq_socket ); } static VALUE zeromq_socket_send_blocking_region( void* argument ) //--------------------------------------------------------------- { struct zeromq_socket_io_request* io_request = ( struct zeromq_socket_io_request* )argument; io_request->result = zmq_sendmsg( io_request->socket, io_request->message, io_request->flags ); return Qnil; } static VALUE zeromq_socket_receive_blocking_region( void* argument ) //------------------------------------------------------------------ { struct zeromq_socket_io_request* io_request = ( struct zeromq_socket_io_request* )argument; io_request->result = zmq_recvmsg( io_request->socket, io_request->message, io_request->flags ); return Qnil; } int zeromq_apply_socket_option( VALUE option, VALUE value, VALUE socket ) //----------------------------------------------------------------------- { socket_setsockopt( socket, option, value ); return ST_CONTINUE; } /* * Document-class: ZeroMQ::Socket * * The Socket class ... */ /* call-seq: new() * * The new method does some stuff. */ //---------------------------------------------------------------------------- VALUE socket_declare( VALUE zeromq_module ) //----------------------------------------- { VALUE klass = Qnil; klass = rb_define_class_under( zeromq_module, "Socket", rb_cObject ); rb_define_alloc_func( klass, socket_allocate ); rb_define_method( klass, "initialize", socket_initialize, -1 ); rb_define_method( klass, "getsockopt", socket_getsockopt, 1 ); rb_define_method( klass, "setsockopt", socket_setsockopt, 2 ); rb_define_method( klass, "bind", socket_bind, 1 ); rb_define_method( klass, "connect", socket_connect, 1 ); rb_define_method( klass, "send", socket_send, -1 ); rb_define_method( klass, "recv", socket_recv, -1 ); rb_define_method( klass, "close", socket_close, 0 ); rb_define_alias( klass, "receive", "recv" ); return klass; } //----------------------------------------------------------------------------- // ZeroMQ::Socket method implmentation static VALUE socket_allocate( VALUE socket_class ) //------------------------------------------------ { return rb_data_object_alloc( socket_class, zeromq_socket_create(), 0, socket_free ); } void socket_free( void* instance ) //-------------------------------- { zeromq_socket_destroy( ( struct zeromq_socket* )instance ); } static VALUE socket_initialize( int arg_count, VALUE* arguments, VALUE self ) //--------------------------------------------------------------------------- { struct zeromq_socket* socket = NULL; Data_Get_Struct( self, void, socket ); VALUE context = Qnil; VALUE socket_type = Qnil; VALUE socket_options = Qnil; rb_scan_args( arg_count, arguments, "12", &context, &socket_type, &socket_options ); if ( CLASS_OF( context ) != context_class ) { socket_options = socket_type; socket_type = context; context = Qnil; } if ( context == Qnil ) { context = context_default( context_class ); } if ( socket_type == Qnil ) { rb_raise( exception_class, "The socket type is required." ); return Qnil; } struct zeromq_context* context_struct = NULL; Data_Get_Struct( context, void, context_struct ); socket->socket = zmq_socket( context_struct->context, NUM2INT( socket_type ) ); if ( !socket->socket ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); return Qnil; } socket->context = context_struct; zeromq_context_retain( socket->context ); if ( CLASS_OF( socket_options ) == rb_cHash ) { rb_hash_foreach( socket_options, zeromq_apply_socket_option, self ); } return self; } static VALUE socket_close( VALUE self_ ) //-------------------------------------- { struct zeromq_socket * s; Data_Get_Struct (self_, struct zeromq_socket, s); if (s->socket != NULL) { int rc = zmq_close(s->socket); if (rc != 0) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } s->socket = NULL; /* Decrement the refcounter for the context (and possibly free it). */ zeromq_context_release( s->context ); s->context = NULL; } return Qnil; } static VALUE socket_getsockopt( VALUE self_, VALUE option_ ) { int rc = 0; VALUE retval; struct zeromq_socket * s; Data_Get_Struct (self_, struct zeromq_socket, s); Check_Socket (s); switch ( NUM2INT( option_ ) ) { case ZMQ_FD: { #ifdef _WIN32 SOCKET optval; #else int optval; #endif size_t optvalsize = sizeof( optval ); rc = zmq_getsockopt( s->socket, NUM2INT( option_ ), ( void* )&optval, &optvalsize ); if ( rc != 0 ) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } if ( NUM2INT( option_ ) == ZMQ_RCVMORE ) retval = optval ? Qtrue : Qfalse; else retval = INT2NUM (optval); } break; case ZMQ_EVENTS: { uint32_t optval; size_t optvalsize = sizeof(optval); rc = zmq_getsockopt( s->socket, NUM2INT( option_ ), ( void* )&optval, &optvalsize ); if ( rc != 0 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); return Qnil; } if ( NUM2INT( option_ ) == ZMQ_RCVMORE ) retval = optval ? Qtrue : Qfalse; else retval = INT2NUM( optval ); } break; case ZMQ_TYPE: case ZMQ_LINGER: case ZMQ_RECONNECT_IVL: case ZMQ_BACKLOG: case ZMQ_RECONNECT_IVL_MAX: case ZMQ_SNDTIMEO: case ZMQ_RCVTIMEO: case ZMQ_RCVHWM: case ZMQ_SNDHWM: { int optval; size_t optvalsize = sizeof( optval ); rc = zmq_getsockopt( s->socket, NUM2INT( option_ ), ( void* )&optval, &optvalsize ); if ( rc != 0 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); return Qnil; } if ( NUM2INT( option_ ) == ZMQ_RCVMORE ) retval = optval ? Qtrue : Qfalse; else retval = INT2NUM (optval); } break; case ZMQ_RCVMORE: case ZMQ_AFFINITY: case ZMQ_RATE: case ZMQ_RECOVERY_IVL: case ZMQ_SNDBUF: case ZMQ_RCVBUF: { int64_t optval; size_t optvalsize = sizeof(optval); rc = zmq_getsockopt (s->socket, NUM2INT (option_), (void *)&optval, &optvalsize); if (rc != 0) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } if (NUM2INT (option_) == ZMQ_RCVMORE) retval = optval ? Qtrue : Qfalse; else retval = INT2NUM (optval); } break; case ZMQ_IDENTITY: { char identity[255]; size_t optvalsize = sizeof (identity); rc = zmq_getsockopt (s->socket, NUM2INT (option_), (void *)identity, &optvalsize); if (rc != 0) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } if (optvalsize > sizeof (identity)) optvalsize = sizeof (identity); retval = rb_str_new (identity, optvalsize); } break; default: rb_raise (exception_class, "%s", zmq_strerror (EINVAL)); return Qnil; } return retval; } static VALUE socket_setsockopt( VALUE self_, VALUE option_, VALUE optval_ ) //------------------------------------------------------------------------- { int rc = 0; struct zeromq_socket * s; Data_Get_Struct (self_, struct zeromq_socket, s); Check_Socket (s); switch ( NUM2INT( option_ ) ) { case ZMQ_AFFINITY: case ZMQ_RATE: case ZMQ_RECOVERY_IVL: case ZMQ_SNDBUF: case ZMQ_RCVBUF: { uint64_t optval = FIX2LONG (optval_); // Forward the code to native 0MQ library. rc = zmq_setsockopt( s->socket, NUM2INT( option_ ), ( void* ) &optval, sizeof( optval ) ); } break; case ZMQ_RCVHWM: case ZMQ_SNDHWM: case ZMQ_LINGER: case ZMQ_RECONNECT_IVL: case ZMQ_BACKLOG: case ZMQ_RECONNECT_IVL_MAX: case ZMQ_SNDTIMEO: case ZMQ_RCVTIMEO: { int optval = FIX2INT (optval_); // Forward the code to native 0MQ library. rc = zmq_setsockopt( s->socket, NUM2INT( option_ ), ( void* )&optval, sizeof( optval ) ); } break; case ZMQ_IDENTITY: case ZMQ_SUBSCRIBE: case ZMQ_UNSUBSCRIBE: { // Forward the code to native 0MQ library. rc = zmq_setsockopt( s->socket, NUM2INT( option_ ), ( void* )StringValueCStr( optval_ ), RSTRING_LEN( optval_ ) ); } break; default: { rb_raise( exception_class, "%s", zmq_strerror( EINVAL ) ); return Qnil; } } if ( rc != 0 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); return Qnil; } return self_; } static VALUE socket_bind( VALUE self_, VALUE addr_ ) //-------------------------------------------------- { struct zeromq_socket * s; Data_Get_Struct (self_, struct zeromq_socket, s); Check_Socket (s); int rc = zmq_bind (s->socket, rb_string_value_cstr (&addr_)); if (rc != 0) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } return Qnil; } static VALUE socket_connect( VALUE self_, VALUE addr_ ) //----------------------------------------------------- { struct zeromq_socket * s; Data_Get_Struct (self_, struct zeromq_socket, s); Check_Socket (s); int rc = zmq_connect (s->socket, rb_string_value_cstr (&addr_)); if (rc != 0) { rb_raise (exception_class, "%s", zmq_strerror (zmq_errno ())); return Qnil; } return Qnil; } static VALUE socket_send( int argument_count, VALUE* arguments, VALUE self ) //-------------------------------------------------------------------------- { VALUE message_bytes_value, flags_value; rb_scan_args( argument_count, arguments, "11", &message_bytes_value, &flags_value ); Check_Type( message_bytes_value, T_STRING ); int flags = NIL_P( flags_value ) ? 0 : NUM2INT( flags_value ); struct zeromq_socket* socket; Data_Get_Struct( self, struct zeromq_socket, socket ); Check_Socket( socket ); zmq_msg_t message; int message_length = ( int )RSTRING_LEN( message_bytes_value ); int result = zmq_msg_init_size( &message, message_length ); if ( result != 0 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); return Qnil; } memcpy( zmq_msg_data( &message ), RSTRING_PTR( message_bytes_value ), message_length ); if ( !( flags & ZMQ_NOBLOCK ) ) { struct zeromq_socket_io_request io_request; io_request.socket = socket->socket; io_request.message = &message; io_request.flags = flags; rb_thread_blocking_region( zeromq_socket_send_blocking_region, ( void* )&io_request, NULL, NULL ); result = io_request.result; } else { result = zmq_sendmsg( socket->socket, &message, flags ); } if ( result == -1 && zmq_errno() == EAGAIN ) { result = zmq_msg_close( &message ); assert( result == 0 ); return Qfalse; } if ( result == -1 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); result = zmq_msg_close( &message ); assert( result == 0 ); return Qnil; } result = zmq_msg_close( &message ); assert( result == 0 ); return Qtrue; } static VALUE socket_recv( int argument_count, VALUE* arguments, VALUE self ) //-------------------------------------------------------------------------- { VALUE flags_value; rb_scan_args( argument_count, arguments, "01", &flags_value ); int flags = NIL_P( flags_value ) ? 0 : NUM2INT( flags_value ); struct zeromq_socket* socket; Data_Get_Struct( self, struct zeromq_socket, socket ); Check_Socket( socket ); zmq_msg_t message; int rc = zmq_msg_init( &message ); assert( rc == 0 ); if ( !( flags & ZMQ_NOBLOCK ) ) { struct zeromq_socket_io_request io_request; io_request.socket = socket->socket; io_request.message = &message; io_request.flags = flags; rb_thread_blocking_region( zeromq_socket_receive_blocking_region, ( void* )&io_request, NULL, NULL ); } else { rc = zmq_recvmsg( socket->socket, &message, flags ); } if ( rc == -1 && zmq_errno() == EAGAIN ) { rc = zmq_msg_close( &message ); assert( rc == 0 ); return Qnil; } if ( rc == -1 ) { rb_raise( exception_class, "%s", zmq_strerror( zmq_errno() ) ); rc = zmq_msg_close( &message ); assert( rc == 0 ); return Qnil; } VALUE message_bytes_value = rb_str_new( ( char* )zmq_msg_data( &message ), zmq_msg_size( &message ) ); rc = zmq_msg_close( &message ); assert( rc == 0 ); return message_bytes_value; }