ext/sctp/socket.c in sctp-socket-0.0.2 vs ext/sctp/socket.c in sctp-socket-0.0.3
- old
+ new
@@ -5,10 +5,19 @@
#include <netinet/sctp.h>
VALUE mSCTP;
VALUE cSocket;
VALUE v_sndrcv_struct;
+VALUE v_assoc_change_struct;
+VALUE v_peeraddr_change_struct;
+VALUE v_remote_error_struct;
+VALUE v_send_failed_event_struct;
+VALUE v_shutdown_event_struct;
+VALUE v_sndinfo_struct;
+VALUE v_adaptation_event_struct;
+VALUE v_partial_delivery_event_struct;
+VALUE v_auth_event_struct;
// Helper function to get a hash value via string or symbol.
VALUE rb_hash_aref2(VALUE v_hash, const char* key){
VALUE v_key, v_val;
@@ -423,11 +432,11 @@
* ensure
* socket.close
* end
*/
static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
- VALUE v_flags;
+ VALUE v_flags, v_notification, v_message;
struct sctp_sndrcvinfo sndrcvinfo;
struct sockaddr_in clientaddr;
int flags, bytes, sock_fd;
char buffer[1024]; // TODO: Let this be configurable?
socklen_t length;
@@ -454,43 +463,180 @@
);
if(bytes < 0)
rb_raise(rb_eSystemCallError, "sctp_recvmsg: %s", strerror(errno));
- // TODO: Check for MSG_NOTIFICATION, return different structs for events.
- /*
+ v_notification = Qnil;
+
if(flags & MSG_NOTIFICATION){
+ uint32_t i;
+ char str[16];
union sctp_notification* snp;
+ VALUE v_str;
+ VALUE* v_temp;
+
snp = (union sctp_notification*)buffer;
- switch(snp->sn_type){
+ switch(snp->sn_header.sn_type){
case SCTP_ASSOC_CHANGE:
+ switch(snp->sn_assoc_change.sac_state){
+ case SCTP_COMM_LOST:
+ v_str = rb_str_new2("comm lost");
+ break;
+ case SCTP_COMM_UP:
+ v_str = rb_str_new2("comm up");
+ break;
+ case SCTP_RESTART:
+ v_str = rb_str_new2("restart");
+ break;
+ case SCTP_SHUTDOWN_COMP:
+ v_str = rb_str_new2("shutdown complete");
+ break;
+ case SCTP_CANT_STR_ASSOC:
+ v_str = rb_str_new2("association setup failed");
+ break;
+ default:
+ v_str = rb_str_new2("unknown");
+ }
+
+ v_notification = rb_struct_new(v_assoc_change_struct,
+ UINT2NUM(snp->sn_assoc_change.sac_type),
+ UINT2NUM(snp->sn_assoc_change.sac_length),
+ UINT2NUM(snp->sn_assoc_change.sac_state),
+ UINT2NUM(snp->sn_assoc_change.sac_error),
+ UINT2NUM(snp->sn_assoc_change.sac_outbound_streams),
+ UINT2NUM(snp->sn_assoc_change.sac_inbound_streams),
+ UINT2NUM(snp->sn_assoc_change.sac_assoc_id),
+ v_str
+ );
break;
case SCTP_PEER_ADDR_CHANGE:
+ switch(snp->sn_paddr_change.spc_state){
+ case SCTP_ADDR_AVAILABLE:
+ v_str = rb_str_new2("available");
+ break;
+ case SCTP_ADDR_UNREACHABLE:
+ v_str = rb_str_new2("unreachable");
+ break;
+ case SCTP_ADDR_REMOVED:
+ v_str = rb_str_new2("removed from association");
+ break;
+ case SCTP_ADDR_ADDED:
+ v_str = rb_str_new2("added to association");
+ break;
+ case SCTP_ADDR_MADE_PRIM:
+ v_str = rb_str_new2("primary destination");
+ break;
+ default:
+ v_str = rb_str_new2("unknown");
+ }
+
+ inet_ntop(
+ ((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_family,
+ &(((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_addr),
+ str,
+ sizeof(str)
+ );
+
+ v_notification = rb_struct_new(v_peeraddr_change_struct,
+ UINT2NUM(snp->sn_paddr_change.spc_type),
+ UINT2NUM(snp->sn_paddr_change.spc_length),
+ rb_str_new2(str),
+ UINT2NUM(snp->sn_paddr_change.spc_state),
+ UINT2NUM(snp->sn_paddr_change.spc_error),
+ UINT2NUM(snp->sn_paddr_change.spc_assoc_id),
+ v_str
+ );
break;
case SCTP_REMOTE_ERROR:
+ v_temp = ALLOCA_N(VALUE, snp->sn_remote_error.sre_length);
+
+ for(i = 0; i < snp->sn_remote_error.sre_length; i++){
+ v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
+ }
+
+ v_notification = rb_struct_new(v_remote_error_struct,
+ UINT2NUM(snp->sn_remote_error.sre_type),
+ UINT2NUM(snp->sn_remote_error.sre_length),
+ UINT2NUM(snp->sn_remote_error.sre_error),
+ UINT2NUM(snp->sn_remote_error.sre_assoc_id),
+ rb_ary_new4(snp->sn_remote_error.sre_length, v_temp)
+ );
break;
- case SCTP_SEND_FAILED:
+ case SCTP_SEND_FAILED_EVENT:
+ v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssf_length);
+
+ for(i = 0; i < snp->sn_send_failed_event.ssf_length; i++){
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
+ }
+
+ v_notification = rb_struct_new(v_send_failed_event_struct,
+ UINT2NUM(snp->sn_send_failed_event.ssf_type),
+ UINT2NUM(snp->sn_send_failed_event.ssf_length),
+ UINT2NUM(snp->sn_send_failed_event.ssf_error),
+ rb_struct_new(v_sndinfo_struct,
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
+ ),
+ UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
+ rb_ary_new4(snp->sn_send_failed_event.ssf_length, v_temp)
+ );
break;
case SCTP_SHUTDOWN_EVENT:
+ v_notification = rb_struct_new(v_shutdown_event_struct,
+ UINT2NUM(snp->sn_shutdown_event.sse_type),
+ UINT2NUM(snp->sn_shutdown_event.sse_length),
+ UINT2NUM(snp->sn_shutdown_event.sse_assoc_id)
+ );
break;
case SCTP_ADAPTATION_INDICATION:
+ v_notification = rb_struct_new(v_adaptation_event_struct,
+ UINT2NUM(snp->sn_adaptation_event.sai_type),
+ UINT2NUM(snp->sn_adaptation_event.sai_length),
+ UINT2NUM(snp->sn_adaptation_event.sai_adaptation_ind),
+ UINT2NUM(snp->sn_adaptation_event.sai_assoc_id)
+ );
break;
case SCTP_PARTIAL_DELIVERY_EVENT:
+ v_notification = rb_struct_new(v_partial_delivery_event_struct,
+ UINT2NUM(snp->sn_pdapi_event.pdapi_type),
+ UINT2NUM(snp->sn_pdapi_event.pdapi_length),
+ UINT2NUM(snp->sn_pdapi_event.pdapi_indication),
+ UINT2NUM(snp->sn_pdapi_event.pdapi_stream),
+ UINT2NUM(snp->sn_pdapi_event.pdapi_seq),
+ UINT2NUM(snp->sn_pdapi_event.pdapi_assoc_id)
+ );
break;
+ case SCTP_AUTHENTICATION_EVENT:
+ v_notification = rb_struct_new(v_auth_event_struct,
+ UINT2NUM(snp->sn_authkey_event.auth_type),
+ UINT2NUM(snp->sn_authkey_event.auth_length),
+ UINT2NUM(snp->sn_authkey_event.auth_keynumber),
+ UINT2NUM(snp->sn_authkey_event.auth_indication),
+ UINT2NUM(snp->sn_authkey_event.auth_assoc_id)
+ );
+ break;
}
}
- */
+ if(NIL_P(v_notification))
+ v_message = rb_str_new(buffer, bytes);
+ else
+ v_message = Qnil;
+
return rb_struct_new(v_sndrcv_struct,
- rb_str_new(buffer, bytes),
+ v_message,
UINT2NUM(sndrcvinfo.sinfo_stream),
UINT2NUM(sndrcvinfo.sinfo_flags),
UINT2NUM(sndrcvinfo.sinfo_ppid),
UINT2NUM(sndrcvinfo.sinfo_context),
UINT2NUM(sndrcvinfo.sinfo_timetolive),
- UINT2NUM(sndrcvinfo.sinfo_assoc_id)
+ UINT2NUM(sndrcvinfo.sinfo_assoc_id),
+ v_notification
);
}
/*
* Set the initial parameters used by the socket when sending out the INIT message.
@@ -556,18 +702,23 @@
* - The message could not be delivered to a peer.
*
* :shutdown
* - The peer has sent a shutdown to the local endpoint.
*
+ * :data_io
+ * - Message data was received. On by default.
+ *
* Others:
*
- * :adaptation_layer
- * :authentication_event
- * :data_io
- * :peer_error
+ * :adaptation
+ * :authentication
* :partial_delivery
+ *
+ * Not yet supported:
+ *
* :sender_dry
+ * :peer_error
*
* By default only data_io is subscribed to.
*
* Example:
*
@@ -590,12 +741,13 @@
events.sctp_association_event = 1;
if(RTEST(rb_hash_aref2(v_options, "address")))
events.sctp_address_event = 1;
+ // Use the new version
if(RTEST(rb_hash_aref2(v_options, "send_failure")))
- events.sctp_send_failure_event = 1;
+ events.sctp_send_failure_event_event = 1;
if(RTEST(rb_hash_aref2(v_options, "peer_error")))
events.sctp_peer_error_event = 1;
if(RTEST(rb_hash_aref2(v_options, "shutdown")))
@@ -698,14 +850,53 @@
void Init_socket(){
mSCTP = rb_define_module("SCTP");
cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
v_sndrcv_struct = rb_struct_define(
- "SndRecvInfo", "message", "stream", "flags",
- "ppid", "context", "ttl", "association_id", NULL
+ "SendReceiveInfo", "message", "stream", "flags",
+ "ppid", "context", "ttl", "association_id", "notification", NULL
);
+ v_assoc_change_struct = rb_struct_define(
+ "AssocChange", "type", "length", "state", "error",
+ "outbound_streams", "inbound_streams", "association_id", "info", NULL
+ );
+
+ v_peeraddr_change_struct = rb_struct_define(
+ "PeerAddrChange", "type", "length", "ip_address",
+ "state", "error", "association_id", "info", NULL
+ );
+
+ v_remote_error_struct = rb_struct_define(
+ "RemoteError", "type", "length", "error", "association_id", "data", NULL
+ );
+
+ v_send_failed_event_struct = rb_struct_define(
+ "SendFailedEvent", "type", "length", "error", "association_id", "data", NULL
+ );
+
+ v_shutdown_event_struct = rb_struct_define(
+ "ShutdownEvent", "type", "length", "association_id", NULL
+ );
+
+ v_sndinfo_struct = rb_struct_define(
+ "SendInfo", "sid", "flags", "ppid", "context", "association_id", NULL
+ );
+
+ v_adaptation_event_struct = rb_struct_define(
+ "AdaptationEvent", "type", "length", "adaptation_indication", "association_id", NULL
+ );
+
+ v_partial_delivery_event_struct = rb_struct_define(
+ "PartialDeliveryEvent", "type", "length", "indication", "stream",
+ "sequence_number", "association_id", NULL
+ );
+
+ v_auth_event_struct = rb_struct_define(
+ "AuthEvent", "type", "length", "key_number", "indication", "association_id", NULL
+ );
+
rb_define_method(cSocket, "initialize", rsctp_init, -1);
rb_define_method(cSocket, "bind", rsctp_bind, -1);
rb_define_method(cSocket, "close", rsctp_close, 0);
rb_define_method(cSocket, "connect", rsctp_connect, -1);
@@ -724,7 +915,7 @@
rb_define_attr(cSocket, "sock_fd", 1, 1);
rb_define_attr(cSocket, "association_id", 1, 1);
rb_define_attr(cSocket, "port", 1, 1);
/* 0.0.2: The version of this library */
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.2"));
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.3"));
}