sctp-socket 0.2.0 → 0.2.2

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
@@ -63,6 +63,65 @@ VALUE v_sctp_initmsg_struct;
63
63
  #define MAX_IP_ADDRESSES 8
64
64
  #define DEFAULT_BUFFER_SIZE 1024
65
65
  #define IP_BUFFER_SIZE INET6_ADDRSTRLEN
66
+ #define MAX_NOTIFICATION_DATA 8192
67
+
68
+ /*
69
+ * Helper function to parse an IP address string and fill a sockaddr_in or sockaddr_in6 structure.
70
+ * Supports both IPv4 and IPv6 addresses.
71
+ *
72
+ * @param addr_str The IP address string to parse
73
+ * @param port The port number (in host byte order)
74
+ * @param sin Pointer to sockaddr_in to fill (for IPv4)
75
+ * @param sin6 Pointer to sockaddr_in6 to fill (for IPv6)
76
+ * @param domain The address family (AF_INET or AF_INET6)
77
+ */
78
+ static void parse_ip_address_v4(const char* addr_str, int port, struct sockaddr_in* sin){
79
+ bzero(sin, sizeof(*sin));
80
+ sin->sin_family = AF_INET;
81
+ sin->sin_port = htons(port);
82
+ if(inet_pton(AF_INET, addr_str, &sin->sin_addr) != 1)
83
+ rb_raise(rb_eArgError, "invalid IPv4 address: %s", addr_str);
84
+ #ifdef BSD
85
+ sin->sin_len = sizeof(struct sockaddr_in);
86
+ #endif
87
+ }
88
+
89
+ static void parse_ip_address_v6(const char* addr_str, int port, struct sockaddr_in6* sin6){
90
+ bzero(sin6, sizeof(*sin6));
91
+ sin6->sin6_family = AF_INET6;
92
+ sin6->sin6_port = htons(port);
93
+ if(inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) != 1)
94
+ rb_raise(rb_eArgError, "invalid IPv6 address: %s", addr_str);
95
+ #ifdef BSD
96
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
97
+ #endif
98
+ }
99
+
100
+ /*
101
+ * Helper function to set INADDR_ANY for IPv4.
102
+ */
103
+ static void set_any_address_v4(int port, struct sockaddr_in* sin){
104
+ bzero(sin, sizeof(*sin));
105
+ sin->sin_family = AF_INET;
106
+ sin->sin_port = htons(port);
107
+ sin->sin_addr.s_addr = htonl(INADDR_ANY);
108
+ #ifdef BSD
109
+ sin->sin_len = sizeof(struct sockaddr_in);
110
+ #endif
111
+ }
112
+
113
+ /*
114
+ * Helper function to set IN6ADDR_ANY for IPv6.
115
+ */
116
+ static void set_any_address_v6(int port, struct sockaddr_in6* sin6){
117
+ bzero(sin6, sizeof(*sin6));
118
+ sin6->sin6_family = AF_INET6;
119
+ sin6->sin6_port = htons(port);
120
+ sin6->sin6_addr = in6addr_any;
121
+ #ifdef BSD
122
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
123
+ #endif
124
+ }
66
125
 
67
126
  /*
68
127
  * Convert a sockaddr_in structure to a Ruby struct.
@@ -197,12 +256,18 @@ VALUE get_notification_info(char* buffer){
197
256
  v_str = rb_str_new2("unknown");
198
257
  }
199
258
 
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
- );
259
+ {
260
+ struct sockaddr* sa = (struct sockaddr*)&snp->sn_paddr_change.spc_aaddr;
261
+
262
+ if(sa->sa_family == AF_INET6){
263
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
264
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
265
+ }
266
+ else{
267
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
268
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
269
+ }
270
+ }
206
271
 
207
272
  v_notification = rb_struct_new(v_peeraddr_change_struct,
208
273
  UINT2NUM(snp->sn_paddr_change.spc_type),
@@ -215,83 +280,150 @@ VALUE get_notification_info(char* buffer){
215
280
  );
216
281
  break;
217
282
  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]);
283
+ {
284
+ size_t data_len = 0;
285
+ VALUE v_data_ary;
286
+
287
+ // Calculate actual data length (total length minus fixed header)
288
+ if(snp->sn_remote_error.sre_length > offsetof(struct sctp_remote_error, sre_data))
289
+ data_len = snp->sn_remote_error.sre_length - offsetof(struct sctp_remote_error, sre_data);
290
+
291
+ // Bounds check to prevent stack overflow
292
+ if(data_len > MAX_NOTIFICATION_DATA)
293
+ data_len = MAX_NOTIFICATION_DATA;
294
+
295
+ if(data_len > 0){
296
+ v_temp = ALLOCA_N(VALUE, data_len);
297
+ for(i = 0; i < data_len; i++){
298
+ v_temp[i] = UINT2NUM(snp->sn_remote_error.sre_data[i]);
299
+ }
300
+ v_data_ary = rb_ary_new4(data_len, v_temp);
301
+ }
302
+ else{
303
+ v_data_ary = rb_ary_new();
304
+ }
305
+
306
+ v_notification = rb_struct_new(v_remote_error_struct,
307
+ UINT2NUM(snp->sn_remote_error.sre_type),
308
+ UINT2NUM(snp->sn_remote_error.sre_flags),
309
+ UINT2NUM(snp->sn_remote_error.sre_length),
310
+ UINT2NUM(snp->sn_remote_error.sre_error),
311
+ UINT2NUM(snp->sn_remote_error.sre_assoc_id),
312
+ v_data_ary
313
+ );
222
314
  }
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
315
  break;
233
316
  #ifdef SCTP_SEND_FAILED_EVENT
234
317
  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);
237
-
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
- }
318
+ {
319
+ size_t data_len = 0;
320
+ VALUE v_data_ary;
241
321
 
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
- );
322
+ #ifdef HAVE_STRUCT_SCTP_SEND_FAILED_EVENT_SSFE_LENGTH
323
+ // Calculate actual data length (total length minus fixed header)
324
+ if(snp->sn_send_failed_event.ssfe_length > offsetof(struct sctp_send_failed_event, ssfe_data))
325
+ data_len = snp->sn_send_failed_event.ssfe_length - offsetof(struct sctp_send_failed_event, ssfe_data);
326
+
327
+ // Bounds check to prevent stack overflow
328
+ if(data_len > MAX_NOTIFICATION_DATA)
329
+ data_len = MAX_NOTIFICATION_DATA;
330
+
331
+ if(data_len > 0){
332
+ v_temp = ALLOCA_N(VALUE, data_len);
333
+ for(i = 0; i < data_len; i++){
334
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssfe_data[i]);
335
+ }
336
+ v_data_ary = rb_ary_new4(data_len, v_temp);
337
+ }
338
+ else{
339
+ v_data_ary = rb_ary_new();
340
+ }
341
+
342
+ v_notification = rb_struct_new(v_send_failed_event_struct,
343
+ UINT2NUM(snp->sn_send_failed_event.ssfe_type),
344
+ UINT2NUM(snp->sn_send_failed_event.ssfe_length),
345
+ UINT2NUM(snp->sn_send_failed_event.ssfe_error),
346
+ rb_struct_new(v_sndinfo_struct,
347
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
348
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
349
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
350
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
351
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
352
+ ),
353
+ UINT2NUM(snp->sn_send_failed_event.ssfe_assoc_id),
354
+ v_data_ary
355
+ );
256
356
  #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
- );
357
+ // Calculate actual data length (total length minus fixed header)
358
+ if(snp->sn_send_failed_event.ssf_length > offsetof(struct sctp_send_failed_event, ssf_data))
359
+ data_len = snp->sn_send_failed_event.ssf_length - offsetof(struct sctp_send_failed_event, ssf_data);
360
+
361
+ // Bounds check to prevent stack overflow
362
+ if(data_len > MAX_NOTIFICATION_DATA)
363
+ data_len = MAX_NOTIFICATION_DATA;
364
+
365
+ if(data_len > 0){
366
+ v_temp = ALLOCA_N(VALUE, data_len);
367
+ for(i = 0; i < data_len; i++){
368
+ v_temp[i] = UINT2NUM(snp->sn_send_failed_event.ssf_data[i]);
369
+ }
370
+ v_data_ary = rb_ary_new4(data_len, v_temp);
371
+ }
372
+ else{
373
+ v_data_ary = rb_ary_new();
374
+ }
375
+
376
+ v_notification = rb_struct_new(v_send_failed_event_struct,
377
+ UINT2NUM(snp->sn_send_failed_event.ssf_type),
378
+ UINT2NUM(snp->sn_send_failed_event.ssf_length),
379
+ UINT2NUM(snp->sn_send_failed_event.ssf_error),
380
+ rb_struct_new(v_sndinfo_struct,
381
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_sid),
382
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_flags),
383
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_ppid),
384
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_context),
385
+ UINT2NUM(snp->sn_send_failed_event.ssfe_info.snd_assoc_id)
386
+ ),
387
+ UINT2NUM(snp->sn_send_failed_event.ssf_assoc_id),
388
+ v_data_ary
389
+ );
277
390
  #endif
391
+ }
278
392
  break;
279
393
  #else
280
394
  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]);
395
+ {
396
+ size_t data_len = 0;
397
+ VALUE v_data_ary;
398
+
399
+ // Calculate actual data length (total length minus fixed header)
400
+ if(snp->sn_send_failed.ssf_length > offsetof(struct sctp_send_failed, ssf_data))
401
+ data_len = snp->sn_send_failed.ssf_length - offsetof(struct sctp_send_failed, ssf_data);
402
+
403
+ // Bounds check to prevent stack overflow
404
+ if(data_len > MAX_NOTIFICATION_DATA)
405
+ data_len = MAX_NOTIFICATION_DATA;
406
+
407
+ if(data_len > 0){
408
+ v_temp = ALLOCA_N(VALUE, data_len);
409
+ for(i = 0; i < data_len; i++){
410
+ v_temp[i] = UINT2NUM(snp->sn_send_failed.ssf_data[i]);
411
+ }
412
+ v_data_ary = rb_ary_new4(data_len, v_temp);
413
+ }
414
+ else{
415
+ v_data_ary = rb_ary_new();
416
+ }
417
+
418
+ v_notification = rb_struct_new(v_send_failed_event_struct,
419
+ UINT2NUM(snp->sn_send_failed.ssf_type),
420
+ UINT2NUM(snp->sn_send_failed.ssf_length),
421
+ UINT2NUM(snp->sn_send_failed.ssf_error),
422
+ Qnil,
423
+ UINT2NUM(snp->sn_send_failed.ssf_assoc_id),
424
+ v_data_ary
425
+ );
285
426
  }
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
427
  break;
296
428
  #endif
297
429
  case SCTP_SHUTDOWN_EVENT:
@@ -451,14 +583,11 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
451
583
  * Returns the port that it was bound to.
452
584
  */
