sctp-socket 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/sctp/socket.c CHANGED
@@ -1,13 +1,15 @@
1
1
  #include "ruby.h"
2
+ #include <ruby/thread.h>
2
3
  #include <string.h>
3
4
  #include <errno.h>
4
5
  #include <arpa/inet.h>
5
- #include <netinet/sctp.h>
6
6
 
7
7
  #ifdef HAVE_SYS_PARAM_H
8
8
  #include <sys/param.h>
9
9
  #endif
10
10
 
11
+ #include "sctp_compat.h"
12
+
11
13
  VALUE mSCTP;
12
14
  VALUE cSocket;
13
15
  VALUE v_sndrcv_struct;
@@ -41,7 +43,7 @@ VALUE v_sctp_initmsg_struct;
41
43
 
42
44
  // Memory safety and error handling macros
43
45
  #define CHECK_FILENO_VALID(fileno) do { \
44
- if ((fileno) < 0) { \
46
+ if (SCTP_FD_INVALID(fileno)) { \
45
47
  rb_raise(rb_eSystemCallError, "invalid file descriptor"); \
46
48
  } \
47
49
  } while(0)
@@ -54,8 +56,7 @@ VALUE v_sctp_initmsg_struct;
54
56
  } while(0)
55
57
 
56
58
  #define CHECK_SOCKET_CLOSED(self) do { \
57
- VALUE v_fileno = rb_iv_get((self), "@fileno"); \
58
- if (NIL_P(v_fileno) || NUM2INT(v_fileno) < 0) { \
59
+ if (NIL_P(rb_iv_get((self), "@fileno"))) { \
59
60
  rb_raise(rb_eIOError, "socket is closed"); \
60
61
  } \
61
62
  } while(0)
@@ -63,6 +64,65 @@ VALUE v_sctp_initmsg_struct;
63
64
  #define MAX_IP_ADDRESSES 8
64
65
  #define DEFAULT_BUFFER_SIZE 1024
65
66
  #define IP_BUFFER_SIZE INET6_ADDRSTRLEN
67
+ #define MAX_NOTIFICATION_DATA 8192
68
+
69
+ /*
70
+ * Helper function to parse an IP address string and fill a sockaddr_in or sockaddr_in6 structure.
71
+ * Supports both IPv4 and IPv6 addresses.
72
+ *
73
+ * @param addr_str The IP address string to parse
74
+ * @param port The port number (in host byte order)
75
+ * @param sin Pointer to sockaddr_in to fill (for IPv4)
76
+ * @param sin6 Pointer to sockaddr_in6 to fill (for IPv6)
77
+ * @param domain The address family (AF_INET or AF_INET6)
78
+ */
79
+ static void parse_ip_address_v4(const char* addr_str, int port, struct sockaddr_in* sin){
80
+ bzero(sin, sizeof(*sin));
81
+ sin->sin_family = AF_INET;
82
+ sin->sin_port = htons(port);
83
+ if(inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1)
84
+ rb_raise(rb_eArgError, "invalid IPv4 address: %s", addr_str);
85
+ #ifdef BSD
86
+ sin->sin_len = sizeof(struct sockaddr_in);
87
+ #endif
88
+ }
89
+
90
+ static void parse_ip_address_v6(const char* addr_str, int port, struct sockaddr_in6* sin6){
91
+ bzero(sin6, sizeof(*sin6));
92
+ sin6->sin6_family = AF_INET6;
93
+ sin6->sin6_port = htons(port);
94
+ if(inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1)
95
+ rb_raise(rb_eArgError, "invalid IPv6 address: %s", addr_str);
96
+ #ifdef BSD
97
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
98
+ #endif
99
+ }
100
+
101
+ /*
102
+ * Helper function to set INADDR_ANY for IPv4.
103
+ */
104
+ static void set_any_address_v4(int port, struct sockaddr_in* sin){
105
+ bzero(sin, sizeof(*sin));
106
+ sin->sin_family = AF_INET;
107
+ sin->sin_port = htons(port);
108
+ sin->sin_addr.s_addr = htonl(INADDR_ANY);
109
+ #ifdef BSD
110
+ sin->sin_len = sizeof(struct sockaddr_in);
111
+ #endif
112
+ }
113
+
114
+ /*
115
+ * Helper function to set IN6ADDR_ANY for IPv6.
116
+ */
117
+ static void set_any_address_v6(int port, struct sockaddr_in6* sin6){
118
+ bzero(sin6, sizeof(*sin6));
119
+ sin6->sin6_family = AF_INET6;
120
+ sin6->sin6_port = htons(port);
121
+ sin6->sin6_addr = in6addr_any;
122
+ #ifdef BSD
123
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
124
+ #endif
125
+ }
66
126
 
67
127
  /*
68
128
  * Convert a sockaddr_in structure to a Ruby struct.
@@ -197,12 +257,18 @@ VALUE get_notification_info(char* buffer){
197
257
  v_str = rb_str_new2("unknown");
198
258
  }
199
259
 
200
- inet_ntop(
201
- ((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_family,
202
- &(((struct sockaddr_in *)&snp->sn_paddr_change.spc_aaddr)->sin_addr),
203
- str,
204
- sizeof(str)
205
- );
260
+ {
261
+ struct sockaddr* sa = (struct sockaddr*)&snp->sn_paddr_change.spc_aaddr;
262
+
263
+ if(sa->sa_family == AF_INET6){
264
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
265
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
266
+ }
267
+ else{
268
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
269
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
270
+ }
271
+ }
206
272
 
207
273
  v_notification = rb_struct_new(v_peeraddr_change_struct,
208
274
  UINT2NUM(snp->sn_paddr_change.spc_type),
@@ -215,83 +281,150 @@ VALUE get_notification_info(char* buffer){
215
281
  );
216
282
  break;
217
283
  case SCTP_REMOTE_ERROR:
218
- v_temp = ALLOCA_N(VALUE, snp->sn_remote_error.sre_length);
219
-
220
- for(i = 0; i < snp->sn_remote_error.sre_length; i++){
221
- v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
284
+ {
285
+ size_t data_len = 0;
286
+ VALUE v_data_ary;
287
+
288
+ // Calculate actual data length (total length minus fixed header)
289
+ if(snp->sn_remote_error.sre_length > offsetof(struct sctp_remote_error, sre_data))
290
+ data_len = snp->sn_remote_error.sre_length - offsetof(struct sctp_remote_error, sre_data);
291
+
292
+ // Bounds check to prevent stack overflow
293
+ if(data_len > MAX_NOTIFICATION_DATA)
294
+ data_len = MAX_NOTIFICATION_DATA;
295
+
296
+ if(data_len > 0){
297
+ v_temp = ALLOCA_N(VALUE, data_len);
298
+ for(i = 0; i < data_len; i++){
299
+ v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
300
+ }
301
+ v_data_ary = rb_ary_new4(data_len, v_temp);
302
+ }
303
+ else{
304
+ v_data_ary = rb_ary_new();
305
+ }
306
+
307
+ v_notification = rb_struct_new(v_remote_error_struct,
308
+ UINT2NUM(snp->sn_remote_error.sre_type),
309
+ UINT2NUM(snp->sn_remote_error.sre_flags),
310
+ UINT2NUM(snp->sn_remote_error.sre_length),
311
+ UINT2NUM(snp->sn_remote_error.sre_error),
312
+ UINT2NUM(snp->sn_remote_error.sre_assoc_id),
313
+ v_data_ary
314
+ );
222
315
  }
223
-
224
- v_notification = rb_struct_new(v_remote_error_struct,
225
- UINT2NUM(snp->sn_remote_error.sre_type),
226
- UINT2NUM(snp->sn_remote_error.sre_flags),
227
- UINT2NUM(snp->sn_remote_error.sre_length),
228
- UINT2NUM(snp->sn_remote_error.sre_error),
229
- UINT2NUM(snp->sn_remote_error.sre_assoc_id),
230
- rb_ary_new4(snp->sn_remote_error.sre_length, v_temp)
231
- );
232
316
  break;
233
317
  #ifdef SCTP_SEND_FAILED_EVENT
234
318
  case SCTP_SEND_FAILED_EVENT:
235
- #ifdef HAVE_STRUCT_SCTP_SEND_FAILED_EVENT_SSFE_LENGTH
236
- v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssfe_length);
319
+ {
320
+ size_t data_len = 0;
321
+ VALUE v_data_ary;
237
322
 
238
- for(i = 0; i < snp->sn_send_failed_event.ssfe_length; i++){
239
- v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssfe_data[i]);
240
- }
241
-
242
- v_notification = rb_struct_new(v_send_failed_event_struct,
243
- UINT2NUM(snp->sn_send_failed_event.ssfe_type),
244
- UINT2NUM(snp->sn_send_failed_event.ssfe_length),
245
- UINT2NUM(snp->sn_send_failed_event.ssfe_error),
246
- rb_struct_new(v_sndinfo_struct,
247
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
248
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
249
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
250
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
251
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
252
- ),
253
- UINT2NUM(snp->sn_send_failed_event.ssfe_assoc_id),
254
- rb_ary_new4(snp->sn_send_failed_event.ssfe_length, v_temp)
255
- );
323
+ #ifdef HAVE_STRUCT_SCTP_SEND_FAILED_EVENT_SSFE_LENGTH
324
+ // Calculate actual data length (total length minus fixed header)
325
+ if(snp->sn_send_failed_event.ssfe_length > offsetof(struct sctp_send_failed_event, ssfe_data))
326
+ data_len = snp->sn_send_failed_event.ssfe_length - offsetof(struct sctp_send_failed_event, ssfe_data);
327
+
328
+ // Bounds check to prevent stack overflow
329
+ if(data_len > MAX_NOTIFICATION_DATA)
330
+ data_len = MAX_NOTIFICATION_DATA;
331
+
332
+ if(data_len > 0){
333
+ v_temp = ALLOCA_N(VALUE, data_len);
334
+ for(i = 0; i < data_len; i++){
335
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssfe_data[i]);
336
+ }
337
+ v_data_ary = rb_ary_new4(data_len, v_temp);
338
+ }
339
+ else{
340
+ v_data_ary = rb_ary_new();
341
+ }
342
+
343
+ v_notification = rb_struct_new(v_send_failed_event_struct,
344
+ UINT2NUM(snp->sn_send_failed_event.ssfe_type),
345
+ UINT2NUM(snp->sn_send_failed_event.ssfe_length),
346
+ UINT2NUM(snp->sn_send_failed_event.ssfe_error),
347
+ rb_struct_new(v_sndinfo_struct,
348
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
349
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
350
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
351
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
352
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
353
+ ),
354
+ UINT2NUM(snp->sn_send_failed_event.ssfe_assoc_id),
355
+ v_data_ary
356
+ );
256
357
  #else
257
- v_temp = ALLOCA_N(VALUE, snp->sn_send_failed_event.ssf_length);
258
-
259
- for(i = 0; i < snp->sn_send_failed_event.ssf_length; i++){
260
- v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
261
- }
262
-
263
- v_notification = rb_struct_new(v_send_failed_event_struct,
264
- UINT2NUM(snp->sn_send_failed_event.ssf_type),
265
- UINT2NUM(snp->sn_send_failed_event.ssf_length),
266
- UINT2NUM(snp->sn_send_failed_event.ssf_error),
267
- rb_struct_new(v_sndinfo_struct,
268
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
269
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
270
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
271
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
272
- UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
273
- ),
274
- UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
275
- rb_ary_new4(snp->sn_send_failed_event.ssf_length, v_temp)
276
- );
358
+ // Calculate actual data length (total length minus fixed header)
359
+ if(snp->sn_send_failed_event.ssf_length > offsetof(struct sctp_send_failed_event, ssf_data))
360
+ data_len = snp->sn_send_failed_event.ssf_length - offsetof(struct sctp_send_failed_event, ssf_data);
361
+
362
+ // Bounds check to prevent stack overflow
363
+ if(data_len > MAX_NOTIFICATION_DATA)
364
+ data_len = MAX_NOTIFICATION_DATA;
365
+
366
+ if(data_len > 0){
367
+ v_temp = ALLOCA_N(VALUE, data_len);
368
+ for(i = 0; i < data_len; i++){
369
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
370
+ }
371
+ v_data_ary = rb_ary_new4(data_len, v_temp);
372
+ }
373
+ else{
374
+ v_data_ary = rb_ary_new();
375
+ }
376
+
377
+ v_notification = rb_struct_new(v_send_failed_event_struct,
378
+ UINT2NUM(snp->sn_send_failed_event.ssf_type),
379
+ UINT2NUM(snp->sn_send_failed_event.ssf_length),
380
+ UINT2NUM(snp->sn_send_failed_event.ssf_error),
381
+ rb_struct_new(v_sndinfo_struct,
382
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
383
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
384
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
385
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
386
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
387
+ ),
388
+ UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
389
+ v_data_ary
390
+ );
277
391
  #endif
392
+ }
278
393
  break;
279
394
  #else
280
395
  case SCTP_SEND_FAILED:
281
- v_temp = ALLOCA_N(VALUE, snp->sn_send_failed.ssf_length);
282
-
283
- for(i = 0; i < snp->sn_send_failed.ssf_length; i++){
284
- v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
396
+ {
397
+ size_t data_len = 0;
398
+ VALUE v_data_ary;
399
+
400
+ // Calculate actual data length (total length minus fixed header)
401
+ if(snp->sn_send_failed.ssf_length > offsetof(struct sctp_send_failed, ssf_data))
402
+ data_len = snp->sn_send_failed.ssf_length - offsetof(struct sctp_send_failed, ssf_data);
403
+
404
+ // Bounds check to prevent stack overflow
405
+ if(data_len > MAX_NOTIFICATION_DATA)
406
+ data_len = MAX_NOTIFICATION_DATA;
407
+
408
+ if(data_len > 0){
409
+ v_temp = ALLOCA_N(VALUE, data_len);
410
+ for(i = 0; i < data_len; i++){
411
+ v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
412
+ }
413
+ v_data_ary = rb_ary_new4(data_len, v_temp);
414
+ }
415
+ else{
416
+ v_data_ary = rb_ary_new();
417
+ }
418
+
419
+ v_notification = rb_struct_new(v_send_failed_event_struct,
420
+ UINT2NUM(snp->sn_send_failed.ssf_type),
421
+ UINT2NUM(snp->sn_send_failed.ssf_length),
422
+ UINT2NUM(snp->sn_send_failed.ssf_error),
423
+ Qnil,
424
+ UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
425
+ v_data_ary
426
+ );
285
427
  }
286
-
287
- v_notification = rb_struct_new(v_send_failed_event_struct,
288
- UINT2NUM(snp->sn_send_failed.ssf_type),
289
- UINT2NUM(snp->sn_send_failed.ssf_length),
290
- UINT2NUM(snp->sn_send_failed.ssf_error),
291
- Qnil,
292
- UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
293
- rb_ary_new4(snp->sn_send_failed.ssf_length, v_temp)
294
- );
295
428
  break;
296
429
  #endif
297
430
  case SCTP_SHUTDOWN_EVENT:
@@ -370,7 +503,7 @@ VALUE get_notification_info(char* buffer){
370
503
  * socket2 = SCTP::Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
371
504
  */
