ext/sctp/socket.c in sctp-socket-0.1.1 vs ext/sctp/socket.c in sctp-socket-0.1.2

- old
+ new

@@ -2,10 +2,14 @@ #include <string.h> #include <errno.h> #include <arpa/inet.h> #include <netinet/sctp.h> +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + VALUE mSCTP; VALUE cSocket; VALUE v_sndrcv_struct; VALUE v_assoc_change_struct; VALUE v_peeraddr_change_struct; @@ -161,10 +165,32 @@ rb_ary_new4(snp->sn_remote_error.sre_length, v_temp) ); break; #ifdef SCTP_SEND_FAILED_EVENT case SCTP_SEND_FAILED_EVENT: +#ifdef HAVE_STRUCT_SCTP_SEND_FAILED_EVENT_SSFE_LENGTH + v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssfe_length); + + for(i = 0; i < snp->sn_send_failed_event.ssfe_length; i++){ + v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssfe_data[i]); + } + + v_notification = rb_struct_new(v_send_failed_event_struct, + UINT2NUM(snp->sn_send_failed_event.ssfe_type), + UINT2NUM(snp->sn_send_failed_event.ssfe_length), + UINT2NUM(snp->sn_send_failed_event.ssfe_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.ssfe_assoc_id), + rb_ary_new4(snp->sn_send_failed_event.ssfe_length, v_temp) + ); +#else 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]); } @@ -181,10 +207,11 @@ 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) ); +#endif break; #else case SCTP_SEND_FAILED: v_temp = ALLOCA_N(VALUE, snp->sn_send_failed.ssf_length); @@ -227,15 +254,23 @@ UINT2NUM(snp->sn_pdapi_event.pdapi_assoc_id) ); break; case SCTP_AUTHENTICATION_EVENT: v_notification = rb_struct_new(v_auth_event_struct, +#ifdef HAVE_UNION_SCTP_NOTIFICATION_SN_AUTH_EVENT + UINT2NUM(snp->sn_auth_event.auth_type), + UINT2NUM(snp->sn_auth_event.auth_length), + UINT2NUM(snp->sn_auth_event.auth_keynumber), + UINT2NUM(snp->sn_auth_event.auth_indication), + UINT2NUM(snp->sn_auth_event.auth_assoc_id) +#else 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) +#endif ); break; case SCTP_SENDER_DRY_EVENT: v_notification = rb_struct_new(v_sender_dry_event_struct, UINT2NUM(snp->sn_sender_dry_event.sender_dry_type), @@ -347,27 +382,33 @@ flags = NUM2INT(v_flags); if(NIL_P(v_addresses)) num_ip = 1; else - num_ip = RARRAY_LEN(v_addresses); + num_ip = (int)RARRAY_LEN(v_addresses); domain = NUM2INT(rb_iv_get(self, "@domain")); fileno = NUM2INT(rb_iv_get(self, "@fileno")); if(num_ip > 1){ for(i = 0; i < num_ip; i++){ v_address = RARRAY_PTR(v_addresses)[i]; addrs[i].sin_family = domain; addrs[i].sin_port = htons(port); addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address)); +#ifdef BSD + addrs[i].sin_len = sizeof(struct sockaddr_in); +#endif } } else{ addrs[0].sin_family = domain; addrs[0].sin_port = htons(port); addrs[0].sin_addr.s_addr = htonl(INADDR_ANY); +#ifdef BSD + addrs[0].sin_len = sizeof(struct sockaddr_in); +#endif } if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0) rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno)); @@ -425,18 +466,21 @@ if(NIL_P(v_port)) rb_raise(rb_eArgError, "you must specify a port"); v_domain = rb_iv_get(self, "@domain"); - num_ip = RARRAY_LEN(v_addresses); + num_ip = (int)RARRAY_LEN(v_addresses); bzero(&addrs, sizeof(addrs)); for(i = 0; i < num_ip; i++){ v_address = RARRAY_PTR(v_addresses)[i]; addrs[i].sin_family = NUM2INT(v_domain); addrs[i].sin_port = htons(NUM2INT(v_port)); addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address)); +#ifdef BSD + addrs[i].sin_len = sizeof(struct sockaddr_in); +#endif } fileno = NUM2INT(rb_iv_get(self, "@fileno")); if(sctp_connectx(fileno, (struct sockaddr *) addrs, num_ip, &assoc) < 0) @@ -615,11 +659,12 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){ VALUE v_msg, v_message, v_addresses; struct iovec iov[IOV_MAX]; struct sockaddr_in* addrs; struct sctp_sendv_spa spa; - int i, fileno, num_bytes, size, num_ip; + int i, fileno, size, num_ip; + ssize_t num_bytes; Check_Type(v_options, T_HASH); bzero(&iov, sizeof(iov)); bzero(&spa, sizeof(spa)); @@ -630,20 +675,20 @@ if(!NIL_P(v_message)) Check_Type(v_message, T_ARRAY); if(!NIL_P(v_addresses)){ Check_Type(v_addresses, T_ARRAY); - num_ip = RARRAY_LEN(v_addresses); + num_ip = (int)RARRAY_LEN(v_addresses); addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(*addrs)); } else{ addrs = NULL; num_ip = 0; } fileno = NUM2INT(rb_iv_get(self, "@fileno")); - size = RARRAY_LEN(v_message); + size = (int)RARRAY_LEN(v_message); if(!size) rb_raise(rb_eArgError, "Must contain at least one message"); if(size > IOV_MAX) @@ -669,20 +714,23 @@ for(i = 0; i < num_ip; i++){ v_address = RARRAY_PTR(v_addresses)[i]; addrs[i].sin_family = domain; addrs[i].sin_port = htons(port); addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address)); +#ifdef BSD + addrs[i].sin_len = sizeof(struct sockaddr_in); +#endif } } for(i = 0; i < size; i++){ v_msg = RARRAY_PTR(v_message)[i]; iov[i].iov_base = StringValueCStr(v_msg); iov[i].iov_len = RSTRING_LEN(v_msg); } - num_bytes = sctp_sendv( + num_bytes = (ssize_t)sctp_sendv( fileno, iov, size, (struct sockaddr*)addrs, num_ip, @@ -693,18 +741,19 @@ ); if(num_bytes < 0) rb_raise(rb_eSystemCallError, "sctp_sendv: %s", strerror(errno)); - return INT2NUM(num_bytes); + return LONG2NUM(num_bytes); } #endif #ifdef HAVE_SCTP_RECVV static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){ VALUE v_flags; - int fileno, flags, bytes, on; + int fileno, flags, on; + ssize_t bytes; uint infotype; socklen_t infolen; struct iovec iov[1]; struct sctp_rcvinfo info; char buffer[1024]; @@ -730,11 +779,11 @@ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno)); infolen = sizeof(struct sctp_rcvinfo); infotype = 0; - bytes = sctp_recvv( + bytes = (ssize_t)sctp_recvv( fileno, iov, 1, NULL, NULL, @@ -847,22 +896,22 @@ info.sinfo_timetolive = ttl; info.sinfo_assoc_id = assoc_id; fileno = NUM2INT(rb_iv_get(self, "@fileno")); - num_bytes = sctp_send( + num_bytes = (ssize_t)sctp_send( fileno, StringValueCStr(v_msg), RSTRING_LEN(v_msg), &info, ctrl_flags ); if(num_bytes < 0) rb_raise(rb_eSystemCallError, "sctp_send: %s", strerror(errno)); - return INT2NUM(num_bytes); + return LONG2NUM(num_bytes); } /* * call-seq: * SCTP::Socket#sendmsg(options) @@ -899,11 +948,11 @@ VALUE v_msg, v_ppid, v_flags, v_stream, v_ttl, v_context, v_addresses; uint16_t stream; uint32_t ppid, flags, ttl, context; ssize_t num_bytes; struct sockaddr_in addrs[8]; - int fileno, size; + int fileno, size, num_ip; Check_Type(v_options, T_HASH); bzero(&addrs, sizeof(addrs)); @@ -942,14 +991,14 @@ context = 0; else context = NUM2INT(v_context); if(!NIL_P(v_addresses)){ - int i, num_ip, port; + int i, port; VALUE v_address, v_port; - num_ip = RARRAY_LEN(v_addresses); + num_ip = (int)RARRAY_LEN(v_addresses); v_port = rb_hash_aref2(v_options, "port"); if(NIL_P(v_port)) port = 0; else @@ -958,21 +1007,55 @@ for(i = 0; i < num_ip; i++){ v_address = RARRAY_PTR(v_addresses)[i]; addrs[i].sin_family = NUM2INT(rb_iv_get(self, "@domain")); addrs[i].sin_port = htons(port); addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address)); +#ifdef BSD + addrs[i].sin_len = sizeof(struct sockaddr_in); +#endif } size = sizeof(addrs); } else{ + num_ip = 0; size = 0; } fileno = NUM2INT(rb_iv_get(self, "@fileno")); - num_bytes = sctp_sendmsg( +#ifdef BSD + if(num_ip){ + num_bytes = (ssize_t)sctp_sendmsgx( + fileno, + StringValueCStr(v_msg), + RSTRING_LEN(v_msg), + (struct sockaddr*)addrs, + num_ip, + ppid, + flags, + stream, + ttl, + context + ); + } + else{ + num_bytes = (ssize_t)sctp_sendmsg( + fileno, + StringValueCStr(v_msg), + RSTRING_LEN(v_msg), + (struct sockaddr*)addrs, + size, + ppid, + flags, + stream, + ttl, + context + ); + } +#else + num_bytes = (ssize_t)sctp_sendmsg( fileno, StringValueCStr(v_msg), RSTRING_LEN(v_msg), (struct sockaddr*)addrs, size, @@ -980,15 +1063,24 @@ flags, stream, ttl, context ); +#endif - if(num_bytes < 0) + if(num_bytes < 0){ +#ifdef BSD + if(num_ip > 0) + rb_raise(rb_eSystemCallError, "sctp_sendmsgx: %s", strerror(errno)); + else + rb_raise(rb_eSystemCallError, "sctp_sendmsg: %s", strerror(errno)); +#else rb_raise(rb_eSystemCallError, "sctp_sendmsg: %s", strerror(errno)); +#endif + } - return INT2NUM(num_bytes); + return LONG2NUM(num_bytes); } /* * call-seq: * SCTP::Socket#recvmsg(flags=0) @@ -1013,11 +1105,12 @@ */ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){ VALUE v_flags, v_notification, v_message; struct sctp_sndrcvinfo sndrcvinfo; struct sockaddr_in clientaddr; - int flags, bytes, fileno; + int flags, fileno; + ssize_t bytes; char buffer[1024]; // TODO: Let this be configurable? socklen_t length; rb_scan_args(argc, argv, "01", &v_flags); @@ -1031,11 +1124,11 @@ bzero(buffer, sizeof(buffer)); bzero(&clientaddr, sizeof(clientaddr)); bzero(&sndrcvinfo, sizeof(sndrcvinfo)); - bytes = sctp_recvmsg( + bytes = (ssize_t)sctp_recvmsg( fileno, buffer, sizeof(buffer), (struct sockaddr*)&clientaddr, &length, @@ -1553,25 +1646,34 @@ size = sizeof(struct sctp_event_subscribe); if(sctp_opt_info(fileno, assoc_id, SCTP_EVENTS, (void*)&events, &size) < 0) rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno)); - return rb_struct_new(v_sctp_event_subscribe_struct, + return rb_struct_new( + v_sctp_event_subscribe_struct, (events.sctp_data_io_event ? Qtrue : Qfalse), (events.sctp_association_event ? Qtrue : Qfalse), (events.sctp_address_event ? Qtrue : Qfalse), (events.sctp_send_failure_event ? Qtrue : Qfalse), (events.sctp_peer_error_event ? Qtrue : Qfalse), (events.sctp_shutdown_event ? Qtrue : Qfalse), (events.sctp_partial_delivery_event ? Qtrue : Qfalse), (events.sctp_adaptation_layer_event ? Qtrue : Qfalse), (events.sctp_authentication_event ? Qtrue : Qfalse), - (events.sctp_sender_dry_event ? Qtrue : Qfalse), - (events.sctp_stream_reset_event ? Qtrue : Qfalse), - (events.sctp_assoc_reset_event ? Qtrue : Qfalse), - (events.sctp_stream_change_event ? Qtrue : Qfalse), - (events.sctp_send_failure_event_event ? Qtrue : Qfalse) + (events.sctp_sender_dry_event ? Qtrue : Qfalse) +#ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_STREAM_RESET_EVENT + ,(events.sctp_stream_reset_event ? Qtrue : Qfalse) +#endif +#ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_ASSOC_RESET_EVENT + ,(events.sctp_assoc_reset_event ? Qtrue : Qfalse) +#endif +#ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_STREAM_CHANGE_EVENT + ,(events.sctp_stream_change_event ? Qtrue : Qfalse) +#endif +#ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_SEND_FAILURE_EVENT_EVENT + ,(events.sctp_send_failure_event_event ? Qtrue : Qfalse) +#endif ); } /* * call-seq: @@ -1724,10 +1826,44 @@ return Qfalse; } /* * call-seq: + * SCTP::Socket#disable_fragments=(bool) + * + * This option is a on/off flag and is passed an integer where a non- + * zero is on and a zero is off. If enabled no SCTP message + * fragmentation will be performed. Instead if a message being sent + * exceeds the current PMTU size, the message will NOT be sent and + * instead a error will be indicated to the user. + */ +static VALUE rsctp_disable_fragments(VALUE self, VALUE v_bool){ + int fileno; + socklen_t size; + sctp_assoc_t assoc_id; + int value; + + fileno = NUM2INT(rb_iv_get(self, "@fileno")); + assoc_id = NUM2INT(rb_iv_get(self, "@association_id")); + size = sizeof(int); + + if(NIL_P(v_bool) || v_bool == Qfalse) + value = 0; + else + value = 1; + + if(sctp_opt_info(fileno, assoc_id, SCTP_DISABLE_FRAGMENTS, (void*)&value, &size) < 0) + rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno)); + + if(value) + return Qtrue; + else + return Qfalse; +} + +/* + * call-seq: * SCTP::Socket#autoclose * * Returns the number of seconds before socket associations automatically * shut down. */ @@ -1843,11 +1979,12 @@ * For one-to-one sockets, this parameter is ignored. Note, however, that this * option will set a key on the association if the socket is connected, * otherwise this will set a key on the endpoint. */ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){ - int fileno, len; + int fileno; + size_t len; char* key; uint keynum; socklen_t size; sctp_assoc_t assoc_id; struct sctp_authkey* auth_key; @@ -1858,11 +1995,11 @@ fileno = NUM2INT(rb_iv_get(self, "@fileno")); key = StringValuePtr(v_key); len = strlen(key); unsigned char byte_array[len+1]; - for(int i = 0; i < len; i++) + for(size_t i = 0; i < len; i++) byte_array[i] = key[i]; byte_array[len] = '\0'; auth_key = malloc(sizeof(auth_key) + sizeof(char[strlen(key)+1])); @@ -2162,10 +2299,11 @@ rb_define_method(cSocket, "autoclose=", rsctp_set_autoclose, 1); rb_define_method(cSocket, "bindx", rsctp_bindx, -1); rb_define_method(cSocket, "close", rsctp_close, 0); rb_define_method(cSocket, "connectx", rsctp_connectx, -1); rb_define_method(cSocket, "delete_shared_key", rsctp_delete_shared_key, -1); + rb_define_method(cSocket, "disable_fragments=", rsctp_disable_fragments, 1); rb_define_method(cSocket, "enable_auth_support", rsctp_enable_auth_support, -1); rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1); rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1); rb_define_method(cSocket, "get_active_shared_key", rsctp_get_active_shared_key, -1); rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0); @@ -2204,12 +2342,12 @@ rb_define_attr(cSocket, "type", 1, 1); rb_define_attr(cSocket, "fileno", 1, 1); rb_define_attr(cSocket, "association_id", 1, 1); rb_define_attr(cSocket, "port", 1, 1); - /* 0.1.1: The version of this library */ - rb_define_const(cSocket, "VERSION", rb_str_new2("0.1.1")); + /* 0.1.2: The version of this library */ + rb_define_const(cSocket, "VERSION", rb_str_new2("0.1.2")); /* send flags */ /* Message is unordered */ rb_define_const(cSocket, "SCTP_UNORDERED", INT2NUM(SCTP_UNORDERED)); @@ -2228,10 +2366,12 @@ rb_define_const(cSocket, "MSG_NOTIFICATION", INT2NUM(MSG_NOTIFICATION)); // ASSOCIATION STATES // +#ifdef HAVE_SCTP_EMPTY rb_define_const(cSocket, "SCTP_EMPTY", INT2NUM(SCTP_EMPTY)); +#endif rb_define_const(cSocket, "SCTP_CLOSED", INT2NUM(SCTP_CLOSED)); rb_define_const(cSocket, "SCTP_COOKIE_WAIT", INT2NUM(SCTP_COOKIE_WAIT)); rb_define_const(cSocket, "SCTP_COOKIE_ECHOED", INT2NUM(SCTP_COOKIE_ECHOED)); rb_define_const(cSocket, "SCTP_ESTABLISHED", INT2NUM(SCTP_ESTABLISHED)); rb_define_const(cSocket, "SCTP_SHUTDOWN_PENDING", INT2NUM(SCTP_SHUTDOWN_PENDING));