453
585
  static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
454
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
455
586
  int i, fileno, num_ip, flags, domain, port, on;
456
587
  VALUE v_addresses, v_port, v_flags, v_address, v_reuse_addr, v_options;
457
588
 
458
589
  rb_scan_args(argc, argv, "01", &v_options);
459
590
 
460
- bzero(&addrs, sizeof(addrs));
461
-
462
591
  if(NIL_P(v_options))
463
592
  v_options = rb_hash_new();
464
593
 
@@ -485,37 +614,51 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
485
614
  if(num_ip > MAX_IP_ADDRESSES)
486
615
  rb_raise(rb_eArgError, "too many IP addresses to bind, maximum is eight");
487
616
 
617
+ CHECK_SOCKET_CLOSED(self);
618
+
488
619
  domain = NUM2INT(rb_iv_get(self, "@domain"));
489
620
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
490
621
 
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);
499
- #endif
500
- }
501
- }
502
- 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
- }
510
-
511
622
  if(v_reuse_addr == Qtrue){
512
623
  on = 1;
513
624
  if(setsockopt(fileno, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
514
625
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
515
626
  }
516
627
 
517
- if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0)
518
- rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
628
+ if(domain == AF_INET6){
629
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
630
+ bzero(&addrs6, sizeof(addrs6));
631
+
632
+ if(!NIL_P(v_addresses)){
633
+ for(i = 0; i < num_ip; i++){
634
+ v_address = RARRAY_AREF(v_addresses, i);
635
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
636
+ }
637
+ }
638
+ else{
639
+ set_any_address_v6(port, &addrs6[0]);
640
+ }
641
+
642
+ if(sctp_bindx(fileno, (struct sockaddr *)addrs6, num_ip, flags) != 0)
643
+ rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
644
+ }
645
+ else{
646
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
647
+ bzero(&addrs, sizeof(addrs));
648
+
649
+ if(!NIL_P(v_addresses)){
650
+ for(i = 0; i < num_ip; i++){
651
+ v_address = RARRAY_AREF(v_addresses, i);
652
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
653
+ }
654
+ }
655
+ else{
656
+ set_any_address_v4(port, &addrs[0]);
657
+ }
658
+
659
+ if(sctp_bindx(fileno, (struct sockaddr *)addrs, num_ip, flags) != 0)
660
+ rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
661
+ }
519
662
 
520
663
  if(port == 0){
521
664
  struct sockaddr_in sin;
@@ -550,10 +693,9 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
550
693
  * methods will automatically establish associations.
551
694
  */
552
695
  static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
553
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
554
- int i, num_ip, fileno;
696
+ int i, num_ip, fileno, domain, port;
555
697
  sctp_assoc_t assoc;
556
- VALUE v_address, v_domain, v_options, v_addresses, v_port;
698
+ VALUE v_address, v_options, v_addresses, v_port;
557
699
 
558
700
  rb_scan_args(argc, argv, "01", &v_options);
559
701
 
@@ -571,25 +713,41 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
571
713
  if(NIL_P(v_port))
572
714
  rb_raise(rb_eArgError, "you must specify a port");
573
715
 
574
- v_domain = rb_iv_get(self, "@domain");
716
+ CHECK_SOCKET_CLOSED(self);
717
+
718
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
719
+ port = NUM2INT(v_port);
720
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
575
721
 
576
722
  num_ip = (int)RARRAY_LEN(v_addresses);
577
- bzero(&addrs, sizeof(addrs));
578
723
 
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
724
+ if(num_ip > MAX_IP_ADDRESSES)
725
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
726
+
727
+ if(domain == AF_INET6){
728
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
729
+ bzero(&addrs6, sizeof(addrs6));
730
+
731
+ for(i = 0; i < num_ip; i++){
732
+ v_address = RARRAY_AREF(v_addresses, i);
733
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
734
+ }
735
+
736
+ if(sctp_connectx(fileno, (struct sockaddr *)addrs6, num_ip, &assoc) < 0)
737
+ rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
587
738
  }
739
+ else{
740
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
741
+ bzero(&addrs, sizeof(addrs));
588
742
 
589
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
743
+ for(i = 0; i < num_ip; i++){
744
+ v_address = RARRAY_AREF(v_addresses, i);
745
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
746
+ }
590
747
 
591
- if(sctp_connectx(fileno, (struct sockaddr *) addrs, num_ip, &assoc) < 0)
592
- rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
748
+ if(sctp_connectx(fileno, (struct sockaddr *)addrs, num_ip, &assoc) < 0)
749
+ rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
750
+ }
593
751
 
594
752
  rb_iv_set(self, "@association_id", INT2NUM(assoc));
595
753
 
@@ -731,8 +889,18 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
731
889
  }
732
890
 
733
891
  for(i = 0; i < num_addrs; i++){
892
+ struct sockaddr* sa = &addrs[i];
734
893
  bzero(&str, sizeof(str));
735
- inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
894
+
895
+ if(sa->sa_family == AF_INET6){
896
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
897
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
898
+ }
899
+ else{
900
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
901
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
902
+ }
903
+
736
904
  rb_ary_push(v_array, rb_str_new2(str));
737
905
  }
738
906
 
@@ -792,8 +960,18 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
792
960
  }