372
505
  static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
373
- int fileno;
506
+ sctp_sock_t fileno;
374
507
  VALUE v_domain, v_type;
375
508
 
376
509
  rb_scan_args(argc, argv, "02", &v_domain, &v_type);
@@ -394,14 +527,14 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
394
527
  rb_raise(rb_eArgError, "unsupported socket type: %d", type);
395
528
  }
396
529
 
397
- fileno = socket(NUM2INT(v_domain), NUM2INT(v_type), IPPROTO_SCTP);
530
+ fileno = sctp_sys_socket(NUM2INT(v_domain), NUM2INT(v_type), IPPROTO_SCTP);
398
531
 
399
- if(fileno < 0)
532
+ if(SCTP_FD_INVALID(fileno))
400
533
  rb_raise(rb_eSystemCallError, "socket: %s", strerror(errno));
401
534
 
402
535
  rb_iv_set(self, "@domain", v_domain);
403
536
  rb_iv_set(self, "@type", v_type);
404
- rb_iv_set(self, "@fileno", INT2NUM(fileno));
537
+ rb_iv_set(self, "@fileno", SCTP_FD_TO_NUM(fileno));
405
538
  rb_iv_set(self, "@association_id", INT2NUM(0));
406
539
 
407
540
  return self;
@@ -451,14 +584,12 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
451
584
  * Returns the port that it was bound to.
452
585
  */
453
586
  static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
454
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
455
- int i, fileno, num_ip, flags, domain, port, on;
587
+ sctp_sock_t fileno;
588
+ int i, num_ip, flags, domain, port, on;
456
589
  VALUE v_addresses, v_port, v_flags, v_address, v_reuse_addr, v_options;
457
590
 
458
591
  rb_scan_args(argc, argv, "01", &v_options);
459
592
 
460
- bzero(&addrs, sizeof(addrs));
461
-
462
593
  if(NIL_P(v_options))
463
594
  v_options = rb_hash_new();
464
595
 
@@ -485,44 +616,63 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
485
616
  if(num_ip > MAX_IP_ADDRESSES)
486
617
  rb_raise(rb_eArgError, "too many IP addresses to bind, maximum is eight");
487
618
 
619
+ CHECK_SOCKET_CLOSED(self);
620
+
488
621
  domain = NUM2INT(rb_iv_get(self, "@domain"));
489
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
622
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
490
623
 
