/******************************************** rb_Spread: A ruby interace to the Spread Group Communication Toolkit Copyright(2001) George Schlossnagle, All Rights Reserved This sotware is release under the Perl Artistic License and is free to use for any purpose. *********************************************/ #include "ruby.h" #include "sp.h" #include #define BUFF_SIZE 1024 struct SpreadConnection { char spread_name[MAX_PROC_NAME]; char private_name[MAX_PRIVATE_NAME]; int priority; int group_membership; int mbox; char private_group[MAX_GROUP_NAME]; int buffer; int recvtimeout; }; struct SpreadMessage { int service_type; char sender[MAX_GROUP_NAME]; int num_groups; char groups[100][MAX_GROUP_NAME]; int16 mess_type; int length; int endian; char *message; }; static VALUE rb_eSpread; static VALUE rb_cSpread; static VALUE rb_cSpreadMessage; void free_spmess(void* ptr) { struct SpreadMessage *sp_mess; sp_mess = (void *) ptr; free(sp_mess->message); free(sp_mess); return; } static VALUE spread_connect(argc, argv, class) int argc; VALUE* argv; VALUE class; { VALUE spread_name_arg, private_name_arg, retobj; struct SpreadConnection *spret; int n; retobj = Data_Make_Struct(class, struct SpreadConnection, 0, free, spret); rb_scan_args(argc, argv, "02", &spread_name_arg, &private_name_arg); Check_Type(spread_name_arg, T_STRING); Check_Type(private_name_arg, T_STRING); if( (n = SP_connect( RSTRING(spread_name_arg)->ptr, RSTRING(private_name_arg)->ptr, 0, 0, &spret->mbox, spret->private_group)) < 0) { rb_raise(rb_eSpread, "failed with error %d connecting to spread daemon at %s", n, RSTRING(spread_name_arg)->ptr); } snprintf(spret->spread_name,MAX_PROC_NAME, "%s", RSTRING(spread_name_arg)->ptr); snprintf(spret->private_name, MAX_PRIVATE_NAME, "%s", RSTRING(private_name_arg)->ptr); spret->buffer = BUFF_SIZE; rb_obj_call_init(retobj, 0, NULL); return retobj; } static VALUE spread_disconnect(obj) VALUE obj; { struct SpreadConnection *sp; Data_Get_Struct(obj, struct SpreadConnection, sp); SP_disconnect(sp->mbox); return Qnil; } static VALUE spread_join(obj, group) VALUE obj; VALUE group; { char *tmp; int i, n; struct SpreadConnection *sp; Data_Get_Struct(obj, struct SpreadConnection, sp); switch(TYPE(group)) { case T_STRING: if((n = SP_join(sp->mbox, RSTRING(group)->ptr)) < 0) { rb_raise(rb_eSpread, "returned %d joining group %s", n, RSTRING(tmp)->ptr); } break; case T_ARRAY: if(RARRAY(group)->len == 0) { /* do something clever */ } for(i=1; ilen; i++) { tmp = (char *)RARRAY(group)->ptr[i]; if((n = SP_join(sp->mbox, RSTRING(tmp)->ptr)) < 0) { rb_raise(rb_eSpread, "returned %d joining group %s", n, RSTRING(tmp)->ptr); } } break; default: break; } return obj; } static VALUE spread_leave(obj, argc, argv) int argc; VALUE* argv; VALUE obj; { char *tmp; int i; VALUE group; struct SpreadConnection *sp; Data_Get_Struct(obj, struct SpreadConnection, sp); rb_scan_args(argc, argv, "1", &group); Check_Type(group, T_STRING); switch (TYPE(group)) { case T_STRING: SP_leave(sp->mbox, RSTRING(group)->ptr); break; case T_ARRAY: if(RARRAY(group)->len == 0) { /* do something clever */ } for(i=1; ilen; i++) { tmp = (char *)RARRAY(group)->ptr[i]; SP_leave(sp->mbox, RSTRING(tmp)->ptr); } break; default: break; } return Qnil; } static VALUE spread_multicast(argc, argv, obj) int argc; VALUE* argv; VALUE obj; { VALUE message, mtype, group, st; struct SpreadConnection *sp; int n; Data_Get_Struct(obj, struct SpreadConnection, sp); rb_scan_args(argc, argv, "04", &message, &group, &st, &mtype); if(mtype == Qnil) { mtype = INT2NUM(1); } switch (TYPE(message)) { case T_STRING: switch(TYPE(group)) { case T_STRING: if ((n = SP_multicast(sp->mbox, NUM2INT(st), RSTRING(group)->ptr, NUM2INT(mtype), RSTRING(message)->len, RSTRING(message)->ptr)) < 0) { rb_raise(rb_eSpread, "Error (%d) during multicast", n); } break; case T_ARRAY: { char groupnames[100][MAX_GROUP_NAME]; int i; if(RARRAY(group)->len == 0) { /* do something */ } for(i=0; ilen; i++) { VALUE tmp; tmp = RARRAY(group)->ptr[i]; snprintf(groupnames[i], MAX_GROUP_NAME, "%s", RSTRING(tmp)->ptr); } if ((n = SP_multigroup_multicast(sp->mbox, NUM2INT(st), RARRAY(group)->len, (const char (*)[MAX_GROUP_NAME])groupnames, NUM2INT(mtype), RSTRING(message)->len, RSTRING(message)->ptr)) < 0) { rb_raise(rb_eSpread, "Error (%d) during multicast", n); } } break; } break; default: rb_raise(rb_eSpread, "Invalid object type for multicast"); break; } return Qnil; } static VALUE spread_poll(obj) VALUE obj; { int n; struct SpreadConnection *sp; Data_Get_Struct(obj, struct SpreadConnection, sp); n = SP_poll(sp->mbox); return INT2NUM(n); } static VALUE spread_receive(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { struct SpreadConnection *sp; struct SpreadMessage *sp_mess; VALUE message; char buffer[BUFF_SIZE]; int n; bzero(buffer, BUFF_SIZE); message = Data_Make_Struct(rb_cSpreadMessage, struct SpreadMessage, 0, free_spmess, sp_mess); Data_Get_Struct(obj, struct SpreadConnection, sp); if((n = SP_receive(sp->mbox, &sp_mess->service_type, sp_mess->sender, 100, &sp_mess->num_groups, sp_mess->groups, &sp_mess->mess_type, &sp_mess->endian, BUFF_SIZE, buffer)) < 0) { rb_raise(rb_eSpread, "error %d during SP_recieve", n); } sp_mess->message = (char *)malloc(n); memcpy(sp_mess->message, buffer, n); sp_mess->length = n; return message; } /* Message Functions */ static VALUE sm_is_unreliable_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_unreliable_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_reliable_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_reliable_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_fifo_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_fifo_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_causal_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_causal_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_agreed_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_agreed_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_safe_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_safe_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_is_regular_mess(obj) VALUE obj; { int n; struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); n = Is_regular_mess(sp_mess->mess_type); return INT2NUM(n); } static VALUE sm_message(obj) VALUE obj; { struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); return rb_str_new(sp_mess->message, sp_mess->length); } static VALUE sm_sender(obj) VALUE obj; { struct SpreadMessage *sp_mess; Data_Get_Struct(obj, struct SpreadMessage, sp_mess); return rb_str_new(sp_mess->sender, MAX_GROUP_NAME); } void Init_spread() { rb_eSpread = rb_define_class("SpreadError", rb_eStandardError); rb_cSpread = rb_define_class("Spread", rb_cObject); rb_cSpreadMessage = rb_define_class("SpreadMessage", rb_cObject); rb_define_singleton_method(rb_cSpread, "new", spread_connect, -1); /* takes spread_name and private_name */ rb_define_method(rb_cSpread, "connect", spread_connect, -1); /* takes nothing */ rb_define_method(rb_cSpread, "disconnect", spread_disconnect, 0); /* takes group to join */ rb_define_method(rb_cSpread, "join", spread_join, 1); /* takes group to leave */ rb_define_method(rb_cSpread, "leave", spread_leave, 1); /* takes message, message_type, group and service-type */ rb_define_method(rb_cSpread, "multicast", spread_multicast, -1); /* Takes nothing returns number of bytes waiting to be read */ rb_define_method(rb_cSpread, "poll", spread_poll, 0); /* Takes nothing, returns a SpreadMessage */ rb_define_method(rb_cSpread, "receive", spread_receive, -1); /* Spread Message Methods */ rb_define_method(rb_cSpreadMessage, "message", sm_message, 0); rb_define_method(rb_cSpreadMessage, "sender", sm_sender, 0); rb_define_method(rb_cSpreadMessage, "is_unreliable", sm_is_unreliable_mess, 0); rb_define_method(rb_cSpreadMessage, "is_reliable", sm_is_reliable_mess, 0); rb_define_method(rb_cSpreadMessage, "is_fifo", sm_is_fifo_mess, 0); rb_define_method(rb_cSpreadMessage, "is_causal", sm_is_causal_mess, 0); rb_define_method(rb_cSpreadMessage, "is_agreed", sm_is_agreed_mess, 0); rb_define_method(rb_cSpreadMessage, "is_safe", sm_is_safe_mess, 0); rb_define_method(rb_cSpreadMessage, "is_regular", sm_is_regular_mess, 0); /* define constants */ rb_define_const(rb_cSpread, "LOW_PRIORITY", INT2NUM(LOW_PRIORITY)); rb_define_const(rb_cSpread, "MEDIUM_PRIORITY", INT2NUM(MEDIUM_PRIORITY)); rb_define_const(rb_cSpread, "HIGH_PRIORITY", INT2NUM(HIGH_PRIORITY)); rb_define_const(rb_cSpread, "UNRELIABLE_MESS", INT2NUM(UNRELIABLE_MESS)); rb_define_const(rb_cSpread, "RELIABLE_MESS", INT2NUM(RELIABLE_MESS)); rb_define_const(rb_cSpread, "FIFO_MESS", INT2NUM(FIFO_MESS)); rb_define_const(rb_cSpread, "CAUSAL_MESS", INT2NUM(CAUSAL_MESS)); rb_define_const(rb_cSpread, "AGREED_MESS", INT2NUM(AGREED_MESS)); rb_define_const(rb_cSpread, "SAFE_MESS", INT2NUM(SAFE_MESS)); rb_define_const(rb_cSpread, "REGULAR_MESS", INT2NUM(REGULAR_MESS)); rb_define_const(rb_cSpread, "SELF_DISCARD", INT2NUM(SELF_DISCARD)); rb_define_const(rb_cSpread, "DROP_RECV", INT2NUM(DROP_RECV)); rb_define_const(rb_cSpread, "REG_MEMB_MESS", INT2NUM(REG_MEMB_MESS)); rb_define_const(rb_cSpread, "TRANSITION_MESS", INT2NUM(TRANSITION_MESS)); rb_define_const(rb_cSpread, "CAUSED_BY_JOIN", INT2NUM(CAUSED_BY_JOIN)); rb_define_const(rb_cSpread, "CAUSED_BY_LEAVE", INT2NUM(CAUSED_BY_LEAVE)); rb_define_const(rb_cSpread, "CAUSED_BY_DISCONNECT", INT2NUM(CAUSED_BY_DISCONNECT)); rb_define_const(rb_cSpread, "CAUSED_BY_NETWORK", INT2NUM(CAUSED_BY_NETWORK)); rb_define_const(rb_cSpread, "MEMBERSHIP_MESS", INT2NUM(MEMBERSHIP_MESS)); rb_define_const(rb_cSpread, "ENDIAN_RESERVED", INT2NUM(ENDIAN_RESERVED)); rb_define_const(rb_cSpread, "RESERVED", INT2NUM(RESERVED)); /* define spread errors */ rb_define_const(rb_eSpread, "ACCEPT_SESSION", INT2NUM(ACCEPT_SESSION)); rb_define_const(rb_eSpread, "ILLEGAL_SPREAD", INT2NUM(ILLEGAL_SPREAD)); rb_define_const(rb_eSpread, "COULD_NOT_CONNECT", INT2NUM(COULD_NOT_CONNECT)); rb_define_const(rb_eSpread, "REJECT_QUOTA", INT2NUM(REJECT_QUOTA)); rb_define_const(rb_eSpread, "REJECT_NO_NAME", INT2NUM(REJECT_NO_NAME)); rb_define_const(rb_eSpread, "REJECT_ILLEGAL_NAME", INT2NUM(REJECT_ILLEGAL_NAME)); rb_define_const(rb_eSpread, "REJECT_NOT_UNIQUE", INT2NUM(REJECT_NOT_UNIQUE)); rb_define_const(rb_eSpread, "REJECT_VERSION", INT2NUM(REJECT_VERSION)); rb_define_const(rb_eSpread, "CONNECTION_CLOSED", INT2NUM(CONNECTION_CLOSED)); rb_define_const(rb_eSpread, "ILLEGAL_SESSION", INT2NUM(ILLEGAL_SESSION)); rb_define_const(rb_eSpread, "ILLEGAL_SERVICE", INT2NUM(ILLEGAL_SERVICE)); rb_define_const(rb_eSpread, "ILLEGAL_MESSAGE", INT2NUM(ILLEGAL_MESSAGE)); rb_define_const(rb_eSpread, "ILLEGAL_GROUP", INT2NUM(ILLEGAL_GROUP)); rb_define_const(rb_eSpread, "BUFFER_TOO_SHORT", INT2NUM(BUFFER_TOO_SHORT)); rb_define_const(rb_eSpread, "GROUPS_TOO_SHORT", INT2NUM(GROUPS_TOO_SHORT)); }