793
961
 
794
962
  for(i = 0; i < num_addrs; i++){
963
+ struct sockaddr* sa = &addrs[i];
795
964
  bzero(&str, sizeof(str));
796
- inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
965
+
966
+ if(sa->sa_family == AF_INET6){
967
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
968
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
969
+ }
970
+ else{
971
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
972
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
973
+ }
974
+
797
975
  rb_ary_push(v_array, rb_str_new2(str));
798
976
  }
799
977
 
@@ -832,9 +1010,8 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
832
1010
  static VALUE rsctp_sendv(VALUE self, VALUE v_options){
833
1011
  VALUE v_msg, v_message, v_addresses;
834
1012
  struct iovec iov[IOV_MAX];
835
- struct sockaddr_in* addrs;
836
1013
  struct sctp_sendv_spa spa;
837
- int i, fileno, size, num_ip;
1014
+ int i, fileno, size, num_ip, domain, port;
838
1015
  ssize_t num_bytes;
839
1016
 
840
1017
  Check_Type(v_options, T_HASH);
@@ -851,13 +1028,16 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
851
1028
 
852
1029
  Check_Type(v_message, T_ARRAY);
853
1030
 
1031
+ CHECK_SOCKET_CLOSED(self);
1032
+
854
1033
  if(!NIL_P(v_addresses)){
855
1034
  Check_Type(v_addresses, T_ARRAY);
856
1035
  num_ip = (int)RARRAY_LEN(v_addresses);
857
- addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(*addrs));
1036
+
1037
+ if(num_ip > MAX_IP_ADDRESSES)
1038
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
858
1039
  }
859
1040
  else{
860
- addrs = NULL;
861
1041
  num_ip = 0;
862
1042
  }
863
1043
 
@@ -875,8 +1055,15 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
875
1055
  spa.sendv_sndinfo.snd_flags = SCTP_UNORDERED;
876
1056
  spa.sendv_sndinfo.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
877
1057
 
878
- if(!NIL_P(v_addresses)){
879
- int i, port, domain;
1058
+ for(i = 0; i < size; i++){
1059
+ v_msg = RARRAY_AREF(v_message, i);
1060
+ iov[i].iov_base = StringValueCStr(v_msg);
1061
+ iov[i].iov_len = RSTRING_LEN(v_msg);
1062
+ }
1063
+
1064
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
1065
+
1066
+ if(num_ip > 0){
880
1067
  VALUE v_address, v_port;
881
1068
 
882
1069
  v_port = rb_iv_get(self, "@port");
@@ -886,36 +1073,62 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
886
1073
  else
887
1074
  port = NUM2INT(v_port);
888
1075
 
889
- domain = NUM2INT(rb_iv_get(self, "@domain"));
1076
+ if(domain == AF_INET6){
1077
+ struct sockaddr_in6* addrs6 = (struct sockaddr_in6*)alloca(num_ip * sizeof(struct sockaddr_in6));
1078
+ bzero(addrs6, num_ip * sizeof(struct sockaddr_in6));
890
1079
 
891
- for(i = 0; i < num_ip; i++){
892
- v_address = RARRAY_PTR(v_addresses)[i];
893
- addrs[i].sin_family = domain;
894
- addrs[i].sin_port = htons(port);
895
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
896
- #ifdef BSD
897
- addrs[i].sin_len = sizeof(struct sockaddr_in);
898
- #endif
1080
+ for(i = 0; i < num_ip; i++){
1081
+ v_address = RARRAY_AREF(v_addresses, i);
1082
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
1083
+ }
1084
+
1085
+ num_bytes = (ssize_t)sctp_sendv(
1086
+ fileno,
1087
+ iov,
1088
+ size,
1089
+ (struct sockaddr*)addrs6,
1090
+ num_ip,
1091
+ &spa,
1092
+ sizeof(spa),
1093
+ SCTP_SENDV_SPA,
1094
+ 0
1095
+ );
899
1096
  }
900
- }
1097
+ else{
1098
+ struct sockaddr_in* addrs = (struct sockaddr_in*)alloca(num_ip * sizeof(struct sockaddr_in));
1099
+ bzero(addrs, num_ip * sizeof(struct sockaddr_in));
901
1100
 
902
- for(i = 0; i < size; i++){
903
- v_msg = RARRAY_PTR(v_message)[i];
904
- iov[i].iov_base = StringValueCStr(v_msg);
905
- iov[i].iov_len = RSTRING_LEN(v_msg);
906
- }
1101
+ for(i = 0; i < num_ip; i++){
1102
+ v_address = RARRAY_AREF(v_addresses, i);
1103
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
1104
+ }
907
1105
 
908
- num_bytes = (ssize_t)sctp_sendv(
909
- fileno,
910
- iov,
911
- size,
912
- (struct sockaddr*)addrs,
913
- num_ip,
914
- &spa,
915
- sizeof(spa),
916
- SCTP_SENDV_SPA,
917
- 0
918
- );
1106
+ num_bytes = (ssize_t)sctp_sendv(
1107
+ fileno,
1108
+ iov,
1109
+ size,
1110
+ (struct sockaddr*)addrs,
1111
+ num_ip,
1112
+ &spa,
1113
+ sizeof(spa),
1114
+ SCTP_SENDV_SPA,
1115
+ 0
1116
+ );
1117
+ }
1118
+ }
1119
+ else{
1120
+ num_bytes = (ssize_t)sctp_sendv(
1121
+ fileno,
1122
+ iov,
1123
+ size,
1124
+ NULL,
1125
+ 0,
1126
+ &spa,
1127
+ sizeof(spa),
1128
+ SCTP_SENDV_SPA,
1129
+ 0
1130
+ );
1131
+ }
919
1132
 
920
1133
  if(num_bytes < 0)
921
1134
  rb_raise(rb_eSystemCallError, "sctp_sendv: %s", strerror(errno));
@@ -925,24 +1138,50 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
925
1138
  #endif
926
1139
 
927
1140
  #ifdef HAVE_SCTP_RECVV
1141
+ /*
1142
+ * call-seq:
1143
+ * SCTP::Socket#recvv(flags=0, buffer_size=1024)
1144
+ *
1145
+ * Receive a message using sctp_recvv from another SCTP endpoint.
1146
+ *
1147
+ * The optional buffer_size parameter specifies the size of the receive buffer
1148
+ * in bytes. Defaults to 1024 bytes if not specified.
1149
+ *
1150
+ * Example:
1151
+ *
1152
+ * begin
1153
+ * socket = SCTP::Socket.new
1154
+ * socket.bind(:port => 62534, :addresses => ['10.0.4.5', '10.0.5.5'])
1155
+ * socket.listen
1156
+ *
1157
+ * while true
1158
+ * info = socket.recvv
1159
+ * puts "Received message: #{info.message}"
1160
+ *
1161
+ * # Or with custom buffer size
1162
+ * info = socket.recvv(0, 4096)
1163
+ * puts "Received message: #{info.message}"
1164
+ * end
1165
+ * ensure
1166
+ * socket.close
1167
+ * end
1168
+ */
928
1169
  static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
929
- VALUE v_flags;
930
- int fileno, flags, on;
1170
+ VALUE v_flags, v_buffer_size;
1171
+ int fileno, flags, on, buffer_size;
931
1172
  ssize_t bytes;
932
1173
  uint infotype;
933
1174
  socklen_t infolen;
934
1175
  struct iovec iov[1];
935
1176
  struct sctp_rcvinfo info;
936
- char buffer[1024];
1177
+ char *buffer;
937
1178
 
938
1179
  bzero(&iov, sizeof(iov));
939
1180
  bzero(&info, sizeof(info));
940
- bzero(&buffer, sizeof(buffer));
941
1181
 
942
- iov->iov_base = buffer;
943
- iov->iov_len = sizeof(buffer);
1182
+ rb_scan_args(argc, argv, "02", &v_flags, &v_buffer_size);
944
1183
 
945
- rb_scan_args(argc, argv, "01", &v_flags);
1184
+ CHECK_SOCKET_CLOSED(self);
946
1185
 
947
1186
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
948
1187
 
@@ -951,9 +1190,28 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
951
1190
  else
952
1191
  flags = NUM2INT(v_flags);
953
1192
 
1193
+ if(NIL_P(v_buffer_size))
1194
+ buffer_size = 1024;
1195
+ else
1196
+ buffer_size = NUM2INT(v_buffer_size);
1197
+
1198
+ if(buffer_size <= 0)
1199
+ rb_raise(rb_eArgError, "buffer size must be positive");
1200
+
1201
+ buffer = (char*)malloc(buffer_size);
1202
+ if(buffer == NULL)
1203
+ rb_raise(rb_eNoMemError, "failed to allocate buffer");
1204
+
1205
+ bzero(buffer, buffer_size);
1206
+
1207
+ iov->iov_base = buffer;
1208
+ iov->iov_len = buffer_size;
1209
+
954
1210
  on = 1;
955
- if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0)
1211
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0){
1212
+ free(buffer);
956
1213
  rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
1214
+ }
957
1215
 