491
- if(!NIL_P(v_addresses)){
492
- for(i = 0; i < num_ip; i++){
493
- v_address = RARRAY_PTR(v_addresses)[i];
494
- addrs[i].sin_family = domain;
495
- addrs[i].sin_port = htons(port);
496
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
497
- #ifdef BSD
498
- addrs[i].sin_len = sizeof(struct sockaddr_in);
624
+ if(v_reuse_addr == Qtrue){
625
+ on = 1;
626
+ #ifdef HAVE_USRSCTP_H
627
+ /* usrsctp runs in userspace; address reuse is not needed/supported. Silently skip. */
628
+ (void)on;
629
+ #else
630
+ if(sctp_sys_setsockopt(fileno, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
631
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
499
632
  #endif
633
+ }
634
+
635
+ if(domain == AF_INET6){
636
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
637
+ bzero(&addrs6, sizeof(addrs6));
638
+
639
+ if(!NIL_P(v_addresses)){
640
+ for(i = 0; i < num_ip; i++){
641
+ v_address = RARRAY_AREF(v_addresses, i);
642
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
643
+ }
500
644
  }
645
+ else{
646
+ set_any_address_v6(port, &addrs6[0]);
647
+ }
648
+
649
+ if(sctp_sys_bindx(fileno, (struct sockaddr *)addrs6, num_ip, flags) != 0)
650
+ rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
501
651
  }
502
652
  else{
503
- addrs[0].sin_family = domain;
504
- addrs[0].sin_port = htons(port);
505
- addrs[0].sin_addr.s_addr = htonl(INADDR_ANY);
506
- #ifdef BSD
507
- addrs[0].sin_len = sizeof(struct sockaddr_in);
508
- #endif
509
- }
653
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
654
+ bzero(&addrs, sizeof(addrs));
510
655
 
511
- if(v_reuse_addr == Qtrue){
512
- on = 1;
513
- if(setsockopt(fileno, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
514
- rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
515
- }
656
+ if(!NIL_P(v_addresses)){
657
+ for(i = 0; i < num_ip; i++){
658
+ v_address = RARRAY_AREF(v_addresses, i);
659
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
660
+ }
661
+ }
662
+ else{
663
+ set_any_address_v4(port, &addrs[0]);
664
+ }
516
665
 
517
- if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0)
518
- rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
666
+ if(sctp_sys_bindx(fileno, (struct sockaddr *)addrs, num_ip, flags) != 0)
667
+ rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
668
+ }
519
669
 
520
670
  if(port == 0){
521
671
  struct sockaddr_in sin;
522
672
  socklen_t len = sizeof(sin);
523
673
  bzero(&sin, len);
524
674
 
525
- if(getsockname(fileno, (struct sockaddr *)&sin, &len) == -1)
675
+ if(sctp_sys_getsockname(fileno, (struct sockaddr *)&sin, &len) == -1)
526
676
  rb_raise(rb_eSystemCallError, "getsockname: %s", strerror(errno));
527
677
 
528
678
  port = sin.sin_port;
@@ -550,10 +700,10 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
550
700
  * methods will automatically establish associations.
551
701
  */
552
702
  static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
553
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
554
- int i, num_ip, fileno;
703
+ sctp_sock_t fileno;
704
+ int i, num_ip, domain, port;
555
705
  sctp_assoc_t assoc;
556
- VALUE v_address, v_domain, v_options, v_addresses, v_port;
706
+ VALUE v_address, v_options, v_addresses, v_port;
557
707
 
558
708
  rb_scan_args(argc, argv, "01", &v_options);
559
709
 
@@ -571,25 +721,41 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
571
721
  if(NIL_P(v_port))
572
722
  rb_raise(rb_eArgError, "you must specify a port");
573
723
 
574
- v_domain = rb_iv_get(self, "@domain");
724
+ CHECK_SOCKET_CLOSED(self);
725
+
726
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
727
+ port = NUM2INT(v_port);
728
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
575
729
 
576
730
  num_ip = (int)RARRAY_LEN(v_addresses);
577
- bzero(&addrs, sizeof(addrs));
578
731
 
579
- for(i = 0; i < num_ip; i++){
580
- v_address = RARRAY_PTR(v_addresses)[i];
581
- addrs[i].sin_family = NUM2INT(v_domain);
582
- addrs[i].sin_port = htons(NUM2INT(v_port));
583
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
584
- #ifdef BSD
585
- addrs[i].sin_len = sizeof(struct sockaddr_in);
586
- #endif
732
+ if(num_ip > MAX_IP_ADDRESSES)
733
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
734
+
735
+ if(domain == AF_INET6){
736
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
737
+ bzero(&addrs6, sizeof(addrs6));
738
+
739
+ for(i = 0; i < num_ip; i++){
740
+ v_address = RARRAY_AREF(v_addresses, i);
741
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
742
+ }
743
+
744
+ if(sctp_sys_connectx(fileno, (struct sockaddr *)addrs6, num_ip, &assoc) < 0)
745
+ rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
587
746
  }
747
+ else{
748
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
749
+ bzero(&addrs, sizeof(addrs));
588
750
 
589
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
751
+ for(i = 0; i < num_ip; i++){
752
+ v_address = RARRAY_AREF(v_addresses, i);
753
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
754
+ }
590
755
 
591
- if(sctp_connectx(fileno, (struct sockaddr *) addrs, num_ip, &assoc) < 0)
592
- rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
756
+ if(sctp_sys_connectx(fileno, (struct sockaddr *)addrs, num_ip, &assoc) < 0)
757
+ rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
758
+ }
593
759
 
594
760
  rb_iv_set(self, "@association_id", INT2NUM(assoc));
595
761
 
@@ -619,7 +785,7 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
619
785
  */
620
786
  static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
621
787
  VALUE v_options, v_linger, v_fileno;
622
- int fileno;
788
+ sctp_sock_t fileno;
623
789
 
624
790
  rb_scan_args(argc, argv, "01", &v_options);
625
791
 
@@ -634,9 +800,13 @@ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
634
800
  if(NIL_P(v_fileno)) // Already closed
635
801
  return self;
636
802
 
637
- fileno = NUM2INT(v_fileno);
803
+ fileno = NUM_TO_SCTP_FD(v_fileno);
638
804
 
639
805
  if(!NIL_P(v_linger)){
806
+ #ifdef HAVE_USRSCTP_H
807
+ /* usrsctp doesn't support SOL_SOCKET options; linger is not available */
808
+ (void)v_linger;
809
+ #else
640
810
  struct linger lin;
641
811
  int linger_time = NUM2INT(v_linger);
642
812
 
@@ -646,11 +816,12 @@ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
646
816
  lin.l_onoff = 1;
647
817
  lin.l_linger = linger_time;
648
818
 
649
- if(setsockopt(fileno, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
819
+ if(sctp_sys_setsockopt(fileno, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
650
820
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
821
+ #endif
651
822
  }
652
823
 
653
- if(close(fileno) < 0)
824
+ if(sctp_sys_close(fileno) < 0)
654
825
  rb_raise(rb_eSystemCallError, "close: %s", strerror(errno));
655
826
 
656
827
  // Mark socket as closed
@@ -700,7 +871,8 @@ static VALUE rsctp_closed_p(VALUE self){
700
871
  static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
701
872
  sctp_assoc_t assoc_id;
702
873
  struct sockaddr* addrs = NULL;
703
- int i, fileno, num_addrs;
874
+ sctp_sock_t fileno;
875
+ int i, num_addrs;
704
876
  char str[IP_BUFFER_SIZE];
705
877
  VALUE v_fileno, v_association_id;
706
878
  VALUE v_array = rb_ary_new();
@@ -709,10 +881,10 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
709
881
 
710
882
  if(NIL_P(v_fileno)){
711
883
  CHECK_SOCKET_CLOSED(self);
712
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
884
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
713
885
  }
714
886
  else{
715
- fileno = NUM2INT(v_fileno);
887
+ fileno = NUM_TO_SCTP_FD(v_fileno);
716
888
  CHECK_FILENO_VALID(fileno);
717
889
  }
718
890
 
@@ -721,22 +893,32 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
721
893
  else
722
894
  assoc_id = NUM2INT(v_association_id);
723
895
 
724
- num_addrs = sctp_getpaddrs(fileno, assoc_id, &addrs);
896
+ num_addrs = sctp_sys_getpaddrs(fileno, assoc_id, &addrs);
725
897
 
726
898
  if(num_addrs < 0){
727
899
  if(addrs != NULL)
728
- sctp_freepaddrs(addrs);
900
+ sctp_sys_freepaddrs(addrs);
729
901
 
730
902
  rb_raise(rb_eSystemCallError, "sctp_getpaddrs: %s", strerror(errno));
731
903
  }
732
904
 
733
905
  for(i = 0; i < num_addrs; i++){
906
+ struct sockaddr* sa = &addrs[i];
734
907
  bzero(&str, sizeof(str));
735
- inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
908
+
909
+ if(sa->sa_family == AF_INET6){
910
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
911
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
912
+ }
913
+ else{
914
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
915
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
916
+ }
917
+
736
918
  rb_ary_push(v_array, rb_str_new2(str));
737
919
  }
738
920
 
739
- sctp_freepaddrs(addrs);
921
+ sctp_sys_freepaddrs(addrs);
740
922
 
741
923
  return v_array;
742
924
  }
@@ -761,7 +943,8 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
761
943
  static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
762
944
  sctp_assoc_t assoc_id;
763
945
  struct sockaddr* addrs = NULL;
764
- int i, fileno, num_addrs;
946
+ sctp_sock_t fileno;
947
+ int i, num_addrs;
765
948
  char str[IP_BUFFER_SIZE];
766
949
  VALUE v_assoc_fileno, v_assoc_id;
767
950
  VALUE v_array = rb_ary_new();
@@ -770,10 +953,10 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
770
953
 
771
954
  if(NIL_P(v_assoc_fileno)){
772
955
  CHECK_SOCKET_CLOSED(self);
773
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
956
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
774
957
  }
775
958
  else{
776
- fileno = NUM2INT(v_assoc_fileno);
959
+ fileno = NUM_TO_SCTP_FD(v_assoc_fileno);
777
960
  CHECK_FILENO_VALID(fileno);
778
961
  }
779
962
 
@@ -782,22 +965,32 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
782
965
  else
783
966
  assoc_id = NUM2INT(v_assoc_id);
784
967
 
785
- num_addrs = sctp_getladdrs(fileno, assoc_id, &addrs);
968
+ num_addrs = sctp_sys_getladdrs(fileno, assoc_id, &addrs);
786
969
 
787
970
  if(num_addrs < 0){
788
971
  if(addrs != NULL)
789
- sctp_freeladdrs(addrs);
972
+ sctp_sys_freeladdrs(addrs);
790
973
 
791
974
  rb_raise(rb_eSystemCallError, "sctp_getladdrs: %s", strerror(errno));
792
975
  }
793
976
 
794
977
  for(i = 0; i < num_addrs; i++){
978
+ struct sockaddr* sa = &addrs[i];
795
979
  bzero(&str, sizeof(str));
796
- inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
980
+
981
+ if(sa->sa_family == AF_INET6){
982
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
983
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
984
+ }
985
+ else{
986
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
987
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
988
+ }
989
+
797
990
  rb_ary_push(v_array, rb_str_new2(str));
798
991
  }
799
992
 
800
- sctp_freeladdrs(addrs);
993
+ sctp_sys_freeladdrs(addrs);
801
994
 
802
995
  return v_array;
803
996
  }
@@ -832,9 +1025,9 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
832
1025
  static VALUE rsctp_sendv(VALUE self, VALUE v_options){
833
1026
  VALUE v_msg, v_message, v_addresses;
834
1027
  struct iovec iov[IOV_MAX];
835
- struct sockaddr_in* addrs;
836
1028
  struct sctp_sendv_spa spa;
837
- int i, fileno, size, num_ip;
1029
+ sctp_sock_t fileno;
1030
+ int i, size, num_ip, domain, port;
838
1031
  ssize_t num_bytes;
839
1032
 
840
1033
  Check_Type(v_options, T_HASH);
@@ -856,14 +1049,15 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
856
1049
  if(!NIL_P(v_addresses)){
857
1050
  Check_Type(v_addresses, T_ARRAY);
858
1051
  num_ip = (int)RARRAY_LEN(v_addresses);
859
- addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(*addrs));
1052
+
1053
+ if(num_ip > MAX_IP_ADDRESSES)
1054
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
860
1055
  }
861
1056
  else{
862
- addrs = NULL;
863
1057
  num_ip = 0;
864
1058
  }
865
1059
 
866
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1060
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
867
1061
  size = (int)RARRAY_LEN(v_message);
868
1062
 
869
1063
  if(!size)
@@ -877,8 +1071,15 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
877
1071
  spa.sendv_sndinfo.snd_flags = SCTP_UNORDERED;
878
1072
  spa.sendv_sndinfo.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
879
1073
 
880
- if(!NIL_P(v_addresses)){
881
- int i, port, domain;
1074
+ for(i = 0; i < size; i++){
1075
+ v_msg = RARRAY_AREF(v_message, i);
1076
+ iov[i].iov_base = StringValueCStr(v_msg);
1077
+ iov[i].iov_len = RSTRING_LEN(v_msg);
1078
+ }
1079
+
1080
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
1081
+
1082
+ if(num_ip > 0){
882
1083
  VALUE v_address, v_port;
883
1084
 
884
1085
  v_port = rb_iv_get(self, "@port");
@@ -888,36 +1089,62 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
888
1089
  else
889
1090
  port = NUM2INT(v_port);
890
1091
 
891
- domain = NUM2INT(rb_iv_get(self, "@domain"));
1092
+ if(domain == AF_INET6){
1093
+ struct sockaddr_in6* addrs6 = (struct sockaddr_in6*)alloca(num_ip * sizeof(struct sockaddr_in6));
1094
+ bzero(addrs6, num_ip * sizeof(struct sockaddr_in6));
892
1095
 
893
- for(i = 0; i < num_ip; i++){
894
- v_address = RARRAY_PTR(v_addresses)[i];
895
- addrs[i].sin_family = domain;
896
- addrs[i].sin_port = htons(port);
897
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
898
- #ifdef BSD
899
- addrs[i].sin_len = sizeof(struct sockaddr_in);
900
- #endif
1096
+ for(i = 0; i < num_ip; i++){
1097
+ v_address = RARRAY_AREF(v_addresses, i);
1098
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
1099
+ }
1100
+
1101
+ num_bytes = (ssize_t)sctp_sys_sendv(
1102
+ fileno,
1103
+ iov,
1104
+ size,
1105
+ (struct sockaddr*)addrs6,
1106
+ num_ip,
1107
+ &spa,
1108
+ sizeof(spa),
1109
+ SCTP_SENDV_SPA,
1110
+ 0
1111
+ );
901
1112
  }
902
- }
1113
+ else{
1114
+ struct sockaddr_in* addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(struct sockaddr_in));
1115
+ bzero(addrs, num_ip * sizeof(struct sockaddr_in));
903
1116
 
904
- for(i = 0; i < size; i++){
905
- v_msg = RARRAY_PTR(v_message)[i];
906
- iov[i].iov_base = StringValueCStr(v_msg);
907
- iov[i].iov_len = RSTRING_LEN(v_msg);
908
- }
1117
+ for(i = 0; i < num_ip; i++){
1118
+ v_address = RARRAY_AREF(v_addresses, i);
1119
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
1120
+ }
909
1121
 
910
- num_bytes = (ssize_t)sctp_sendv(
911
- fileno,
912
- iov,
913
- size,
914
- (struct sockaddr*)addrs,
915
- num_ip,
916
- &spa,
917
- sizeof(spa),
918
- SCTP_SENDV_SPA,
919
- 0
920
- );
1122
+ num_bytes = (ssize_t)sctp_sys_sendv(
1123
+ fileno,
1124
+ iov,
1125
+ size,
1126
+ (struct sockaddr*)addrs,
1127
+ num_ip,
1128
+ &spa,
1129
+ sizeof(spa),
1130
+ SCTP_SENDV_SPA,
1131
+ 0
1132
+ );
1133
+ }
1134
+ }
1135
+ else{
1136
+ num_bytes = (ssize_t)sctp_sys_sendv(
1137
+ fileno,
1138
+ iov,
1139
+ size,
1140
+ NULL,
1141
+ 0,
1142
+ &spa,
1143
+ sizeof(spa),
1144
+ SCTP_SENDV_SPA,
1145
+ 0
1146
+ );
1147
+ }
921
1148
 
922
1149
  if(num_bytes < 0)
923
1150
  rb_raise(rb_eSystemCallError, "sctp_sendv: %s", strerror(errno));
@@ -926,6 +1153,80 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
926
1153
  }
927
1154
  #endif
928
1155
 
1156
+ /*
1157
+ * GVL-release helpers for blocking receive calls.
1158
+ *
1159
+ * usrsctp_recvv blocks on internal userspace locks, not real system calls,
1160
+ * so Ruby's signal-handling thread never gets a chance to run. By releasing
1161
+ * the GVL around the blocking call, other Ruby threads (including the signal
1162
+ * thread) can execute. The UBF (unblock function) is invoked by Ruby when
1163
+ * it needs to interrupt the blocking call (e.g. Ctrl-C).
1164
+ *
1165
+ * For native SCTP we use RUBY_UBF_IO which sends a signal that interrupts
1166
+ * the real recvmsg() syscall. For usrsctp we shut down the read side of
1167
+ * the socket, which causes usrsctp_recvv to return with an error.
1168
+ */
1169
+
1170
+ /* --- recvmsg (sctp_recvmsg / usrsctp_recvv via sctp_sys_recvmsg) --- */
1171
+
1172
+ struct recvmsg_nogvl_args {
1173
+ sctp_sock_t fd;
1174
+ void *buf;
1175
+ size_t len;
1176
+ struct sockaddr *from;
1177
+ socklen_t *fromlen;
1178
+ struct sctp_sndrcvinfo *sinfo;
1179
+ int *msg_flags;
1180
+ ssize_t result;
1181
+ int saved_errno;
1182
+ };
1183
+
1184
+ static void *recvmsg_nogvl(void *arg){
1185
+ struct recvmsg_nogvl_args *a = (struct recvmsg_nogvl_args *)arg;
1186
+ a->result = sctp_sys_recvmsg(a->fd, a->buf, a->len,
1187
+ a->from, a->fromlen, a->sinfo, a->msg_flags);
1188
+ a->saved_errno = errno;
1189
+ return NULL;
1190
+ }
1191
+
1192
+ #ifdef HAVE_USRSCTP_H
1193
+ static void recvmsg_ubf(void *arg){
1194
+ struct recvmsg_nogvl_args *a = (struct recvmsg_nogvl_args *)arg;
1195
+ usrsctp_shutdown(a->fd, SHUT_RD);
1196
+ }
1197
+ #endif
1198
+
1199
+ /* --- recvv (sctp_recvv / usrsctp_recvv via sctp_sys_recvv) --- */
1200
+
1201
+ struct recvv_nogvl_args {
1202
+ sctp_sock_t fd;
1203
+ const struct iovec *iov;
1204
+ int iovcnt;
1205
+ struct sockaddr *from;
1206
+ socklen_t *fromlen;
1207
+ void *info;
1208
+ socklen_t *infolen;
1209
+ unsigned int *infotype;
1210
+ int *flags;
1211
+ ssize_t result;
1212
+ int saved_errno;
1213
+ };
1214
+
1215
+ static void *recvv_nogvl(void *arg){
1216
+ struct recvv_nogvl_args *a = (struct recvv_nogvl_args *)arg;
1217
+ a->result = sctp_sys_recvv(a->fd, a->iov, a->iovcnt,
1218
+ a->from, a->fromlen, a->info, a->infolen, a->infotype, a->flags);
1219
+ a->saved_errno = errno;
1220
+ return NULL;
1221
+ }
1222
+
1223
+ #ifdef HAVE_USRSCTP_H
1224
+ static void recvv_ubf(void *arg){
1225
+ struct recvv_nogvl_args *a = (struct recvv_nogvl_args *)arg;
1226
+ usrsctp_shutdown(a->fd, SHUT_RD);
1227
+ }
1228
+ #endif
1229
+
929
1230
  #ifdef HAVE_SCTP_RECVV
930
1231
  /*
931
1232
  * call-seq:
@@ -957,7 +1258,8 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
957
1258
  */
958
1259
  static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
959
1260
  VALUE v_flags, v_buffer_size;
960
- int fileno, flags, on, buffer_size;
1261
+ sctp_sock_t fileno;
1262
+ int flags, on, buffer_size;
961
1263
  ssize_t bytes;
962
1264
  uint infotype;
963
1265
  socklen_t infolen;
@@ -970,7 +1272,9 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
970
1272
 
971
1273
  rb_scan_args(argc, argv, "02", &v_flags, &v_buffer_size);
972
1274
 
973
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1275
+ CHECK_SOCKET_CLOSED(self);
1276
+
1277
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
974
1278
 
975
1279
  if(NIL_P(v_flags))
976
1280
  flags = 0;
@@ -995,7 +1299,7 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
995
1299
  iov->iov_len = buffer_size;
996
1300
 
997
1301
  on = 1;
998
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0){
1302
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0){
999
1303
  free(buffer);
1000
1304
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1001
1305
  }
@@ -1003,17 +1307,27 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
1003
1307
  infolen = sizeof(struct sctp_rcvinfo);
1004
1308
  infotype = 0;
1005
1309
 
1006
- bytes = (ssize_t)sctp_recvv(
1007
- fileno,
1008
- iov,
1009
- 1,
1010
- NULL,
1011
- NULL,
1012
- &info,
1013
- &infolen,
1014
- &infotype,
1015
- &flags
1016
- );
1310
+ {
1311
+ struct recvv_nogvl_args recv_args;
1312
+ recv_args.fd = fileno;
1313
+ recv_args.iov = iov;
1314
+ recv_args.iovcnt = 1;
1315
+ recv_args.from = NULL;
1316
+ recv_args.fromlen = NULL;
1317
+ recv_args.info = &info;
1318
+ recv_args.infolen = &infolen;
1319
+ recv_args.infotype = &infotype;
1320
+ recv_args.flags = &flags;
1321
+
1322
+ #ifdef HAVE_USRSCTP_H
1323
+ rb_thread_call_without_gvl(recvv_nogvl, &recv_args, recvv_ubf, &recv_args);
1324
+ #else
1325
+ rb_thread_call_without_gvl(recvv_nogvl, &recv_args, RUBY_UBF_IO, NULL);
1326
+ #endif
1327
+
1328
+ bytes = recv_args.result;
1329
+ errno = recv_args.saved_errno;
1330
+ }
1017
1331
 
1018
1332
  if(bytes < 0){
1019
1333
  free(buffer);
@@ -1062,7 +1376,7 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
1062
1376
  uint16_t stream;
1063
1377
  uint32_t ppid, send_flags, ctrl_flags, ttl, context;
1064
1378
  ssize_t num_bytes;
1065
- int fileno;
1379
+ sctp_sock_t fileno;
1066
1380
  sctp_assoc_t assoc_id;
1067
1381
  struct sctp_sndrcvinfo info;
1068
1382
  VALUE v_msg, v_stream, v_ppid, v_context, v_send_flags, v_ctrl_flags, v_ttl, v_assoc_id;
@@ -1116,6 +1430,8 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
1116
1430
  else
1117
1431
  assoc_id = NUM2INT(v_assoc_id);
1118
1432
 
1433
+ CHECK_SOCKET_CLOSED(self);
1434
+
1119
1435
  info.sinfo_stream = stream;
1120
1436
  info.sinfo_flags = send_flags;
1121
1437
  info.sinfo_ppid = ppid;
@@ -1123,9 +1439,9 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
1123
1439
  info.sinfo_timetolive = ttl;
1124
1440
  info.sinfo_assoc_id = assoc_id;
1125
1441
 
1126
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1442
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1127
1443
 
1128
- num_bytes = (ssize_t)sctp_send(
1444
+ num_bytes = (ssize_t)sctp_sys_send(
1129
1445
  fileno,
1130
1446
  StringValueCStr(v_msg),
1131
1447
  RSTRING_LEN(v_msg),
@@ -1176,13 +1492,11 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1176
1492
  uint16_t stream;
1177
1493
  uint32_t ppid, flags, ttl, context;
1178
1494
  ssize_t num_bytes;
1179
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
1180
- int fileno, size, num_ip;
1495
+ sctp_sock_t fileno;
1496
+ int num_ip, domain;
1181
1497
 
1182
1498
  Check_Type(v_options, T_HASH);
1183
1499
 
1184
- bzero(&addrs, sizeof(addrs));
1185
-
1186
1500
  v_msg = rb_hash_aref2(v_options, "message");
1187
1501
  v_stream = rb_hash_aref2(v_options, "stream");
1188
1502
  v_ppid = rb_hash_aref2(v_options, "ppid");
@@ -1222,12 +1536,21 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1222
1536
  else
1223
1537
  context = NUM2INT(v_context);
1224
1538
 
1539
+ CHECK_SOCKET_CLOSED(self);
1540
+
1541
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1542
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
1543
+
1225
1544
  if(!NIL_P(v_addresses)){
1226
1545
  int i, port;
1227
1546
  VALUE v_address, v_port;
1228
1547
 
1229
1548
  Check_Type(v_addresses, T_ARRAY);
1230
1549
  num_ip = (int)RARRAY_LEN(v_addresses);
1550
+
1551
+ if(num_ip > MAX_IP_ADDRESSES)
1552
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
1553
+
1231
1554
  v_port = rb_hash_aref2(v_options, "port");
1232
1555
 
1233
1556
  if(NIL_P(v_port))
@@ -1235,47 +1558,62 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1235
1558
  else
1236
1559
  port = NUM2INT(v_port);
1237
1560
 
1238
- for(i = 0; i < num_ip; i++){
1239
- v_address = RARRAY_PTR(v_addresses)[i];
1240
- addrs[i].sin_family = NUM2INT(rb_iv_get(self, "@domain"));
1241
- addrs[i].sin_port = htons(port);
1242
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
1243
- #ifdef BSD
1244
- addrs[i].sin_len = sizeof(struct sockaddr_in);
1245
- #endif
1561
+ if(domain == AF_INET6){
1562
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
1563
+
1564
+ bzero(&addrs6, sizeof(addrs6));
1565
+
1566
+ for(i = 0; i < num_ip; i++){
1567
+ v_address = RARRAY_AREF(v_addresses, i);
1568
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
1569
+ }
1570
+
1571
+ num_bytes = (ssize_t)sctp_sys_sendmsg(
1572
+ fileno,
1573
+ StringValueCStr(v_msg),
1574
+ RSTRING_LEN(v_msg),
1575
+ (struct sockaddr*)addrs6,
1576
+ num_ip,
1577
+ ppid,
1578
+ flags,
1579
+ stream,
1580
+ ttl,
1581
+ context
1582
+ );
1246
1583
  }
1584
+ else{
1585
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
1247
1586
 
1248
- size = sizeof(addrs);
1249
- }
1250
- else{
1251
- num_ip = 0;
1252
- size = 0;
1253
- }
1587
+ bzero(&addrs, sizeof(addrs));
1254
1588
 
1255
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1589
+ for(i = 0; i < num_ip; i++){
1590
+ v_address = RARRAY_AREF(v_addresses, i);
1591
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
1592
+ }
1256
1593
 
1257
- #ifdef BSD
1258
- if(num_ip){
1259
- num_bytes = (ssize_t)sctp_sendmsgx(
1260
- fileno,
1261
- StringValueCStr(v_msg),
1262
- RSTRING_LEN(v_msg),
1263
- (struct sockaddr*)addrs,
1264
- num_ip,
1265
- ppid,
1266
- flags,
1267
- stream,
1268
- ttl,
1269
- context
1270
- );
1594
+ num_bytes = (ssize_t)sctp_sys_sendmsg(
1595
+ fileno,
1596
+ StringValueCStr(v_msg),
1597
+ RSTRING_LEN(v_msg),
1598
+ (struct sockaddr*)addrs,
1599
+ num_ip,
1600
+ ppid,
1601
+ flags,
1602
+ stream,
1603
+ ttl,
1604
+ context
1605
+ );
1606
+ }
1271
1607
  }
1272
1608
  else{
1273
- num_bytes = (ssize_t)sctp_sendmsg(
1609
+ // No addresses - use empty addrs
1610
+ num_ip = 0;
1611
+ num_bytes = (ssize_t)sctp_sys_sendmsg(
1274
1612
  fileno,
1275
1613
  StringValueCStr(v_msg),
1276
1614
  RSTRING_LEN(v_msg),
1277
- (struct sockaddr*)addrs,
1278
- size,
1615
+ NULL,
1616
+ 0,
1279
1617
  ppid,
1280
1618
  flags,
1281
1619
  stream,
@@ -1283,31 +1621,9 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1283
1621
  context
1284
1622
  );
1285
1623
  }
1286
- #else
1287
- num_bytes = (ssize_t)sctp_sendmsg(
1288
- fileno,
1289
- StringValueCStr(v_msg),
1290
- RSTRING_LEN(v_msg),
1291
- (struct sockaddr*)addrs,
1292
- size,
1293
- ppid,
1294
- flags,
1295
- stream,
1296
- ttl,
1297
- context
1298
- );
1299
- #endif
1300
1624
 
1301
- if(num_bytes < 0){
1302
- #ifdef BSD
1303
- if(num_ip > 0)
1304
- rb_raise(rb_eSystemCallError, "sctp_sendmsgx: %s", strerror(errno));
1305
- else
1306
- rb_raise(rb_eSystemCallError, "sctp_sendmsg: %s", strerror(errno));
1307
- #else
1625
+ if(num_bytes < 0)
1308
1626
  rb_raise(rb_eSystemCallError, "sctp_sendmsg: %s", strerror(errno));
1309
- #endif
1310
- }
1311
1627
 
1312
1628
  return LONG2NUM(num_bytes);
1313
1629
  }
@@ -1345,7 +1661,8 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1345
1661
  VALUE v_flags, v_buffer_size, v_notification, v_message;
1346
1662
  struct sctp_sndrcvinfo sndrcvinfo;
1347
1663
  struct sockaddr_in clientaddr;
1348
- int flags, fileno, buffer_size;
1664
+ sctp_sock_t fileno;
1665
+ int flags, buffer_size;
1349
1666
  ssize_t bytes;
1350
1667
  char *buffer;
1351
1668
  socklen_t length;
@@ -1369,22 +1686,34 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1369
1686
  if(buffer == NULL)
1370
1687
  rb_raise(rb_eNoMemError, "failed to allocate buffer");
1371
1688
 
1372
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1689
+ CHECK_SOCKET_CLOSED(self);
1690
+
1691
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1373
1692
  length = sizeof(struct sockaddr_in);
1374
1693
 
1375
1694
  bzero(buffer, buffer_size);
1376
1695
  bzero(&clientaddr, sizeof(clientaddr));
1377
1696
  bzero(&sndrcvinfo, sizeof(sndrcvinfo));
1378
1697
 
1379
- bytes = (ssize_t)sctp_recvmsg(
1380
- fileno,
1381
- buffer,
1382
- buffer_size,
1383
- (struct sockaddr*)&clientaddr,
1384
- &length,
1385
- &sndrcvinfo,
1386
- &flags
1387
- );
1698
+ {
1699
+ struct recvmsg_nogvl_args recv_args;
1700
+ recv_args.fd = fileno;
1701
+ recv_args.buf = buffer;
1702
+ recv_args.len = buffer_size;
1703
+ recv_args.from = (struct sockaddr*)&clientaddr;
1704
+ recv_args.fromlen = &length;
1705
+ recv_args.sinfo = &sndrcvinfo;
1706
+ recv_args.msg_flags = &flags;
1707
+
1708
+ #ifdef HAVE_USRSCTP_H
1709
+ rb_thread_call_without_gvl(recvmsg_nogvl, &recv_args, recvmsg_ubf, &recv_args);
1710
+ #else
1711
+ rb_thread_call_without_gvl(recvmsg_nogvl, &recv_args, RUBY_UBF_IO, NULL);
1712
+ #endif
1713
+
1714
+ bytes = recv_args.result;
1715
+ errno = recv_args.saved_errno;
1716
+ }
1388
1717
 
1389
1718
  if(bytes < 0){
1390
1719
  free(buffer);
@@ -1437,18 +1766,20 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1437
1766
  * By default these values are set to zero (i.e. ignored).
1438
1767
  */
1439
1768
  static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1440
- int fileno;
1769
+ sctp_sock_t fileno;
1441
1770
  struct sctp_initmsg initmsg;
1442
1771
  VALUE v_output, v_input, v_attempts, v_timeout;
1443
1772
 
1444
1773
  bzero(&initmsg, sizeof(initmsg));
1445
1774
 
1775
+ CHECK_SOCKET_CLOSED(self);
1776
+
1446
1777
  v_output = rb_hash_aref2(v_options, "output_streams");
1447
1778
  v_input = rb_hash_aref2(v_options, "input_streams");
1448
1779
  v_attempts = rb_hash_aref2(v_options, "max_attempts");
1449
1780
  v_timeout = rb_hash_aref2(v_options, "timeout");
1450
1781
 
1451
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1782
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1452
1783
 
1453
1784
  if(!NIL_P(v_output))
1454
1785
  initmsg.sinit_num_ostreams = NUM2INT(v_output);
@@ -1462,7 +1793,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1462
1793
  if(!NIL_P(v_timeout))
1463
1794
  initmsg.sinit_max_init_timeo = NUM2INT(v_timeout);
1464
1795
 
1465
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)) < 0)
1796
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)) < 0)
1466
1797
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1467
1798
 
1468
1799
  return self;
@@ -1507,13 +1838,15 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1507
1838
  * socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true)
1508
1839
  */
1509
1840
  static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
1510
- int fileno;
1841
+ sctp_sock_t fileno;
1511
1842
  struct sctp_event_subscribe events;
1512
1843
 
1513
1844
  bzero(&events, sizeof(events));
1514
1845
  Check_Type(v_options, T_HASH);
1515
1846
 
1516
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1847
+ CHECK_SOCKET_CLOSED(self);
1848
+
1849
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1517
1850
 
1518
1851
  if(RTEST(rb_hash_aref2(v_options, "data_io")))
1519
1852
  events.sctp_data_io_event = 1;
@@ -1549,8 +1882,43 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
1549
1882
  if(RTEST(rb_hash_aref2(v_options, "sender_dry")))
1550
1883
  events.sctp_sender_dry_event = 1;
1551
1884
 
1552
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) < 0)
1885
+ #ifdef HAVE_USRSCTP_H
1886
+ /* usrsctp uses SCTP_EVENT + struct sctp_event for per-event subscription */
1887
+ {
1888
+ struct sctp_event se;
1889
+ memset(&se, 0, sizeof(se));
1890
+ se.se_assoc_id = 0;
1891
+
1892
+ /* data_io: enable via SCTP_RECVRCVINFO sockopt */
1893
+ if(events.sctp_data_io_event){
1894
+ int on = 1;
1895
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0)
1896
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1897
+ }
1898
+
1899
+ #define SUBSCRIBE_EVENT(field, type) \
1900
+ if(events.field){ \
1901
+ se.se_type = (type); se.se_on = 1; \
1902
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_EVENT, &se, sizeof(se)) < 0) \
1903
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno)); \
1904
+ }
1905
+
1906
+ SUBSCRIBE_EVENT(sctp_association_event, SCTP_ASSOC_CHANGE)
1907
+ SUBSCRIBE_EVENT(sctp_address_event, SCTP_PEER_ADDR_CHANGE)
1908
+ SUBSCRIBE_EVENT(sctp_send_failure_event, SCTP_SEND_FAILED)
1909
+ SUBSCRIBE_EVENT(sctp_peer_error_event, SCTP_REMOTE_ERROR)
1910
+ SUBSCRIBE_EVENT(sctp_shutdown_event, SCTP_SHUTDOWN_EVENT)
1911
+ SUBSCRIBE_EVENT(sctp_partial_delivery_event, SCTP_PARTIAL_DELIVERY_EVENT)
1912
+ SUBSCRIBE_EVENT(sctp_adaptation_layer_event, SCTP_ADAPTATION_INDICATION)
1913
+ SUBSCRIBE_EVENT(sctp_authentication_event, SCTP_AUTHENTICATION_EVENT)
1914
+ SUBSCRIBE_EVENT(sctp_sender_dry_event, SCTP_SENDER_DRY_EVENT)
1915
+
1916
+ #undef SUBSCRIBE_EVENT
1917
+ }
1918
+ #else
1919
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) < 0)
1553
1920
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1921
+ #endif
1554
1922
 
