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));