958
1216
  infolen = sizeof(struct sctp_rcvinfo);
959
1217
  infotype = 0;
@@ -970,16 +1228,19 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
970
1228
  &flags
971
1229
  );
972
1230
 
973
- if(bytes < 0)
1231
+ if(bytes < 0){
1232
+ free(buffer);
974
1233
  rb_raise(rb_eSystemCallError, "sctp_recvv: %s", strerror(errno));
1234
+ }
975
1235
 
976
1236
  if(infotype != SCTP_RECVV_RCVINFO){
1237
+ free(buffer);
977
1238
  return Qnil;
978
1239
  }
979
1240
  else{
980
- return rb_struct_new(
1241
+ VALUE result = rb_struct_new(
981
1242
  v_sctp_receive_info_struct,
982
- rb_str_new2(iov->iov_base),
1243
+ rb_str_new(iov->iov_base, bytes),
983
1244
  UINT2NUM(info.rcv_sid),
984
1245
  UINT2NUM(info.rcv_ssn),
985
1246
  UINT2NUM(info.rcv_flags),
@@ -989,6 +1250,8 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
989
1250
  UINT2NUM(info.rcv_context),
990
1251
  UINT2NUM(info.rcv_assoc_id)
991
1252
  );
1253
+ free(buffer);
1254
+ return result;
992
1255
  }
993
1256
  }
994
1257
  #endif
@@ -1066,6 +1329,8 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
1066
1329
  else
1067
1330
  assoc_id = NUM2INT(v_assoc_id);
1068
1331
 
1332
+ CHECK_SOCKET_CLOSED(self);
1333
+
1069
1334
  info.sinfo_stream = stream;
1070
1335
  info.sinfo_flags = send_flags;
1071
1336
  info.sinfo_ppid = ppid;
@@ -1126,13 +1391,10 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1126
1391
  uint16_t stream;
1127
1392
  uint32_t ppid, flags, ttl, context;
1128
1393
  ssize_t num_bytes;
1129
- struct sockaddr_in addrs[MAX_IP_ADDRESSES];
1130
- int fileno, size, num_ip;
1394
+ int fileno, num_ip, domain;
1131
1395
 
1132
1396
  Check_Type(v_options, T_HASH);
1133
1397
 
1134
- bzero(&addrs, sizeof(addrs));
1135
-
1136
1398
  v_msg = rb_hash_aref2(v_options, "message");
1137
1399
  v_stream = rb_hash_aref2(v_options, "stream");
1138
1400
  v_ppid = rb_hash_aref2(v_options, "ppid");
@@ -1172,12 +1434,21 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1172
1434
  else
1173
1435
  context = NUM2INT(v_context);
1174
1436
 