1555
1923
  return self;
1556
1924
  }
@@ -1581,7 +1949,8 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
1581
1949
  */
1582
1950
  static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1583
1951
  VALUE v_backlog;
1584
- int backlog, fileno;
1952
+ sctp_sock_t fileno;
1953
+ int backlog;
1585
1954
 
1586
1955
  rb_scan_args(argc, argv, "01", &v_backlog);
1587
1956
 
@@ -1593,9 +1962,11 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1593
1962
  if(backlog > SOMAXCONN)
1594
1963
  rb_raise(rb_eArgError, "backlog value exceeds maximum value of: %i", SOMAXCONN);
1595
1964
 
1596
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1965
+ CHECK_SOCKET_CLOSED(self);
1597
1966
 
1598
- if(listen(fileno, backlog) < 0)
1967
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1968
+
1969
+ if(sctp_sys_listen(fileno, backlog) < 0)
1599
1970
  rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
1600
1971
 
1601
1972
  return self;
@@ -1620,18 +1991,20 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1620
1991
  * end
1621
1992
  */
1622
1993
  static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
1623
- int fileno, assoc_fileno;
1994
+ sctp_sock_t fileno, assoc_fileno;
1624
1995
  sctp_assoc_t assoc_id;
1625
1996
 
1626
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1997
+ CHECK_SOCKET_CLOSED(self);
1998
+
1999
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1627
2000
  assoc_id = NUM2INT(v_assoc_id);
1628
2001
 
1629
- assoc_fileno = sctp_peeloff(fileno, assoc_id);
2002
+ assoc_fileno = sctp_sys_peeloff(fileno, assoc_id);
1630
2003
 
1631
- if(assoc_fileno < 0)
2004
+ if(SCTP_FD_INVALID(assoc_fileno))
1632
2005
  rb_raise(rb_eSystemCallError, "sctp_peeloff: %s", strerror(errno));
1633
2006
 
1634
- return INT2NUM(assoc_fileno);
2007
+ return SCTP_FD_TO_NUM(assoc_fileno);
1635
2008
  }
1636
2009
 
1637
2010
  /*
@@ -1653,32 +2026,60 @@ static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
1653
2026
  * * association_id
1654
2027
  */
1655
2028
  static VALUE rsctp_get_default_send_params(VALUE self){
1656
- int fileno;
2029
+ sctp_sock_t fileno;
1657
2030
  socklen_t size;
1658
2031
  sctp_assoc_t assoc_id;
1659
- struct sctp_sndrcvinfo sndrcv;
1660
2032
 
1661
- bzero(&sndrcv, sizeof(sndrcv));
2033
+ CHECK_SOCKET_CLOSED(self);
1662
2034
 
1663
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2035
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1664
2036
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1665
- size = sizeof(struct sctp_sndrcvinfo);
1666
2037
 
1667
- if(sctp_opt_info(fileno, assoc_id, SCTP_DEFAULT_SEND_PARAM, (void*)&sndrcv, &size) < 0)
1668
- rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1669
-
1670
- return rb_struct_new(
1671
- v_sctp_default_send_params_struct,
1672
- INT2NUM(sndrcv.sinfo_stream),
1673
- INT2NUM(sndrcv.sinfo_ssn),
1674
- INT2NUM(sndrcv.sinfo_flags),
1675
- INT2NUM(sndrcv.sinfo_ppid),
1676
- INT2NUM(sndrcv.sinfo_context),
1677
- INT2NUM(sndrcv.sinfo_timetolive),
1678
- INT2NUM(sndrcv.sinfo_tsn),
1679
- INT2NUM(sndrcv.sinfo_cumtsn),
1680
- INT2NUM(sndrcv.sinfo_assoc_id)
1681
- );
2038
+ #ifdef HAVE_USRSCTP_H
2039
+ {
2040
+ struct sctp_sndinfo sndinfo;
2041
+ bzero(&sndinfo, sizeof(sndinfo));
2042
+ size = sizeof(sndinfo);
2043
+
2044
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_DEFAULT_SNDINFO, (void*)&sndinfo, &size) < 0)
2045
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2046
+
2047
+ return rb_struct_new(
2048
+ v_sctp_default_send_params_struct,
2049
+ INT2NUM(sndinfo.snd_sid),
2050
+ INT2NUM(0), /* ssn - not available via sndinfo */
2051
+ INT2NUM(sndinfo.snd_flags),
2052
+ INT2NUM(sndinfo.snd_ppid),
2053
+ INT2NUM(sndinfo.snd_context),
2054
+ INT2NUM(0), /* timetolive - not available via sndinfo */
2055
+ INT2NUM(0), /* tsn - not available via sndinfo */
2056
+ INT2NUM(0), /* cumtsn - not available via sndinfo */
2057
+ INT2NUM(sndinfo.snd_assoc_id)
2058
+ );
2059
+ }
2060
+ #else
2061
+ {
2062
+ struct sctp_sndrcvinfo sndrcv;
2063
+ bzero(&sndrcv, sizeof(sndrcv));
2064
+ size = sizeof(struct sctp_sndrcvinfo);
2065
+
2066
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_DEFAULT_SEND_PARAM, (void*)&sndrcv, &size) < 0)
2067
+ rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2068
+
2069
+ return rb_struct_new(
2070
+ v_sctp_default_send_params_struct,
2071
+ INT2NUM(sndrcv.sinfo_stream),
2072
+ INT2NUM(sndrcv.sinfo_ssn),
2073
+ INT2NUM(sndrcv.sinfo_flags),
2074
+ INT2NUM(sndrcv.sinfo_ppid),
2075
+ INT2NUM(sndrcv.sinfo_context),
2076
+ INT2NUM(sndrcv.sinfo_timetolive),
2077
+ INT2NUM(sndrcv.sinfo_tsn),
2078
+ INT2NUM(sndrcv.sinfo_cumtsn),
2079
+ INT2NUM(sndrcv.sinfo_assoc_id)
2080
+ );
2081
+ }
2082
+ #endif
1682
2083
  }