1437
+ CHECK_SOCKET_CLOSED(self);
1438
+
1439
+ fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1440
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
1441
+
1175
1442
  if(!NIL_P(v_addresses)){
1176
1443
  int i, port;
1177
1444
  VALUE v_address, v_port;
1178
1445
 
1179
1446
  Check_Type(v_addresses, T_ARRAY);
1180
1447
  num_ip = (int)RARRAY_LEN(v_addresses);
1448
+
1449
+ if(num_ip > MAX_IP_ADDRESSES)
1450
+ rb_raise(rb_eArgError, "too many IP addresses, maximum is eight");
1451
+
1181
1452
  v_port = rb_hash_aref2(v_options, "port");
1182
1453
 
1183
1454
  if(NIL_P(v_port))
@@ -1185,47 +1456,92 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1185
1456
  else
1186
1457
  port = NUM2INT(v_port);
1187
1458
 
1188
- for(i = 0; i < num_ip; i++){
1189
- v_address = RARRAY_PTR(v_addresses)[i];
1190
- addrs[i].sin_family = NUM2INT(rb_iv_get(self, "@domain"));
1191
- addrs[i].sin_port = htons(port);
1192
- addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
1459
+ if(domain == AF_INET6){
1460
+ struct sockaddr_in6 addrs6[MAX_IP_ADDRESSES];
1461
+
1462
+ bzero(&addrs6, sizeof(addrs6));
1463
+
1464
+ for(i = 0; i < num_ip; i++){
1465
+ v_address = RARRAY_AREF(v_addresses, i);
1466
+ parse_ip_address_v6(StringValueCStr(v_address), port, &addrs6[i]);
1467
+ }
1468
+
1193
1469
  #ifdef BSD
1194
- addrs[i].sin_len = sizeof(struct sockaddr_in);
1470
+ num_bytes = (ssize_t)sctp_sendmsgx(
1471
+ fileno,
1472
+ StringValueCStr(v_msg),
1473
+ RSTRING_LEN(v_msg),
1474
+ (struct sockaddr*)addrs6,
1475
+ num_ip,
1476
+ ppid,
1477
+ flags,
1478
+ stream,
1479
+ ttl,
1480
+ context
1481
+ );
1482
+ #else
1483
+ num_bytes = (ssize_t)sctp_sendmsg(
1484
+ fileno,
1485
+ StringValueCStr(v_msg),
1486
+ RSTRING_LEN(v_msg),
1487
+ (struct sockaddr*)addrs6,
1488
+ num_ip * sizeof(struct sockaddr_in6),
1489
+ ppid,
1490
+ flags,
1491
+ stream,
1492
+ ttl,
1493
+ context
1494
+ );
1195
1495
  #endif
1196
1496
  }
1497
+ else{
1498
+ struct sockaddr_in addrs[MAX_IP_ADDRESSES];
1197
1499
 
1198
- size = sizeof(addrs);
1199
- }
1200
- else{
1201
- num_ip = 0;
1202
- size = 0;
1203
- }
1500
+ bzero(&addrs, sizeof(addrs));
1204
1501
 
1205
- fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1502
+ for(i = 0; i < num_ip; i++){
1503
+ v_address = RARRAY_AREF(v_addresses, i);
1504
+ parse_ip_address_v4(StringValueCStr(v_address), port, &addrs[i]);
1505
+ }
1206
1506
 
1207
1507
  #ifdef BSD
1208
- if(num_ip){
1209
- num_bytes = (ssize_t)sctp_sendmsgx(
1210
- fileno,
1211
- StringValueCStr(v_msg),
1212
- RSTRING_LEN(v_msg),
1213
- (struct sockaddr*)addrs,
1214
- num_ip,
1215
- ppid,
1216
- flags,
1217
- stream,
1218
- ttl,
1219
- context
1220
- );
1508
+ num_bytes = (ssize_t)sctp_sendmsgx(
1509
+ fileno,
1510
+ StringValueCStr(v_msg),
1511
+ RSTRING_LEN(v_msg),
1512
+ (struct sockaddr*)addrs,
1513
+ num_ip,
1514
+ ppid,
1515
+ flags,
1516
+ stream,
1517
+ ttl,
1518
+ context
1519
+ );
1520
+ #else
1521
+ num_bytes = (ssize_t)sctp_sendmsg(
1522
+ fileno,
1523
+ StringValueCStr(v_msg),
1524
+ RSTRING_LEN(v_msg),
1525
+ (struct sockaddr*)addrs,
1526
+ num_ip * sizeof(struct sockaddr_in),
1527
+ ppid,
1528
+ flags,
1529
+ stream,
1530
+ ttl,
1531
+ context
1532
+ );
1533
+ #endif
1534
+ }
1221
1535
  }
1222
1536
  else{
1537
+ // No addresses - use empty addrs
1538
+ num_ip = 0;
1223
1539
  num_bytes = (ssize_t)sctp_sendmsg(
1224
1540
  fileno,
1225
1541
  StringValueCStr(v_msg),
1226
1542
  RSTRING_LEN(v_msg),
1227
- (struct sockaddr*)addrs,
1228
- size,
1543
+ NULL,
1544
+ 0,
1229
1545
  ppid,
1230
1546
  flags,
1231
1547
  stream,
@@ -1233,20 +1549,6 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1233
1549
  context
1234
1550
  );
1235
1551
  }
1236
- #else
1237
- num_bytes = (ssize_t)sctp_sendmsg(
1238
- fileno,
1239
- StringValueCStr(v_msg),
1240
- RSTRING_LEN(v_msg),
1241
- (struct sockaddr*)addrs,
1242
- size,
1243
- ppid,
1244
- flags,
1245
- stream,
1246
- ttl,
1247
- context
1248
- );
1249
- #endif
1250
1552
 
1251
1553
  if(num_bytes < 0){
1252
1554
  #ifdef BSD
@@ -1264,10 +1566,13 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1264
1566
 
1265
1567
  /*
1266
1568
  * call-seq:
1267
- * SCTP::Socket#recvmsg(flags=0)
1569
+ * SCTP::Socket#recvmsg(flags=0, buffer_size=1024)
1268
1570
  *
1269
1571
  * Receive a message from another SCTP endpoint.
1270
1572
  *
1573
+ * The optional buffer_size parameter specifies the size of the receive buffer
1574
+ * in bytes. Defaults to 1024 bytes if not specified.
1575
+ *
1271
1576
  * Example:
1272
1577
  *
1273
1578
  * begin
@@ -1279,46 +1584,66 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
1279
1584
  * while true
1280
1585
  * info = socket.recvmsg
1281
1586
  * puts "Received message: #{info.message}"
1587
+ *
1588
+ * # Or with custom buffer size
1589
+ * info = socket.recvmsg(0, 4096)
1590
+ * puts "Received message: #{info.message}"
1282
1591
  * end
1283
1592
  * ensure
1284
1593
  * socket.close
1285
1594
  * end
1286
1595
  */
1287
1596
  static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1288
- VALUE v_flags, v_notification, v_message;
1597
+ VALUE v_flags, v_buffer_size, v_notification, v_message;
1289
1598
  struct sctp_sndrcvinfo sndrcvinfo;
1290
1599
  struct sockaddr_in clientaddr;
1291
- int flags, fileno;
1600
+ int flags, fileno, buffer_size;
1292
1601
  ssize_t bytes;
1293
- char buffer[1024]; // TODO: Let this be configurable?
1602
+ char *buffer;
1294
1603
  socklen_t length;
1295
1604
 
1296
- rb_scan_args(argc, argv, "01", &v_flags);
1605
+ rb_scan_args(argc, argv, "02", &v_flags, &v_buffer_size);
1297
1606
 
1298
1607
  if(NIL_P(v_flags))
1299
1608
  flags = 0;
1300
1609
  else
1301
1610
  flags = NUM2INT(v_flags);
1302
1611
 
1612
+ if(NIL_P(v_buffer_size))
1613
+ buffer_size = 1024;
1614
+ else
1615
+ buffer_size = NUM2INT(v_buffer_size);
1616
+
1617
+ if(buffer_size <= 0)
1618
+ rb_raise(rb_eArgError, "buffer size must be positive");
1619
+
1620
+ buffer = (char*)malloc(buffer_size);
1621
+ if(buffer == NULL)
1622
+ rb_raise(rb_eNoMemError, "failed to allocate buffer");
1623
+
1624
+ CHECK_SOCKET_CLOSED(self);
1625
+
1303
1626
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1304
1627
  length = sizeof(struct sockaddr_in);
1305
1628
 
1306
- bzero(buffer, sizeof(buffer));
1629
+ bzero(buffer, buffer_size);
1307
1630
  bzero(&clientaddr, sizeof(clientaddr));
1308
1631
  bzero(&sndrcvinfo, sizeof(sndrcvinfo));
1309
1632
 
1310
1633
  bytes = (ssize_t)sctp_recvmsg(
1311
1634
  fileno,
1312
1635
  buffer,
1313
- sizeof(buffer),
1636
+ buffer_size,
1314
1637
  (struct sockaddr*)&clientaddr,
1315
1638
  &length,
1316
1639
  &sndrcvinfo,
1317
1640
  &flags
1318
1641
  );
1319
1642
 
1320
- if(bytes < 0)
1643
+ if(bytes < 0){
1644
+ free(buffer);
1321
1645
  rb_raise(rb_eSystemCallError, "sctp_recvmsg: %s", strerror(errno));
1646
+ }
1322
1647
 
1323
1648
  v_notification = Qnil;
1324
1649
 
@@ -1330,6 +1655,8 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
1330
1655
  else
1331
1656
  v_message = Qnil;
1332
1657
 
1658
+ free(buffer);
1659
+
1333
1660
  return rb_struct_new(v_sndrcv_struct,
1334
1661
  v_message,
1335
1662
  UINT2NUM(sndrcvinfo.sinfo_stream),
@@ -1370,6 +1697,8 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
1370
1697
 
1371
1698
  bzero(&initmsg, sizeof(initmsg));
1372
1699
 
1700
+ CHECK_SOCKET_CLOSED(self);
1701
+
1373
1702
  v_output = rb_hash_aref2(v_options, "output_streams");
1374
1703
  v_input = rb_hash_aref2(v_options, "input_streams");
1375
1704
  v_attempts = rb_hash_aref2(v_options, "max_attempts");
@@ -1440,6 +1769,8 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
1440
1769
  bzero(&events, sizeof(events));
1441
1770
  Check_Type(v_options, T_HASH);
1442
1771
 
1772
+ CHECK_SOCKET_CLOSED(self);
1773
+
1443
1774
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1444
1775
 
1445
1776
  if(RTEST(rb_hash_aref2(v_options, "data_io")))
@@ -1520,6 +1851,8 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
1520
1851
  if(backlog > SOMAXCONN)
1521
1852
  rb_raise(rb_eArgError, "backlog value exceeds maximum value of: %i", SOMAXCONN);
1522
1853
 
1854
+ CHECK_SOCKET_CLOSED(self);
1855
+
1523
1856
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1524
1857
 
1525
1858
  if(listen(fileno, backlog) < 0)
@@ -1550,6 +1883,8 @@ static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
1550
1883
  int fileno, assoc_fileno;
1551
1884
  sctp_assoc_t assoc_id;
1552
1885
 
1886
+ CHECK_SOCKET_CLOSED(self);
1887
+
1553
1888
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1554
1889
  assoc_id = NUM2INT(v_assoc_id);
1555
1890
 
@@ -1587,6 +1922,8 @@ static VALUE rsctp_get_default_send_params(VALUE self){
1587
1922
 
1588
1923
  bzero(&sndrcv, sizeof(sndrcv));
1589
1924
 
1925
+ CHECK_SOCKET_CLOSED(self);
1926
+
1590
1927
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1591
1928
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1592
1929
  size = sizeof(struct sctp_sndrcvinfo);
@@ -1632,6 +1969,8 @@ static VALUE rsctp_get_association_info(VALUE self){
1632
1969
 
1633
1970
  bzero(&assoc, sizeof(assoc));
1634
1971
 
1972
+ CHECK_SOCKET_CLOSED(self);
1973
+
1635
1974
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1636
1975
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1637
1976
  size = sizeof(struct sctp_assocparams);
@@ -1674,6 +2013,8 @@ static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
1674
2013
 
1675
2014
  bzero(&assoc, sizeof(assoc));
1676
2015
 
2016
+ CHECK_SOCKET_CLOSED(self);
2017
+
1677
2018
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1678
2019
 
1679
2020
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
@@ -1738,6 +2079,8 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
1738
2079
  int how, fileno;
1739
2080
  VALUE v_how;
1740
2081
 
2082
+ CHECK_SOCKET_CLOSED(self);
2083
+
1741
2084
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1742
2085
 
1743
2086
  rb_scan_args(argc, argv, "01", &v_how);
@@ -1777,6 +2120,8 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
1777
2120
 
1778
2121
  bzero(&rto, sizeof(rto));
1779
2122
 
2123
+ CHECK_SOCKET_CLOSED(self);
2124
+
1780
2125
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1781
2126
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1782
2127
  size = sizeof(struct sctp_rtoinfo);
@@ -1816,6 +2161,8 @@ static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
1816
2161
 
1817
2162
  bzero(&rto, sizeof(rto));
1818
2163
 
2164
+ CHECK_SOCKET_CLOSED(self);
2165
+
1819
2166
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1820
2167
 
1821
2168
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
@@ -1881,10 +2228,12 @@ static VALUE rsctp_get_status(VALUE self){
1881
2228
  sctp_assoc_t assoc_id;
1882
2229
  struct sctp_status status;
1883
2230
  struct sctp_paddrinfo* spinfo;
1884
- char tmpname[INET_ADDRSTRLEN];
2231
+ char tmpname[INET6_ADDRSTRLEN];
1885
2232
 
1886
2233
  bzero(&status, sizeof(status));
1887
2234
 
2235
+ CHECK_SOCKET_CLOSED(self);
2236
+
1888
2237
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1889
2238
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1890
2239
  size = sizeof(struct sctp_status);
@@ -1949,6 +2298,8 @@ static VALUE rsctp_get_subscriptions(VALUE self){
1949
2298
 
1950
2299
  bzero(&events, sizeof(events));
1951
2300
 
2301
+ CHECK_SOCKET_CLOSED(self);
2302
+
1952
2303
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
1953
2304
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
1954
2305
  size = sizeof(struct sctp_event_subscribe);
@@ -2014,6 +2365,8 @@ static VALUE rsctp_get_peer_address_params(VALUE self){
2014
2365
  bzero(&paddr, sizeof(paddr));
2015
2366
  bzero(&str, sizeof(str));
2016
2367
 
2368
+ CHECK_SOCKET_CLOSED(self);
2369
+
2017
2370
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2018
2371
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2019
2372
  size = sizeof(struct sctp_paddrparams);
@@ -2021,7 +2374,18 @@ static VALUE rsctp_get_peer_address_params(VALUE self){
2021
2374
  if(sctp_opt_info(fileno, assoc_id, SCTP_PEER_ADDR_PARAMS, (void*)&paddr, &size) < 0)
2022
2375
  rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2023
2376
 
2024
- inet_ntop(AF_INET, ((struct sockaddr_in*)&paddr.spp_address), str, sizeof(str));
2377
+ {
2378
+ struct sockaddr* sa = (struct sockaddr*)&paddr.spp_address;
2379
+
2380
+ if(sa->sa_family == AF_INET6){
2381
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
2382
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str));
2383
+ }
2384
+ else{
2385
+ struct sockaddr_in* sin = (struct sockaddr_in*)sa;
2386
+ inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str));
2387
+ }
2388
+ }
2025
2389
 
2026
2390
  return rb_struct_new(
2027
2391
  v_sctp_peer_addr_params_struct,
@@ -2061,6 +2425,8 @@ static VALUE rsctp_get_init_msg(VALUE self){
2061
2425
 
2062
2426
  bzero(&initmsg, sizeof(initmsg));
2063
2427
 
2428
+ CHECK_SOCKET_CLOSED(self);
2429
+
2064
2430
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2065
2431
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2066
2432
  size = sizeof(struct sctp_initmsg);
@@ -2089,6 +2455,8 @@ static VALUE rsctp_get_nodelay(VALUE self){
2089
2455
  sctp_assoc_t assoc_id;
2090
2456
  int value;
2091
2457
 
2458
+ CHECK_SOCKET_CLOSED(self);
2459
+
2092
2460
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2093
2461
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2094
2462
  size = sizeof(int);
@@ -2115,6 +2483,8 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
2115
2483
  socklen_t size;
2116
2484
  int value;
2117
2485
 
2486
+ CHECK_SOCKET_CLOSED(self);
2487
+
2118
2488
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2119
2489
  size = sizeof(int);
2120
2490
 
@@ -2148,6 +2518,8 @@ static VALUE rsctp_disable_fragments(VALUE self, VALUE v_bool){
2148
2518
  sctp_assoc_t assoc_id;
2149
2519
  int value;
2150
2520
 
2521
+ CHECK_SOCKET_CLOSED(self);
2522
+
2151
2523
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2152
2524
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2153
2525
  size = sizeof(int);
@@ -2179,6 +2551,8 @@ static VALUE rsctp_get_autoclose(VALUE self){
2179
2551
  sctp_assoc_t assoc_id;
2180
2552
  int value;
2181
2553
 
2554
+ CHECK_SOCKET_CLOSED(self);
2555
+
2182
2556
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2183
2557
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
2184
2558
  size = sizeof(int);
@@ -2215,6 +2589,8 @@ static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
2215
2589
  int fileno;
2216
2590
  int value;
2217
2591
 
2592
+ CHECK_SOCKET_CLOSED(self);
2593
+
2218
2594
  value = NUM2INT(v_seconds);
2219
2595
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2220
2596
 
@@ -2239,6 +2615,8 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2239
2615
 
2240
2616
  rb_scan_args(argc, argv, "01", &v_assoc_id);
2241
2617
 
2618
+ CHECK_SOCKET_CLOSED(self);
2619
+
2242
2620
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2243
2621
  size = sizeof(struct sctp_assoc_value);
2244
2622
 
@@ -2250,8 +2628,8 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
2250
2628
  assoc_value.assoc_id = assoc_id;
2251
2629
  assoc_value.assoc_value = 1;
2252
2630
 
2253
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
2254
- rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2631
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, size) < 0)
2632
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2255
2633
 
2256
2634
  return self;
2257
2635
  }
@@ -2295,7 +2673,7 @@ static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
2295
2673
 
2296
2674
  /*
2297
2675
  * call-seq:
2298
- * SCTP::Socket#set_shared_key(key, keynum, association_id=nil)
2676
+ * SCTP::Socket#set_shared_key(key, keynum=1, association_id=nil)
2299
2677
  *
2300
2678
  * This option will set a shared secret key which is used to build an
2301
2679
  * association shared key.
@@ -2324,25 +2702,18 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2324
2702
  size_t len;
2325
2703
  char* key;
2326
2704
  uint keynum;
2327
- socklen_t size;
2705
+ size_t size;
2328
2706
  sctp_assoc_t assoc_id;
2329
2707
  struct sctp_authkey* auth_key;
2330
2708
  VALUE v_key, v_keynumber, v_assoc_id;
2331
2709
 
2332
2710
  rb_scan_args(argc, argv, "12", &v_key, &v_keynumber, &v_assoc_id);
2333
2711
 
2712
+ CHECK_SOCKET_CLOSED(self);
2713
+
2334
2714
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2335
2715
  key = StringValuePtr(v_key);
2336
- len = strlen(key);
2337
- unsigned char byte_array[len+1];
2338
-
2339
- for(size_t i = 0; i < len; i++)
2340
- byte_array[i] = key[i];
2341
-
2342
- byte_array[len] = '\0';
2343
-
2344
- auth_key = malloc(sizeof(auth_key) + sizeof(char[strlen(key)+1]));
2345
- size = sizeof(auth_key);
2716
+ len = RSTRING_LEN(v_key); // Use Ruby's string length, not strlen
2346
2717
 
2347
2718
  if(NIL_P(v_assoc_id))
2348
2719
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
@@ -2354,14 +2725,25 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
2354
2725
  else
2355
2726
  keynum = NUM2INT(v_keynumber);
2356
2727
 
2728
+ // Allocate the structure with space for the key
2729
+ size = sizeof(struct sctp_authkey) + len;
2730
+ auth_key = malloc(size);
2731
+
2732
+ if (auth_key == NULL)
2733
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for auth key");
2734
+
2357
2735
  auth_key->sca_assoc_id = assoc_id;
2358
2736
  auth_key->sca_keynumber = keynum;
2359
- auth_key->sca_keylength = strlen(key);
2360
- memcpy(auth_key->sca_key, byte_array, sizeof(byte_array));
2737
+ auth_key->sca_keylength = len;
2738
+ memcpy(auth_key->sca_key, key, len);
2361
2739
 
2362
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_KEY, (void*)auth_key, &size) < 0)
2363
- rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2740
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_KEY, (void*)auth_key, size) < 0) {
2741
+ int err = errno;
2742
+ free(auth_key);
2743
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(err));
2744
+ }
2364
2745
 
2746
+ free(auth_key);
2365
2747
  return self;
2366
2748
  }
2367
2749
 
@@ -2377,14 +2759,21 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2377
2759
  struct sctp_authkeyid authkey;
2378
2760
  sctp_assoc_t assoc_id;
2379
2761
  VALUE v_assoc_id, v_keynum;
2380
- uint keynum;
2762
+ int keynum;
2381
2763
 
2382
2764
  rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2383
2765
 
2766
+ CHECK_SOCKET_CLOSED(self);
2767
+
2384
2768
  bzero(&authkey, sizeof(authkey));
2385
2769
 
2770
+ // Cast it later, we want to force a validity check.
2771
+ keynum = FIX2INT(v_keynum);
2772
+
2773
+ if(keynum < 0)
2774
+ rb_raise(rb_eArgError, "invalid keynum value");
2775
+
2386
2776
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2387
- keynum = NUM2UINT(v_keynum);
2388
2777
 
2389
2778
  if(NIL_P(v_assoc_id))
2390
2779
  assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
@@ -2392,7 +2781,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2392
2781
  assoc_id = NUM2INT(v_assoc_id);
2393
2782
 
2394
2783
  authkey.scact_assoc_id = assoc_id;
2395
- authkey.scact_keynumber = keynum;
2784
+ authkey.scact_keynumber = (uint)keynum;
2396
2785
 
2397
2786
  size = sizeof(struct sctp_authkeyid);
2398
2787
 
@@ -2413,7 +2802,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
2413
2802
  * authenticated chunks. The key identifier MUST correspond to an existing
2414
2803
  * shared key. Note that shared key identifier '0' defaults to a null key.
2415
2804
  *
2416
- * The association_idparameter, if non-zero, indicates what association that
2805
+ * The association_id parameter, if non-zero, indicates what association that
2417
2806
  * the shared key identifier is being set active upon. If this element contains
2418
2807
  * zero, then the activation applies to the endpoint and all future
2419
2808
  * associations will use the specified shared key identifier.
@@ -2430,11 +2819,17 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2430
2819
  struct sctp_authkeyid authkey;
2431
2820
  sctp_assoc_t assoc_id;
2432
2821
  VALUE v_assoc_id, v_keynum;
2433
- uint keynum;
2822
+ int keynum;
2434
2823
 
2435
2824
  rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2436
2825
 
2437
- keynum = NUM2UINT(v_keynum);
2826
+ CHECK_SOCKET_CLOSED(self);
2827
+
2828
+ keynum = FIX2INT(v_keynum);
2829
+
2830
+ if(keynum < 0)
2831
+ rb_raise(rb_eArgError, "invalid keynum value");
2832
+
2438
2833
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2439
2834
 
2440
2835
  if(NIL_P(v_assoc_id))
@@ -2443,11 +2838,11 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
2443
2838
  assoc_id = NUM2INT(v_assoc_id);
2444
2839
 
2445
2840
  authkey.scact_assoc_id = assoc_id;
2446
- authkey.scact_keynumber = keynum;
2841
+ authkey.scact_keynumber = (uint)keynum;
2447
2842
  size = sizeof(struct sctp_authkeyid);
2448
2843
 
2449
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, &size) < 0)
2450
- rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2844
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, size) < 0)
2845
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2451
2846
 
2452
2847
  return self;
2453
2848
  }
@@ -2487,6 +2882,8 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2487
2882
 
2488
2883
  rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
2489
2884
 
2885
+ CHECK_SOCKET_CLOSED(self);
2886
+
2490
2887
  bzero(&authkey, sizeof(authkey));
2491
2888
 
2492
2889
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
@@ -2502,8 +2899,8 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2502
2899
 
2503
2900
  size = sizeof(struct sctp_authkeyid);
2504
2901
 
2505
- if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_DELETE_KEY, (void*)&authkey, &size) < 0)
2506
- rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
2902
+ if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, (void*)&authkey, size) < 0)
2903
+ rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
2507
2904
 
2508
2905
  return INT2NUM(authkey.scact_keynumber);
2509
2906
  }
@@ -2512,14 +2909,20 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
2512
2909
  * call-seq:
2513
2910
  * SCTP::Socket#map_ipv4=(bool)
2514
2911
  *
2515
- * If set to true and the socket is type PF_INET6, then IPv4 addresses will be
2912
+ * If set to true and the socket is type xF_INET6, then IPv4 addresses will be
2516
2913
  * mapped to V6 representation. If set to false (the default), then no mapping
2517
- * will be done of V4 addresses and a user will receive both PF_INET6 and
2518
- * PF_INET type addresses on the socket.
2914
+ * will be done of V4 addresses and a user will receive both xF_INET6 and
2915
+ * xF_INET type addresses on the socket.
2916
+ *
2917
+ * Note that setting this to true on a socket that is not type xF_INET6 is
2918
+ * undefined behavior, and may raise an error on your platform. Otherwise it's
2919
+ * a no-op.
2519
2920
  */
2520
2921
  static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
2521
2922
  int fileno, boolean;
2522
2923
 
2924
+ CHECK_SOCKET_CLOSED(self);
2925
+
2523
2926
  boolean = 0;
2524
2927
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2525
2928
 
@@ -2594,6 +2997,8 @@ static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2594
2997
 
2595
2998
  bzero(&sndrcv, sizeof(sndrcv));
2596
2999
 
3000
+ CHECK_SOCKET_CLOSED(self);
3001
+
2597
3002
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
2598
3003
 
2599
3004
  v_stream = rb_hash_aref2(v_options, "stream");
@@ -2677,17 +3082,19 @@ static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
2677
3082
  */
2678
3083
  static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
2679
3084
  VALUE v_assoc_id, v_address, v_hbinterval, v_pathmaxrxt, v_pathmtu, v_flags, v_ipv6_flowlabel;
2680
- int fileno;
3085
+ int fileno, domain;
2681
3086
  sctp_assoc_t assoc_id;
2682
3087
  struct sctp_paddrparams paddr;
2683
- struct sockaddr_in* sin;
2684
3088
 
2685
3089
  if(!RB_TYPE_P(v_options, T_HASH))
2686
3090
  rb_raise(rb_eTypeError, "options must be a hash");
2687
3091
 
2688
3092
  bzero(&paddr, sizeof(paddr));
2689
3093
 
3094
+ CHECK_SOCKET_CLOSED(self);
3095
+
2690
3096
  fileno = NUM2INT(rb_iv_get(self, "@fileno"));
3097
+ domain = NUM2INT(rb_iv_get(self, "@domain"));
2691
3098
 
2692
3099
  v_assoc_id = rb_hash_aref2(v_options, "association_id");
2693
3100
  v_address = rb_hash_aref2(v_options, "address");
@@ -2703,12 +3110,28 @@ static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
2703
3110
  assoc_id = NUM2INT(v_assoc_id);
2704
3111
  paddr.spp_assoc_id = assoc_id;
2705
3112
 
2706
- // If address is provided, set up the sockaddr structure
3113
+ // If address is provided, set up the sockaddr structure based on domain
2707
3114
  if(!NIL_P(v_address)){
2708
- sin = (struct sockaddr_in*)&paddr.spp_address;
2709
- sin->sin_family = AF_INET;
2710
- if(inet_pton(AF_INET, StringValueCStr(v_address), &sin->sin_addr) <= 0)
2711
- rb_raise(rb_eArgError, "invalid IP address");
3115
+ const char* addr_str = StringValueCStr(v_address);
3116
+
3117
+ if(domain == AF_INET6){
3118
+ struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&paddr.spp_address;
3119
+ sin6->sin6_family = AF_INET6;
3120
+ if(inet_pton(AF_INET6, addr_str, &sin6->sin6_addr) <= 0)
3121
+ rb_raise(rb_eArgError, "invalid IPv6 address: %s", addr_str);
3122
+ #ifdef BSD
3123
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
3124
+ #endif
3125
+ }
3126
+ else{
3127
+ struct sockaddr_in* sin = (struct sockaddr_in*)&paddr.spp_address;
3128
+ sin->sin_family = AF_INET;
3129
+ if(inet_pton(AF_INET, addr_str, &sin->sin_addr) <= 0)
3130
+ rb_raise(rb_eArgError, "invalid IPv4 address: %s", addr_str);
3131
+ #ifdef BSD
3132
+ sin->sin_len = sizeof(struct sockaddr_in);
3133
+ #endif
3134
+ }
2712
3135
  }
2713
3136
 
2714
3137
  if(!NIL_P(v_hbinterval))
@@ -2826,7 +3249,7 @@ void Init_socket(void){
2826
3249
 
2827
3250
  v_sctp_receive_info_struct = rb_struct_define(
2828
3251
  "ReceiveInfo", "message", "sid", "ssn", "flags", "ppid", "tsn",
2829
- "cumtsn", "context", "assocation_id", NULL
3252
+ "cumtsn", "context", "association_id", NULL
2830
3253
  );
2831
3254
 
2832
3255
  v_sctp_peer_addr_params_struct = rb_struct_define(
@@ -2899,8 +3322,8 @@ void Init_socket(void){
2899
3322
  rb_define_attr(cSocket, "association_id", 1, 1);
2900
3323
  rb_define_attr(cSocket, "port", 1, 1);
2901
3324
 
2902
- /* 0.1.4: The version of this library */
2903
- rb_define_const(cSocket, "VERSION", rb_str_new2("0.2.0"));
3325
+ /* 0.2.2: The version of this library */
3326
+ rb_define_const(cSocket, "VERSION", rb_str_new2("0.2.2"));
2904
3327
 
2905
3328
  /* send flags */
2906
3329