1683
2084
 
1684
2085
  /*
@@ -1698,18 +2099,20 @@ static VALUE rsctp_get_default_send_params(VALUE self){
1698
2099
  * All values that refer to time values are measured in milliseconds.
1699
2100
  */
1700
2101
  static VALUE rsctp_get_association_info(VALUE self){
1701
- int fileno;
2102
+ sctp_sock_t fileno;
1702
2103
  socklen_t size;
1703
2104
  sctp_assoc_t assoc_id;
1704
2105
  struct sctp_assocparams assoc;
1705
2106
 
1706
2107
  bzero(&assoc, sizeof(assoc));
1707
2108
 
1708
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2109
+ CHECK_SOCKET_CLOSED(self);
2110
+
2111
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1709
2112
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1710
2113
  size = sizeof(struct sctp_assocparams);
1711
2114
 
1712
- if(sctp_opt_info(fileno, assoc_id, SCTP_ASSOCINFO, (void*)&assoc, &size) < 0)
2115
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_ASSOCINFO, (void*)&assoc, &size) < 0)
1713
2116
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1714
2117
 
1715
2118
  return rb_struct_new(
@@ -1741,13 +2144,15 @@ static VALUE rsctp_get_association_info(VALUE self){
1741
2144
  */
1742
2145
  static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
1743
2146
  VALUE v_assoc_id, v_max_rxt, v_nbr_peer, v_peer_rw, v_local_rw, v_cookie;
1744
- int fileno;
2147
+ sctp_sock_t fileno;
1745
2148
  sctp_assoc_t assoc_id;
1746
2149
  struct sctp_assocparams assoc;
1747
2150
 
1748
2151
  bzero(&assoc, sizeof(assoc));
1749
2152
 
1750
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2153
+ CHECK_SOCKET_CLOSED(self);
2154
+
2155
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1751
2156
 
1752
2157
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
1753
2158
  v_max_rxt = rb_hash_aref2(v_options, "max_retransmission_count");
@@ -1778,7 +2183,7 @@ static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
1778
2183
  if(!NIL_P(v_cookie))
1779
2184
  assoc.sasoc_cookie_life = NUM2INT(v_cookie);
1780
2185
 
1781
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) < 0)
2186
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) < 0)
1782
2187
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1783
2188
 
1784
2189
  return rb_struct_new(
@@ -1808,10 +2213,13 @@ static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
1808
2213
  * The default is SHUT_RDWR.
1809
2214
  */
1810
2215
  static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1811
- int how, fileno;
2216
+ sctp_sock_t fileno;
2217
+ int how;
1812
2218
  VALUE v_how;
1813
2219
 
1814
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2220
+ CHECK_SOCKET_CLOSED(self);
2221
+
2222
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1815
2223
 
1816
2224
  rb_scan_args(argc, argv, "01", &v_how);
1817
2225
 
@@ -1823,7 +2231,7 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1823
2231
  how = NUM2INT(v_how);
1824
2232
  }
1825
2233
 
1826
- if(shutdown(fileno, how) < 0)
2234
+ if(sctp_sys_shutdown(fileno, how) < 0)
1827
2235
  rb_raise(rb_eSystemCallError, "shutdown: %s", strerror(errno));
1828
2236
 
1829
2237
  return self;
@@ -1843,18 +2251,20 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1843
2251
  * * min
1844
2252
  */
1845
2253
  static VALUE rsctp_get_retransmission_info(VALUE self){
1846
- int fileno;
2254
+ sctp_sock_t fileno;
1847
2255
  socklen_t size;
1848
2256
  sctp_assoc_t assoc_id;
1849
2257
  struct sctp_rtoinfo rto;
1850
2258
 
1851
2259
  bzero(&rto, sizeof(rto));
1852
2260
 
1853
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2261
+ CHECK_SOCKET_CLOSED(self);
2262
+
2263
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1854
2264
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1855
2265
  size = sizeof(struct sctp_rtoinfo);
1856
2266
 
1857
- if(sctp_opt_info(fileno, assoc_id, SCTP_RTOINFO, (void*)&rto, &size) < 0)
2267
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_RTOINFO, (void*)&rto, &size) < 0)
1858
2268
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1859
2269
 
1860
2270
  return rb_struct_new(
@@ -1883,13 +2293,15 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
1883
2293
  */
1884
2294
  static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
1885
2295
  VALUE v_assoc_id, v_initial, v_max, v_min;
1886
- int fileno;
2296
+ sctp_sock_t fileno;
1887
2297
  sctp_assoc_t assoc_id;
1888
2298
  struct sctp_rtoinfo rto;
1889
2299
 
1890
2300
  bzero(&rto, sizeof(rto));
1891
2301
 
1892
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2302
+ CHECK_SOCKET_CLOSED(self);
2303
+
2304
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1893
2305
 
1894
2306
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
1895
2307
  v_initial = rb_hash_aref2(v_options, "initial");
@@ -1912,7 +2324,7 @@ static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
1912
2324
  if(!NIL_P(v_min))
1913
2325
  rto.srto_min = NUM2INT(v_min);
1914
2326
 
1915
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RTOINFO, &rto, sizeof(rto)) < 0)
2327
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_RTOINFO, &rto, sizeof(rto)) < 0)
1916
2328
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1917
2329
 
1918
2330
  return rb_struct_new(
@@ -1949,20 +2361,22 @@ static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
1949
2361
  * * primary (IP)
1950
2362
  */
1951
2363
  static VALUE rsctp_get_status(VALUE self){
1952
- int fileno;
2364
+ sctp_sock_t fileno;
1953
2365
  socklen_t size;
1954
2366
  sctp_assoc_t assoc_id;
1955
2367
  struct sctp_status status;
1956
2368
  struct sctp_paddrinfo* spinfo;
1957
- char tmpname[INET_ADDRSTRLEN];
2369
+ char tmpname[INET6_ADDRSTRLEN];
1958
2370
 
1959
2371
  bzero(&status, sizeof(status));
1960
2372
 
1961
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2373
+ CHECK_SOCKET_CLOSED(self);
2374
+
2375
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
1962
2376
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1963
2377
  size = sizeof(struct sctp_status);
1964
2378
 
1965
- if(sctp_opt_info(fileno, assoc_id, SCTP_STATUS, (void*)&status, &size) < 0)
2379
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_STATUS, (void*)&status, &size) < 0)
1966
2380
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
1967
2381
 
1968
2382
  spinfo = &status.sstat_primary;
@@ -2015,19 +2429,64 @@ static VALUE rsctp_get_status(VALUE self){
2015
2429
  * * send_failure_event
2016
2430
  */
2017
2431
  static VALUE rsctp_get_subscriptions(VALUE self){
2018
- int fileno;
2019
- socklen_t size;
2432
+ sctp_sock_t fileno;
2020
2433
  sctp_assoc_t assoc_id;
2021
2434
  struct sctp_event_subscribe events;
2435
+ #ifndef HAVE_USRSCTP_H
2436
+ socklen_t size;
2437
+ #endif
2022
2438
 
2023
2439
  bzero(&events, sizeof(events));
2024
2440
 
2025
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2441
+ CHECK_SOCKET_CLOSED(self);
2442
+
2443
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2026
2444
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2027
- size = sizeof(struct sctp_event_subscribe);
2028
2445
 
2029
- if(sctp_opt_info(fileno, assoc_id, SCTP_EVENTS, (void*)&events, &size) < 0)
2446
+ #ifdef HAVE_USRSCTP_H
2447
+ /* usrsctp uses SCTP_EVENT + struct sctp_event for per-event query */
2448
+ {
2449
+ struct sctp_event se;
2450
+ socklen_t se_size;
2451
+
2452
+ memset(&events, 0, sizeof(events));
2453
+
2454
+ /* data_io: check SCTP_RECVRCVINFO sockopt */
2455
+ {
2456
+ int on = 0;
2457
+ socklen_t on_size = sizeof(on);
2458
+ if(sctp_sys_getsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, &on_size) == 0 && on)
2459
+ events.sctp_data_io_event = 1;
2460
+ }
2461
+
2462
+ #define QUERY_EVENT(field, type) \
2463
+ memset(&se, 0, sizeof(se)); \
2464
+ se.se_assoc_id = assoc_id; \
2465
+ se.se_type = (type); \
2466
+ se_size = sizeof(se); \
2467
+ if(sctp_sys_getsockopt(fileno, IPPROTO_SCTP, SCTP_EVENT, &se, &se_size) == 0 && se.se_on) \
2468
+ events.field = 1;
2469
+
2470
+ QUERY_EVENT(sctp_association_event, SCTP_ASSOC_CHANGE)
2471
+ QUERY_EVENT(sctp_address_event, SCTP_PEER_ADDR_CHANGE)
2472
+ QUERY_EVENT(sctp_send_failure_event, SCTP_SEND_FAILED)
2473
+ QUERY_EVENT(sctp_peer_error_event, SCTP_REMOTE_ERROR)
2474
+ QUERY_EVENT(sctp_shutdown_event, SCTP_SHUTDOWN_EVENT)
2475
+ QUERY_EVENT(sctp_partial_delivery_event, SCTP_PARTIAL_DELIVERY_EVENT)
2476
+ QUERY_EVENT(sctp_adaptation_layer_event, SCTP_ADAPTATION_INDICATION)
2477
+ QUERY_EVENT(sctp_authentication_event, SCTP_AUTHENTICATION_EVENT)
2478
+ QUERY_EVENT(sctp_sender_dry_event, SCTP_SENDER_DRY_EVENT)
2479
+ #ifdef HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE_SCTP_STREAM_RESET_EVENT
2480
+ QUERY_EVENT(sctp_stream_reset_event, SCTP_STREAM_RESET_EVENT)
2481
+ #endif
2482
+
2483
+ #undef QUERY_EVENT
2484
+ }
2485
+ #else
2486
+ size = sizeof(struct sctp_event_subscribe);
2487
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_EVENTS, (void*)&events, &size) < 0)
2030
2488
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2489
+ #endif
2031
2490
 
2032
2491
  return rb_struct_new(
2033
2492
  v_sctp_event_subscribe_struct,
@@ -2078,7 +2537,7 @@ static VALUE rsctp_get_subscriptions(VALUE self){
2078
2537
  * * ipv6_flowlabel
2079
2538
  */
2080
2539
  static VALUE rsctp_get_peer_address_params(VALUE self){
2081
- int fileno;
2540
+ sctp_sock_t fileno;
2082
2541
  char str[IP_BUFFER_SIZE];
2083
2542
  socklen_t size;
2084
2543
  sctp_assoc_t assoc_id;
@@ -2087,14 +2546,27 @@ static VALUE rsctp_get_peer_address_params(VALUE self){
2087
2546
  bzero(&paddr, sizeof(paddr));
2088
2547
  bzero(&str, sizeof(str));
2089
2548
 
2090
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2549
+ CHECK_SOCKET_CLOSED(self);
2550
+
2551
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2091
2552
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2092
2553
  size = sizeof(struct sctp_paddrparams);
2093
2554
 
2094
- if(sctp_opt_info(fileno, assoc_id, SCTP_PEER_ADDR_PARAMS, (void*)&paddr, &size) < 0)
2555
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_PEER_ADDR_PARAMS, (void*)&paddr, &size) < 0)
2095
2556
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2096
2557
 
2097
- inet_ntop(AF_INET, ((struct sockaddr_in*)&paddr.spp_address), str, sizeof(str));
2558
+ {
2559
+ struct sockaddr* sa = (struct sockaddr*)&paddr.spp_address;
2560
+
2561
+ if(sa->sa_family == AF_INET6){
2562
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
2563
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
2564
+ }
2565
+ else{
2566
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
2567
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
2568
+ }
2569
+ }
2098
2570
 
2099
2571
  return rb_struct_new(
2100
2572
  v_sctp_peer_addr_params_struct,
@@ -2127,18 +2599,20 @@ static VALUE rsctp_get_peer_address_params(VALUE self){
2127
2599
  * (in milliseconds) to use in attempting an INIT.
2128
2600
  */
2129
2601
  static VALUE rsctp_get_init_msg(VALUE self){
2130
- int fileno;
2602
+ sctp_sock_t fileno;
2131
2603
  socklen_t size;
2132
2604
  sctp_assoc_t assoc_id;
2133
2605
  struct sctp_initmsg initmsg;
2134
2606
 
2135
2607
  bzero(&initmsg, sizeof(initmsg));
2136
2608
 
2137
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2609
+ CHECK_SOCKET_CLOSED(self);
2610
+
2611
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2138
2612
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2139
2613
  size = sizeof(struct sctp_initmsg);
2140
2614
 
2141
- if(sctp_opt_info(fileno, assoc_id, SCTP_INITMSG, (void*)&initmsg, &size) < 0)
2615
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_INITMSG, (void*)&initmsg, &size) < 0)
2142
2616
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2143
2617
 
2144
2618
  return rb_struct_new(
@@ -2157,16 +2631,18 @@ static VALUE rsctp_get_init_msg(VALUE self){
2157
2631
  * Returns whether or not the nodelay option has been set.
2158
2632
  */
2159
2633
  static VALUE rsctp_get_nodelay(VALUE self){
2160
- int fileno;
2634
+ sctp_sock_t fileno;
2161
2635
  socklen_t size;
2162
2636
  sctp_assoc_t assoc_id;
2163
2637
  int value;
2164
2638
 
2165
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2639
+ CHECK_SOCKET_CLOSED(self);
2640
+
2641
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2166
2642
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2167
2643
  size = sizeof(int);
2168
2644
 
2169
- if(sctp_opt_info(fileno, assoc_id, SCTP_NODELAY, (void*)&value, &size) < 0)
2645
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_NODELAY, (void*)&value, &size) < 0)
2170
2646
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2171
2647
 
2172
2648
  if(value)
@@ -2184,11 +2660,13 @@ static VALUE rsctp_get_nodelay(VALUE self){
2184
2660
  * cost of more packets in the network.
2185
2661
  */
2186
2662
  static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
2187
- int fileno;
2663
+ sctp_sock_t fileno;
2188
2664
  socklen_t size;
2189
2665
  int value;
2190
2666
 
2191
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2667
+ CHECK_SOCKET_CLOSED(self);
2668
+
2669
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2192
2670
  size = sizeof(int);
2193
2671
 
2194
2672
  if(NIL_P(v_bool) || v_bool == Qfalse)
@@ -2196,7 +2674,7 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
2196
2674
  else
2197
2675
  value = 1;
2198
2676
 
2199
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_NODELAY, &value, size) < 0)
2677
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_NODELAY, &value, size) < 0)
2200
2678
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2201
2679
 
2202
2680
  if(value)
@@ -2216,12 +2694,14 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
2216
2694
  * instead a error will be indicated to the user.
2217
2695
  */
2218
2696
  static VALUE rsctp_disable_fragments(VALUE self, VALUE v_bool){
2219
- int fileno;
2697
+ sctp_sock_t fileno;
2220
2698
  socklen_t size;
2221
2699
  sctp_assoc_t assoc_id;
2222
2700
  int value;
2223
2701
 
2224
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2702
+ CHECK_SOCKET_CLOSED(self);
2703
+
2704
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2225
2705
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2226
2706
  size = sizeof(int);
2227
2707
 
@@ -2230,7 +2710,7 @@ static VALUE rsctp_disable_fragments(VALUE self, VALUE v_bool){
2230
2710
  else
2231
2711
  value = 1;
2232
2712
 
2233
- if(sctp_opt_info(fileno, assoc_id, SCTP_DISABLE_FRAGMENTS, (void*)&value, &size) < 0)
2713
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_DISABLE_FRAGMENTS, (void*)&value, &size) < 0)
2234
2714
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2235
2715
 
2236
2716
  if(value)
@@ -2247,16 +2727,18 @@ static VALUE rsctp_disable_fragments(VALUE self, VALUE v_bool){
2247
2727
  * shut down.
2248
2728
  */
2249
2729
  static VALUE rsctp_get_autoclose(VALUE self){
2250
- int fileno;
2730
+ sctp_sock_t fileno;
2251
2731
  socklen_t size;
2252
2732
  sctp_assoc_t assoc_id;
2253
2733
  int value;
2254
2734
 
2255
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2735
+ CHECK_SOCKET_CLOSED(self);
2736
+
2737
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2256
2738
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2257
2739
  size = sizeof(int);
2258
2740
 
2259
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTOCLOSE, (void*)&value, &size) < 0)
2741
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_AUTOCLOSE, (void*)&value, &size) < 0)
2260
2742
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2261
2743
 
2262
2744
  return INT2NUM(value);
@@ -2285,13 +2767,15 @@ static VALUE rsctp_get_autoclose(VALUE self){
2285
2767
  * This socket option is applicable to the one-to-many style socket only.
2286
2768
  */
2287
2769
  static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
2288
- int fileno;
2770
+ sctp_sock_t fileno;
2289
2771
  int value;
2290
2772
 
2773
+ CHECK_SOCKET_CLOSED(self);
2774
+
2291
2775
  value = NUM2INT(v_seconds);
2292
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2776
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2293
2777
 
2294
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTOCLOSE, &value, sizeof(value)) < 0)
2778
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTOCLOSE, &value, sizeof(value)) < 0)
2295
2779
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2296
2780
 
2297
2781
  return INT2NUM(value);
@@ -2304,7 +2788,7 @@ static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
2304
2788
  * Enables auth for future associations.
2305
2789
  */
2306
2790
  static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2307
- int fileno;
2791
+ sctp_sock_t fileno;
2308
2792
  socklen_t size;
2309
2793
  sctp_assoc_t assoc_id;
2310
2794
  struct sctp_assoc_value assoc_value;
@@ -2314,7 +2798,7 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2314
2798
 
2315
2799
  CHECK_SOCKET_CLOSED(self);
2316
2800
 
2317
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2801
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2318
2802
  size = sizeof(struct sctp_assoc_value);
2319
2803
 
2320
2804
  if(NIL_P(v_assoc_id))
@@ -2325,7 +2809,7 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2325
2809
  assoc_value.assoc_id = assoc_id;
2326
2810
  assoc_value.assoc_value = 1;
2327
2811
 
2328
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, size) < 0)
2812
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, size) < 0)
2329
2813
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2330
2814
 
2331
2815
  return self;
@@ -2339,7 +2823,7 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2339
2823
  * Returns true if auth support is enabled, false otherwise.
2340
2824
  */
2341
2825
  static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
2342
- int fileno;
2826
+ sctp_sock_t fileno;
2343
2827
  socklen_t size;
2344
2828
  sctp_assoc_t assoc_id;
2345
2829
  struct sctp_assoc_value assoc_value;
@@ -2349,7 +2833,7 @@ static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
2349
2833
 
2350
2834
  CHECK_SOCKET_CLOSED(self);
2351
2835
 
2352
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2836
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2353
2837
  size = sizeof(struct sctp_assoc_value);
2354
2838
 
2355
2839
  if(NIL_P(v_assoc_id))
@@ -2359,7 +2843,7 @@ static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
2359
2843
 
2360
2844
  assoc_value.assoc_id = assoc_id;
2361
2845
 
2362
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
2846
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
2363
2847
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2364
2848
 
2365
2849
  if(assoc_value.assoc_value)
@@ -2395,7 +2879,7 @@ static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
2395
2879
  * otherwise this will set a key on the endpoint.
2396
2880
  */
2397
2881
  static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2398
- int fileno;
2882
+ sctp_sock_t fileno;
2399
2883
  size_t len;
2400
2884
  char* key;
2401
2885
  uint keynum;
@@ -2408,7 +2892,7 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2408
2892
 
2409
2893
  CHECK_SOCKET_CLOSED(self);
2410
2894
 
2411
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2895
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2412
2896
  key = StringValuePtr(v_key);
2413
2897
  len = RSTRING_LEN(v_key); // Use Ruby's string length, not strlen
2414
2898
 
@@ -2423,7 +2907,7 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2423
2907
  keynum = NUM2INT(v_keynumber);
2424
2908
 
2425
2909
  // Allocate the structure with space for the key
2426
- size = sizeof(struct sctp_authkey) + len;
2910
+ size = (socklen_t)(sizeof(struct sctp_authkey) + len);
2427
2911
  auth_key = malloc(size);
2428
2912
 
2429
2913
  if (auth_key == NULL)
@@ -2434,7 +2918,7 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2434
2918
  auth_key->sca_keylength = len;
2435
2919
  memcpy(auth_key->sca_key, key, len);
2436
2920
 
2437
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_KEY, (void*)auth_key, size) < 0) {
2921
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_KEY, (void*)auth_key, size) < 0) {
2438
2922
  int err = errno;
2439
2923
  free(auth_key);
2440
2924
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(err));
@@ -2451,7 +2935,7 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2451
2935
  * Gets the active shared key to be used to build the association shared key.
2452
2936
  */
2453
2937
  static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2454
- int fileno;
2938
+ sctp_sock_t fileno;
2455
2939
  socklen_t size;
2456
2940
  struct sctp_authkeyid authkey;
2457
2941
  sctp_assoc_t assoc_id;
@@ -2460,6 +2944,8 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2460
2944
 
2461
2945
  rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2462
2946
 
2947
+ CHECK_SOCKET_CLOSED(self);
2948
+
2463
2949
  bzero(&authkey, sizeof(authkey));
2464
2950
 
2465
2951
  // Cast it later, we want to force a validity check.
@@ -2468,7 +2954,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2468
2954
  if(keynum < 0)
2469
2955
  rb_raise(rb_eArgError, "invalid keynum value");
2470
2956
 
2471
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2957
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2472
2958
 
2473
2959
  if(NIL_P(v_assoc_id))
2474
2960
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
@@ -2480,7 +2966,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2480
2966
 
2481
2967
  size = sizeof(struct sctp_authkeyid);
2482
2968
 
2483
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, &size) < 0)
2969
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, &size) < 0)
2484
2970
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2485
2971
 
2486
2972
  return INT2NUM(authkey.scact_keynumber);
@@ -2509,7 +2995,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2509
2995
  * By default, the association_id is the result of SCTP::Socket#association_id.
2510
2996
  */
2511
2997
  static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2512
- int fileno;
2998
+ sctp_sock_t fileno;
2513
2999
  socklen_t size;
2514
3000
  struct sctp_authkeyid authkey;
2515
3001
  sctp_assoc_t assoc_id;
@@ -2518,12 +3004,14 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2518
3004
 
2519
3005
  rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2520
3006
 
3007
+ CHECK_SOCKET_CLOSED(self);
3008
+
2521
3009
  keynum = FIX2INT(v_keynum);
2522
3010
 
2523
3011
  if(keynum < 0)
2524
3012
  rb_raise(rb_eArgError, "invalid keynum value");
2525
3013
 
2526
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3014
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2527
3015
 
2528
3016
  if(NIL_P(v_assoc_id))
2529
3017
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
@@ -2534,7 +3022,7 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2534
3022
  authkey.scact_keynumber = (uint)keynum;
2535
3023
  size = sizeof(struct sctp_authkeyid);
2536
3024
 
2537
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, size) < 0)
3025
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, size) < 0)
2538
3026
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2539
3027
 
2540
3028
  return self;
@@ -2566,7 +3054,7 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2566
3054
  * otherwise this will delete the key from the endpoint.
2567
3055
  */
2568
3056
  static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2569
- int fileno;
3057
+ sctp_sock_t fileno;
2570
3058
  socklen_t size;
2571
3059
  struct sctp_authkeyid authkey;
2572
3060
  sctp_assoc_t assoc_id;
@@ -2579,7 +3067,7 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2579
3067
 
2580
3068
  bzero(&authkey, sizeof(authkey));
2581
3069
 
2582
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3070
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2583
3071
  keynum = NUM2UINT(v_keynum);
2584
3072
 
2585
3073
  if(NIL_P(v_assoc_id))
@@ -2592,7 +3080,7 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2592
3080
 
2593
3081
  size = sizeof(struct sctp_authkeyid);
2594
3082
 
2595
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, (void*)&authkey, size) < 0)
3083
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, (void*)&authkey, size) < 0)
2596
3084
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2597
3085
 
2598
3086
  return INT2NUM(authkey.scact_keynumber);
@@ -2612,15 +3100,18 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2612
3100
  * a no-op.
2613
3101
  */
2614
3102
  static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
2615
- int fileno, boolean;
3103
+ sctp_sock_t fileno;
3104
+ int boolean;
3105
+
3106
+ CHECK_SOCKET_CLOSED(self);
2616
3107
 
2617
3108
  boolean = 0;
2618
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3109
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2619
3110
 
2620
3111
  if(v_bool == Qtrue)
2621
3112
  boolean = 1;
2622
3113
 
2623
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&boolean, sizeof(boolean)) < 0)
3114
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&boolean, sizeof(boolean)) < 0)
2624
3115
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2625
3116
 
2626
3117
  return v_bool;
@@ -2634,18 +3125,18 @@ static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
2634
3125
  * for PF_INET6 sockets. Returns true if mapping is enabled, false otherwise.
2635
3126
  */
2636
3127
  static VALUE rsctp_get_map_ipv4(VALUE self){
2637
- int fileno;
3128
+ sctp_sock_t fileno;
2638
3129
  socklen_t size;
2639
3130
  sctp_assoc_t assoc_id;
2640
3131
  int value;
2641
3132
 
2642
3133
  CHECK_SOCKET_CLOSED(self);
2643
3134
 
2644
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3135
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2645
3136
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2646
3137
  size = sizeof(int);
2647
3138
 
2648
- if(sctp_opt_info(fileno, assoc_id, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&value, &size) < 0)
3139
+ if(sctp_sys_opt_info(fileno, assoc_id, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&value, &size) < 0)
2649
3140
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2650
3141
 
2651
3142
  if(value)
@@ -2679,7 +3170,7 @@ static VALUE rsctp_get_map_ipv4(VALUE self){
2679
3170
  */
2680
3171
  static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2681
3172
  VALUE v_stream, v_ssn, v_flags, v_ppid, v_context, v_ttl, v_tsn, v_cumtsn, v_assoc_id;
2682
- int fileno;
3173
+ sctp_sock_t fileno;
2683
3174
  sctp_assoc_t assoc_id;
2684
3175
  struct sctp_sndrcvinfo sndrcv;
2685
3176
 
@@ -2688,7 +3179,9 @@ static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2688
3179
 
2689
3180
  bzero(&sndrcv, sizeof(sndrcv));
2690
3181
 
2691
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3182
+ CHECK_SOCKET_CLOSED(self);
3183
+
3184
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
2692
3185
 
2693
3186
  v_stream = rb_hash_aref2(v_options, "stream");
2694
3187
  v_ssn = rb_hash_aref2(v_options, "ssn");
@@ -2730,8 +3223,23 @@ static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2730
3223
  if(!NIL_P(v_cumtsn))
2731
3224
  sndrcv.sinfo_cumtsn = NUM2INT(v_cumtsn);
2732
3225
 
2733
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, &sndrcv, sizeof(sndrcv)) < 0)
3226
+ #ifdef HAVE_USRSCTP_H
3227
+ {
3228
+ struct sctp_sndinfo sndinfo;
3229
+ bzero(&sndinfo, sizeof(sndinfo));
3230
+ sndinfo.snd_sid = sndrcv.sinfo_stream;
3231
+ sndinfo.snd_flags = sndrcv.sinfo_flags;
3232
+ sndinfo.snd_ppid = sndrcv.sinfo_ppid;
3233
+ sndinfo.snd_context = sndrcv.sinfo_context;
3234
+ sndinfo.snd_assoc_id = sndrcv.sinfo_assoc_id;
3235
+
3236
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_DEFAULT_SNDINFO, &sndinfo, sizeof(sndinfo)) < 0)
3237
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
3238
+ }
3239
+ #else
3240
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, &sndrcv, sizeof(sndrcv)) < 0)
2734
3241
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
3242
+ #endif
2735
3243
 
2736
3244
  return rb_struct_new(
2737
3245
  v_sctp_default_send_params_struct,
@@ -2771,17 +3279,20 @@ static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2771
3279
  */
2772
3280
  static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
2773
3281
  VALUE v_assoc_id, v_address, v_hbinterval, v_pathmaxrxt, v_pathmtu, v_flags, v_ipv6_flowlabel;
2774
- int fileno;
3282
+ sctp_sock_t fileno;
3283
+ int domain;
2775
3284
  sctp_assoc_t assoc_id;
2776
3285
  struct sctp_paddrparams paddr;
2777
- struct sockaddr_in* sin;
2778
3286
 
2779
3287
  if(!RB_TYPE_P(v_options, T_HASH))
2780
3288
  rb_raise(rb_eTypeError, "options must be a hash");
2781
3289
 
2782
3290
  bzero(&paddr, sizeof(paddr));
2783
3291
 
2784
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3292
+ CHECK_SOCKET_CLOSED(self);
3293
+
3294
+ fileno = NUM_TO_SCTP_FD(rb_iv_get(self, "@fileno"));
3295
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
2785
3296
 
2786
3297
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
2787
3298
  v_address = rb_hash_aref2(v_options, "address");
@@ -2797,12 +3308,28 @@ static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
2797
3308
  assoc_id = NUM2INT(v_assoc_id);
2798
3309
  paddr.spp_assoc_id = assoc_id;
2799
3310
 
2800
- // If address is provided, set up the sockaddr structure
3311
+ // If address is provided, set up the sockaddr structure based on domain
2801
3312
  if(!NIL_P(v_address)){
2802
- sin = (struct sockaddr_in*)&paddr.spp_address;
2803
- sin->sin_family = AF_INET;
2804
- if(inet_pton(AF_INET, StringValueCStr(v_address), &sin->sin_addr) <= 0)
2805
- rb_raise(rb_eArgError, "invalid IP address");
3313
+ const char* addr_str = StringValueCStr(v_address);
3314
+
3315
+ if(domain == AF_INET6){
3316
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&paddr.spp_address;
3317
+ sin6->sin6_family = AF_INET6;
3318
+ if(inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) <= 0)
3319
+ rb_raise(rb_eArgError, "invalid IPv6 address: %s", addr_str);
3320
+ #ifdef BSD
3321
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
3322
+ #endif
3323
+ }
3324
+ else{
3325
+ struct sockaddr_in* sin = (struct sockaddr_in*)&paddr.spp_address;
3326
+ sin->sin_family = AF_INET;
3327
+ if(inet_pton(AF_INET, addr_str, &sin->sin_addr) <= 0)
3328
+ rb_raise(rb_eArgError, "invalid IPv4 address: %s", addr_str);
3329
+ #ifdef BSD
3330
+ sin->sin_len = sizeof(struct sockaddr_in);
3331
+ #endif
3332
+ }
2806
3333
  }
2807
3334
 
2808
3335
  if(!NIL_P(v_hbinterval))
@@ -2820,7 +3347,7 @@ static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
2820
3347
  if(!NIL_P(v_ipv6_flowlabel))
2821
3348
  paddr.spp_ipv6_flowlabel = NUM2INT(v_ipv6_flowlabel);
2822
3349
 
2823
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddr, sizeof(paddr)) < 0)
3350
+ if(sctp_sys_setsockopt(fileno, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddr, sizeof(paddr)) < 0)
2824
3351
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2825
3352
 
2826
3353
  return rb_struct_new(
@@ -2920,7 +3447,7 @@ void Init_socket(void){
2920
3447
 
2921
3448
  v_sctp_receive_info_struct = rb_struct_define(
2922
3449
  "ReceiveInfo", "message", "sid", "ssn", "flags", "ppid", "tsn",
2923
- "cumtsn", "context", "assocation_id", NULL
3450
+ "cumtsn", "context", "association_id", NULL
2924
3451
  );
2925
3452
 
2926
3453
  v_sctp_peer_addr_params_struct = rb_struct_define(
@@ -2993,8 +3520,8 @@ void Init_socket(void){
2993
3520
  rb_define_attr(cSocket, "association_id", 1, 1);
2994
3521
  rb_define_attr(cSocket, "port", 1, 1);
2995
3522
 
2996
- /* 0.2.0: The version of this library */
2997
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.2.1"));
3523
+ /* 0.3.0: The version of this library */
3524
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.3.0"));
2998
3525
 
2999
3526
  /* send flags */
3000
3527