sctp-socket 0.1.3 → 0.2.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ruby.yml +1 -1
- data/.gitignore +1 -0
- data/CHANGES.md +18 -0
- data/README.md +75 -0
- data/examples/client_for_server_test.rb +34 -0
- data/examples/sctp_server_example.rb +69 -0
- data/examples/server_using_sctp_server.rb +65 -0
- data/ext/sctp/socket.c +593 -67
- data/lib/sctp/server.rb +207 -0
- data/sctp-socket.gemspec +1 -1
- data.tar.gz.sig +0 -0
- metadata +6 -5
- metadata.gz.sig +0 -0
- data/ext/sctp/socket/client.c +0 -7
- data/ext/sctp/socket/server.c +0 -7
- data/ext/sctp/socket.h +0 -18
data/ext/sctp/socket.c
CHANGED
@@ -39,14 +39,57 @@ VALUE v_sctp_initmsg_struct;
|
|
39
39
|
#endif
|
40
40
|
#endif
|
41
41
|
|
42
|
-
//
|
42
|
+
// Memory safety and error handling macros
|
43
|
+
#define CHECK_FILENO_VALID(fileno) do { \
|
44
|
+
if ((fileno) < 0) { \
|
45
|
+
rb_raise(rb_eSystemCallError, "invalid file descriptor"); \
|
46
|
+
} \
|
47
|
+
} while(0)
|
48
|
+
|
49
|
+
#define SAFE_FREE(ptr) do { \
|
50
|
+
if ((ptr) != NULL) { \
|
51
|
+
free(ptr); \
|
52
|
+
(ptr) = NULL; \
|
53
|
+
} \
|
54
|
+
} while(0)
|
55
|
+
|
56
|
+
#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
|
+
rb_raise(rb_eIOError, "socket is closed"); \
|
60
|
+
} \
|
61
|
+
} while(0)
|
62
|
+
|
63
|
+
#define MAX_IP_ADDRESSES 8
|
64
|
+
#define DEFAULT_BUFFER_SIZE 1024
|
65
|
+
#define IP_BUFFER_SIZE INET6_ADDRSTRLEN
|
66
|
+
|
67
|
+
/*
|
68
|
+
* Convert a sockaddr_in structure to a Ruby struct.
|
69
|
+
* Handles both IPv4 and IPv6 addresses properly.
|
70
|
+
*
|
71
|
+
* @param addr Pointer to sockaddr_in structure
|
72
|
+
* @return Ruby struct representing the socket address
|
73
|
+
*/
|
43
74
|
VALUE convert_sockaddr_in_to_struct(struct sockaddr_in* addr){
|
44
|
-
char ipbuf[
|
75
|
+
char ipbuf[IP_BUFFER_SIZE];
|
76
|
+
const char* result;
|
77
|
+
|
78
|
+
if(addr == NULL)
|
79
|
+
rb_raise(rb_eArgError, "null address pointer");
|
80
|
+
|
81
|
+
if((addr->sin_family != AF_INET) && (addr->sin_family != AF_INET6))
|
82
|
+
rb_raise(rb_eArgError, "unsupported address family");
|
83
|
+
|
84
|
+
bzero(ipbuf, sizeof(ipbuf));
|
45
85
|
|
46
86
|
if(addr->sin_family == AF_INET6)
|
47
|
-
inet_ntop(addr->sin_family, &(((struct sockaddr_in6 *)addr)->sin6_addr), ipbuf, sizeof(ipbuf));
|
87
|
+
result = inet_ntop(addr->sin_family, &(((struct sockaddr_in6 *)addr)->sin6_addr), ipbuf, sizeof(ipbuf));
|
48
88
|
else
|
49
|
-
inet_ntop(addr->sin_family, &(((struct sockaddr_in *)addr)->sin_addr), ipbuf, sizeof(ipbuf));
|
89
|
+
result = inet_ntop(addr->sin_family, &(((struct sockaddr_in *)addr)->sin_addr), ipbuf, sizeof(ipbuf));
|
90
|
+
|
91
|
+
if(result == NULL)
|
92
|
+
rb_raise(rb_eSystemCallError, "inet_ntop: %s", strerror(errno));
|
50
93
|
|
51
94
|
return rb_struct_new(v_sockaddr_in_struct,
|
52
95
|
INT2NUM(addr->sin_family),
|
@@ -55,27 +98,49 @@ VALUE convert_sockaddr_in_to_struct(struct sockaddr_in* addr){
|
|
55
98
|
);
|
56
99
|
}
|
57
100
|
|
58
|
-
|
101
|
+
/*
|
102
|
+
* Helper function to get a hash value via string or symbol key.
|
103
|
+
* This provides Ruby's flexible hash access pattern.
|
104
|
+
*
|
105
|
+
* @param v_hash Ruby hash object
|
106
|
+
* @param key String key to look up
|
107
|
+
* @return Ruby value or Qnil if not found
|
108
|
+
*/
|
59
109
|
VALUE rb_hash_aref2(VALUE v_hash, const char* key){
|
60
110
|
VALUE v_key, v_val;
|
61
111
|
|
112
|
+
if(key == NULL)
|
113
|
+
return Qnil;
|
114
|
+
|
115
|
+
// Try a string key first
|
62
116
|
v_key = rb_str_new2(key);
|
63
117
|
v_val = rb_hash_aref(v_hash, v_key);
|
64
118
|
|
119
|
+
// If not found, try a symbol key
|
65
120
|
if(NIL_P(v_val))
|
66
121
|
v_val = rb_hash_aref(v_hash, ID2SYM(rb_intern(key)));
|
67
122
|
|
68
123
|
return v_val;
|
69
124
|
}
|
70
125
|
|
126
|
+
/*
|
127
|
+
* Parse and convert SCTP notification messages into Ruby structures.
|
128
|
+
* This function handles various types of SCTP notifications.
|
129
|
+
*
|
130
|
+
* @param buffer Raw notification buffer from SCTP
|
131
|
+
* @return Ruby struct representing the notification
|
132
|
+
*/
|
71
133
|
VALUE get_notification_info(char* buffer){
|
72
134
|
uint32_t i;
|
73
|
-
char str[
|
135
|
+
char str[IP_BUFFER_SIZE];
|
74
136
|
union sctp_notification* snp;
|
75
137
|
VALUE v_notification = Qnil;
|
76
138
|
VALUE v_str = Qnil;
|
77
139
|
VALUE* v_temp;
|
78
140
|
|
141
|
+
if(buffer == NULL)
|
142
|
+
rb_raise(rb_eArgError, "notification buffer is null");
|
143
|
+
|
79
144
|
snp = (union sctp_notification*)buffer;
|
80
145
|
|
81
146
|
switch(snp->sn_header.sn_type){
|
@@ -310,11 +375,24 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
310
375
|
|
311
376
|
rb_scan_args(argc, argv, "02", &v_domain, &v_type);
|
312
377
|
|
313
|
-
|
378
|
+
// Set defaults with validation
|
379
|
+
if(NIL_P(v_domain)){
|
314
380
|
v_domain = INT2NUM(AF_INET);
|
315
|
-
|
316
|
-
|
381
|
+
}
|
382
|
+
else{
|
383
|
+
int domain = NUM2INT(v_domain);
|
384
|
+
if((domain != AF_INET) && (domain != AF_INET6))
|
385
|
+
rb_raise(rb_eArgError, "unsupported domain family: %d", domain);
|
386
|
+
}
|
387
|
+
|
388
|
+
if(NIL_P(v_type)){
|
317
389
|
v_type = INT2NUM(SOCK_SEQPACKET);
|
390
|
+
}
|
391
|
+
else{
|
392
|
+
int type = NUM2INT(v_type);
|
393
|
+
if (type != SOCK_SEQPACKET && type != SOCK_STREAM)
|
394
|
+
rb_raise(rb_eArgError, "unsupported socket type: %d", type);
|
395
|
+
}
|
318
396
|
|
319
397
|
fileno = socket(NUM2INT(v_domain), NUM2INT(v_type), IPPROTO_SCTP);
|
320
398
|
|
@@ -373,7 +451,7 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
373
451
|
* Returns the port that it was bound to.
|
374
452
|
*/
|
375
453
|
static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
|
376
|
-
struct sockaddr_in addrs[
|
454
|
+
struct sockaddr_in addrs[MAX_IP_ADDRESSES];
|
377
455
|
int i, fileno, num_ip, flags, domain, port, on;
|
378
456
|
VALUE v_addresses, v_port, v_flags, v_address, v_reuse_addr, v_options;
|
379
457
|
|
@@ -404,7 +482,7 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
|
|
404
482
|
else
|
405
483
|
num_ip = (int)RARRAY_LEN(v_addresses);
|
406
484
|
|
407
|
-
if(num_ip >
|
485
|
+
if(num_ip > MAX_IP_ADDRESSES)
|
408
486
|
rb_raise(rb_eArgError, "too many IP addresses to bind, maximum is eight");
|
409
487
|
|
410
488
|
domain = NUM2INT(rb_iv_get(self, "@domain"));
|
@@ -472,7 +550,7 @@ static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
|
|
472
550
|
* methods will automatically establish associations.
|
473
551
|
*/
|
474
552
|
static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
|
475
|
-
struct sockaddr_in addrs[
|
553
|
+
struct sockaddr_in addrs[MAX_IP_ADDRESSES];
|
476
554
|
int i, num_ip, fileno;
|
477
555
|
sctp_assoc_t assoc;
|
478
556
|
VALUE v_address, v_domain, v_options, v_addresses, v_port;
|
@@ -540,7 +618,7 @@ static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
|
|
540
618
|
* socket.close(linger: 5)
|
541
619
|
*/
|
542
620
|
static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
|
543
|
-
VALUE v_options, v_linger;
|
621
|
+
VALUE v_options, v_linger, v_fileno;
|
544
622
|
int fileno;
|
545
623
|
|
546
624
|
rb_scan_args(argc, argv, "01", &v_options);
|
@@ -551,27 +629,56 @@ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
|
|
551
629
|
Check_Type(v_options, T_HASH);
|
552
630
|
|
553
631
|
v_linger = rb_hash_aref2(v_options, "linger");
|
632
|
+
v_fileno = rb_iv_get(self, "@fileno");
|
554
633
|
|
555
|
-
|
634
|
+
if(NIL_P(v_fileno)) // Already closed
|
635
|
+
return self;
|
636
|
+
|
637
|
+
fileno = NUM2INT(v_fileno);
|
556
638
|
|
557
639
|
if(!NIL_P(v_linger)){
|
558
640
|
struct linger lin;
|
641
|
+
int linger_time = NUM2INT(v_linger);
|
642
|
+
|
643
|
+
if(linger_time < 0)
|
644
|
+
rb_raise(rb_eArgError, "linger time must be non-negative");
|
645
|
+
|
559
646
|
lin.l_onoff = 1;
|
560
|
-
lin.l_linger =
|
647
|
+
lin.l_linger = linger_time;
|
561
648
|
|
562
649
|
if(setsockopt(fileno, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0)
|
563
650
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
564
651
|
}
|
565
652
|
|
566
|
-
if(close(fileno))
|
653
|
+
if(close(fileno) < 0)
|
567
654
|
rb_raise(rb_eSystemCallError, "close: %s", strerror(errno));
|
568
655
|
|
656
|
+
// Mark socket as closed
|
657
|
+
rb_iv_set(self, "@fileno", Qnil);
|
658
|
+
|
569
659
|
return self;
|
570
660
|
}
|
571
661
|
|
572
662
|
/*
|
573
663
|
* call-seq:
|
574
|
-
* SCTP::Socket#
|
664
|
+
* SCTP::Socket#closed?
|
665
|
+
*
|
666
|
+
* Returns true if the socket is closed, false otherwise.
|
667
|
+
*
|
668
|
+
* Example:
|
669
|
+
* socket = SCTP::Socket.new
|
670
|
+
* socket.closed? # => false
|
671
|
+
* socket.close
|
672
|
+
* socket.closed? # => true
|
673
|
+
*/
|
674
|
+
static VALUE rsctp_closed_p(VALUE self){
|
675
|
+
VALUE v_fileno = rb_iv_get(self, "@fileno");
|
676
|
+
return NIL_P(v_fileno) ? Qtrue : Qfalse;
|
677
|
+
}
|
678
|
+
|
679
|
+
/*
|
680
|
+
* call-seq:
|
681
|
+
* SCTP::Socket#getpeernames
|
575
682
|
*
|
576
683
|
* Return an array of all addresses of a peer of the current socket
|
577
684
|
* and association number.
|
@@ -584,7 +691,7 @@ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
|
|
584
691
|
* socket = SCTP::Socket.new
|
585
692
|
* # ...
|
586
693
|
* p socket.getpeernames
|
587
|
-
*
|
694
|
+
*
|
588
695
|
* info = socket.recvmsg
|
589
696
|
* association_fileno = socket.peeloff(info.association_id)
|
590
697
|
*
|
@@ -592,20 +699,22 @@ static VALUE rsctp_close(int argc, VALUE* argv, VALUE self){
|
|
592
699
|
*/
|
593
700
|
static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
|
594
701
|
sctp_assoc_t assoc_id;
|
595
|
-
struct sockaddr* addrs;
|
702
|
+
struct sockaddr* addrs = NULL;
|
596
703
|
int i, fileno, num_addrs;
|
597
|
-
char str[
|
704
|
+
char str[IP_BUFFER_SIZE];
|
598
705
|
VALUE v_fileno, v_association_id;
|
599
706
|
VALUE v_array = rb_ary_new();
|
600
707
|
|
601
|
-
bzero(&addrs, sizeof(addrs));
|
602
|
-
|
603
708
|
rb_scan_args(argc, argv, "02", &v_fileno, &v_association_id);
|
604
709
|
|
605
|
-
if(NIL_P(v_fileno))
|
710
|
+
if(NIL_P(v_fileno)){
|
711
|
+
CHECK_SOCKET_CLOSED(self);
|
606
712
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
607
|
-
|
713
|
+
}
|
714
|
+
else{
|
608
715
|
fileno = NUM2INT(v_fileno);
|
716
|
+
CHECK_FILENO_VALID(fileno);
|
717
|
+
}
|
609
718
|
|
610
719
|
if(NIL_P(v_association_id))
|
611
720
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
@@ -615,14 +724,16 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
|
|
615
724
|
num_addrs = sctp_getpaddrs(fileno, assoc_id, &addrs);
|
616
725
|
|
617
726
|
if(num_addrs < 0){
|
618
|
-
|
727
|
+
if(addrs != NULL)
|
728
|
+
sctp_freepaddrs(addrs);
|
729
|
+
|
619
730
|
rb_raise(rb_eSystemCallError, "sctp_getpaddrs: %s", strerror(errno));
|
620
731
|
}
|
621
732
|
|
622
733
|
for(i = 0; i < num_addrs; i++){
|
734
|
+
bzero(&str, sizeof(str));
|
623
735
|
inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
|
624
736
|
rb_ary_push(v_array, rb_str_new2(str));
|
625
|
-
bzero(&str, sizeof(str));
|
626
737
|
}
|
627
738
|
|
628
739
|
sctp_freepaddrs(addrs);
|
@@ -649,20 +760,22 @@ static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
|
|
649
760
|
*/
|
650
761
|
static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
|
651
762
|
sctp_assoc_t assoc_id;
|
652
|
-
struct sockaddr* addrs;
|
763
|
+
struct sockaddr* addrs = NULL;
|
653
764
|
int i, fileno, num_addrs;
|
654
|
-
char str[
|
765
|
+
char str[IP_BUFFER_SIZE];
|
655
766
|
VALUE v_assoc_fileno, v_assoc_id;
|
656
767
|
VALUE v_array = rb_ary_new();
|
657
768
|
|
658
|
-
bzero(&addrs, sizeof(addrs));
|
659
|
-
|
660
769
|
rb_scan_args(argc, argv, "02", &v_assoc_fileno, &v_assoc_id);
|
661
770
|
|
662
|
-
if(NIL_P(v_assoc_fileno))
|
771
|
+
if(NIL_P(v_assoc_fileno)){
|
772
|
+
CHECK_SOCKET_CLOSED(self);
|
663
773
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
664
|
-
|
774
|
+
}
|
775
|
+
else{
|
665
776
|
fileno = NUM2INT(v_assoc_fileno);
|
777
|
+
CHECK_FILENO_VALID(fileno);
|
778
|
+
}
|
666
779
|
|
667
780
|
if(NIL_P(v_assoc_id))
|
668
781
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
@@ -672,14 +785,16 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
|
|
672
785
|
num_addrs = sctp_getladdrs(fileno, assoc_id, &addrs);
|
673
786
|
|
674
787
|
if(num_addrs < 0){
|
675
|
-
|
788
|
+
if(addrs != NULL)
|
789
|
+
sctp_freeladdrs(addrs);
|
790
|
+
|
676
791
|
rb_raise(rb_eSystemCallError, "sctp_getladdrs: %s", strerror(errno));
|
677
792
|
}
|
678
793
|
|
679
794
|
for(i = 0; i < num_addrs; i++){
|
795
|
+
bzero(&str, sizeof(str));
|
680
796
|
inet_ntop(AF_INET, &(((struct sockaddr_in *)&addrs[i])->sin_addr), str, sizeof(str));
|
681
797
|
rb_ary_push(v_array, rb_str_new2(str));
|
682
|
-
bzero(&str, sizeof(str));
|
683
798
|
}
|
684
799
|
|
685
800
|
sctp_freeladdrs(addrs);
|
@@ -704,11 +819,11 @@ static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
|
|
704
819
|
* socket = SCTP::Socket.new
|
705
820
|
*
|
706
821
|
* # You can specify addresses here or in an earlier connectx call.
|
707
|
-
* socket.sendv
|
822
|
+
* socket.sendv({
|
708
823
|
* :message => ['Hello ', 'World.'],
|
709
824
|
* :addresses => ['10.0.5.4', '10.0.6.4'],
|
710
825
|
* :info_type => SCTP::Socket:::SCTP_SENDV_SNDINFO
|
711
|
-
* )
|
826
|
+
* })
|
712
827
|
*
|
713
828
|
* CAVEAT: Currently info_type is not yet supported.
|
714
829
|
*
|
@@ -730,8 +845,11 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
730
845
|
v_message = rb_hash_aref2(v_options, "message");
|
731
846
|
v_addresses = rb_hash_aref2(v_options, "addresses");
|
732
847
|
|
733
|
-
|
734
|
-
|
848
|
+
// Validate required message parameter
|
849
|
+
if(NIL_P(v_message))
|
850
|
+
rb_raise(rb_eArgError, "message parameter is required");
|
851
|
+
|
852
|
+
Check_Type(v_message, T_ARRAY);
|
735
853
|
|
736
854
|
if(!NIL_P(v_addresses)){
|
737
855
|
Check_Type(v_addresses, T_ARRAY);
|
@@ -982,7 +1100,7 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
982
1100
|
* :stream -> The SCTP stream number you wish to send the message on.
|
983
1101
|
* :addresses -> An array of addresses to send the message to.
|
984
1102
|
* :context -> The default context used for the sendmsg call if the send fails.
|
985
|
-
* :ppid -> The payload protocol identifier that is passed to the peer endpoint.
|
1103
|
+
* :ppid -> The payload protocol identifier that is passed to the peer endpoint.
|
986
1104
|
* :flags -> A bitwise integer that contain one or more values that control behavior.
|
987
1105
|
*
|
988
1106
|
* Note that the :addresses option is not mandatory in a one-to-one (SOCK_STREAM)
|
@@ -1008,7 +1126,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1008
1126
|
uint16_t stream;
|
1009
1127
|
uint32_t ppid, flags, ttl, context;
|
1010
1128
|
ssize_t num_bytes;
|
1011
|
-
struct sockaddr_in addrs[
|
1129
|
+
struct sockaddr_in addrs[MAX_IP_ADDRESSES];
|
1012
1130
|
int fileno, size, num_ip;
|
1013
1131
|
|
1014
1132
|
Check_Type(v_options, T_HASH);
|
@@ -1023,6 +1141,9 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1023
1141
|
v_ttl = rb_hash_aref2(v_options, "ttl");
|
1024
1142
|
v_addresses = rb_hash_aref2(v_options, "addresses");
|
1025
1143
|
|
1144
|
+
if(NIL_P(v_msg))
|
1145
|
+
rb_raise(rb_eArgError, "message parameter is required");
|
1146
|
+
|
1026
1147
|
if(NIL_P(v_stream))
|
1027
1148
|
stream = 0;
|
1028
1149
|
else
|
@@ -1055,6 +1176,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1055
1176
|
int i, port;
|
1056
1177
|
VALUE v_address, v_port;
|
1057
1178
|
|
1179
|
+
Check_Type(v_addresses, T_ARRAY);
|
1058
1180
|
num_ip = (int)RARRAY_LEN(v_addresses);
|
1059
1181
|
v_port = rb_hash_aref2(v_options, "port");
|
1060
1182
|
|
@@ -1176,7 +1298,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
1176
1298
|
if(NIL_P(v_flags))
|
1177
1299
|
flags = 0;
|
1178
1300
|
else
|
1179
|
-
flags = NUM2INT(v_flags);
|
1301
|
+
flags = NUM2INT(v_flags);
|
1180
1302
|
|
1181
1303
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1182
1304
|
length = sizeof(struct sockaddr_in);
|
@@ -1305,7 +1427,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
1305
1427
|
* :peer_error (aka remote error)
|
1306
1428
|
*
|
1307
1429
|
* Example:
|
1308
|
-
*
|
1430
|
+
*
|
1309
1431
|
* socket = SCTP::Socket.new
|
1310
1432
|
*
|
1311
1433
|
* socket.bind(:port => port, :addresses => ['127.0.0.1'])
|
@@ -1402,7 +1524,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
|
1402
1524
|
|
1403
1525
|
if(listen(fileno, backlog) < 0)
|
1404
1526
|
rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
|
1405
|
-
|
1527
|
+
|
1406
1528
|
return self;
|
1407
1529
|
}
|
1408
1530
|
|
@@ -1427,7 +1549,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
|
1427
1549
|
static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
|
1428
1550
|
int fileno, assoc_fileno;
|
1429
1551
|
sctp_assoc_t assoc_id;
|
1430
|
-
|
1552
|
+
|
1431
1553
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1432
1554
|
assoc_id = NUM2INT(v_assoc_id);
|
1433
1555
|
|
@@ -1528,6 +1650,75 @@ static VALUE rsctp_get_association_info(VALUE self){
|
|
1528
1650
|
);
|
1529
1651
|
}
|
1530
1652
|
|
1653
|
+
/*
|
1654
|
+
* call-seq:
|
1655
|
+
* SCTP::Socket#set_association_info(options)
|
1656
|
+
*
|
1657
|
+
* Sets the association specific parameters. The +options+ parameter
|
1658
|
+
* is a hash that accepts the following keywords:
|
1659
|
+
*
|
1660
|
+
* * association_id
|
1661
|
+
* * max_retransmission_count
|
1662
|
+
* * number_peer_destinations
|
1663
|
+
* * peer_receive_window
|
1664
|
+
* * local_receive_window
|
1665
|
+
* * cookie_life
|
1666
|
+
*
|
1667
|
+
* All values that refer to time values are measured in milliseconds.
|
1668
|
+
*/
|
1669
|
+
static VALUE rsctp_set_association_info(VALUE self, VALUE v_options){
|
1670
|
+
VALUE v_assoc_id, v_max_rxt, v_nbr_peer, v_peer_rw, v_local_rw, v_cookie;
|
1671
|
+
int fileno;
|
1672
|
+
sctp_assoc_t assoc_id;
|
1673
|
+
struct sctp_assocparams assoc;
|
1674
|
+
|
1675
|
+
bzero(&assoc, sizeof(assoc));
|
1676
|
+
|
1677
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1678
|
+
|
1679
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
1680
|
+
v_max_rxt = rb_hash_aref2(v_options, "max_retransmission_count");
|
1681
|
+
v_nbr_peer = rb_hash_aref2(v_options, "number_peer_destinations");
|
1682
|
+
v_peer_rw = rb_hash_aref2(v_options, "peer_receive_window");
|
1683
|
+
v_local_rw = rb_hash_aref2(v_options, "local_receive_window");
|
1684
|
+
v_cookie = rb_hash_aref2(v_options, "cookie_life");
|
1685
|
+
|
1686
|
+
if(NIL_P(v_assoc_id))
|
1687
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1688
|
+
else
|
1689
|
+
assoc_id = NUM2INT(v_assoc_id);
|
1690
|
+
|
1691
|
+
assoc.sasoc_assoc_id = assoc_id;
|
1692
|
+
|
1693
|
+
if(!NIL_P(v_max_rxt))
|
1694
|
+
assoc.sasoc_asocmaxrxt = NUM2INT(v_max_rxt);
|
1695
|
+
|
1696
|
+
if(!NIL_P(v_nbr_peer))
|
1697
|
+
assoc.sasoc_number_peer_destinations = NUM2INT(v_nbr_peer);
|
1698
|
+
|
1699
|
+
if(!NIL_P(v_peer_rw))
|
1700
|
+
assoc.sasoc_peer_rwnd = NUM2INT(v_peer_rw);
|
1701
|
+
|
1702
|
+
if(!NIL_P(v_local_rw))
|
1703
|
+
assoc.sasoc_local_rwnd = NUM2INT(v_local_rw);
|
1704
|
+
|
1705
|
+
if(!NIL_P(v_cookie))
|
1706
|
+
assoc.sasoc_cookie_life = NUM2INT(v_cookie);
|
1707
|
+
|
1708
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) < 0)
|
1709
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1710
|
+
|
1711
|
+
return rb_struct_new(
|
1712
|
+
v_sctp_associnfo_struct,
|
1713
|
+
INT2NUM(assoc.sasoc_assoc_id),
|
1714
|
+
INT2NUM(assoc.sasoc_asocmaxrxt),
|
1715
|
+
INT2NUM(assoc.sasoc_number_peer_destinations),
|
1716
|
+
INT2NUM(assoc.sasoc_peer_rwnd),
|
1717
|
+
INT2NUM(assoc.sasoc_local_rwnd),
|
1718
|
+
INT2NUM(assoc.sasoc_cookie_life)
|
1719
|
+
);
|
1720
|
+
}
|
1721
|
+
|
1531
1722
|
/*
|
1532
1723
|
* call-seq:
|
1533
1724
|
* SCTP::Socket#shutdown
|
@@ -1602,6 +1793,64 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
|
|
1602
1793
|
);
|
1603
1794
|
}
|
1604
1795
|
|
1796
|
+
/*
|
1797
|
+
* call-seq:
|
1798
|
+
* SCTP::Socket#set_retransmission_info(options)
|
1799
|
+
*
|
1800
|
+
* Sets the protocol parameters that are used to initialize and bind the
|
1801
|
+
* retransmission timeout (RTO) tunable. The method accepts a hash with
|
1802
|
+
* the following possible keys:
|
1803
|
+
*
|
1804
|
+
* * association_id
|
1805
|
+
* * initial
|
1806
|
+
* * max
|
1807
|
+
* * min
|
1808
|
+
*
|
1809
|
+
* The +initial+, +max+ and +min+ options default to zero (unchanged).
|
1810
|
+
*/
|
1811
|
+
static VALUE rsctp_set_retransmission_info(VALUE self, VALUE v_options){
|
1812
|
+
VALUE v_assoc_id, v_initial, v_max, v_min;
|
1813
|
+
int fileno;
|
1814
|
+
sctp_assoc_t assoc_id;
|
1815
|
+
struct sctp_rtoinfo rto;
|
1816
|
+
|
1817
|
+
bzero(&rto, sizeof(rto));
|
1818
|
+
|
1819
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1820
|
+
|
1821
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
1822
|
+
v_initial = rb_hash_aref2(v_options, "initial");
|
1823
|
+
v_max = rb_hash_aref2(v_options, "max");
|
1824
|
+
v_min = rb_hash_aref2(v_options, "min");
|
1825
|
+
|
1826
|
+
if(NIL_P(v_assoc_id))
|
1827
|
+
v_assoc_id = rb_iv_get(self, "@association_id");
|
1828
|
+
|
1829
|
+
assoc_id = NUM2INT(v_assoc_id);
|
1830
|
+
|
1831
|
+
rto.srto_assoc_id = assoc_id;
|
1832
|
+
|
1833
|
+
if(!NIL_P(v_initial))
|
1834
|
+
rto.srto_initial = NUM2INT(v_initial);
|
1835
|
+
|
1836
|
+
if(!NIL_P(v_max))
|
1837
|
+
rto.srto_max = NUM2INT(v_max);
|
1838
|
+
|
1839
|
+
if(!NIL_P(v_min))
|
1840
|
+
rto.srto_min = NUM2INT(v_min);
|
1841
|
+
|
1842
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RTOINFO, &rto, sizeof(rto)) < 0)
|
1843
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1844
|
+
|
1845
|
+
return rb_struct_new(
|
1846
|
+
v_sctp_rtoinfo_struct,
|
1847
|
+
v_assoc_id,
|
1848
|
+
v_initial,
|
1849
|
+
v_max,
|
1850
|
+
v_min
|
1851
|
+
);
|
1852
|
+
}
|
1853
|
+
|
1605
1854
|
/*
|
1606
1855
|
* call-seq:
|
1607
1856
|
* SCTP::Socket#get_status
|
@@ -1757,7 +2006,7 @@ static VALUE rsctp_get_subscriptions(VALUE self){
|
|
1757
2006
|
*/
|
1758
2007
|
static VALUE rsctp_get_peer_address_params(VALUE self){
|
1759
2008
|
int fileno;
|
1760
|
-
char str[
|
2009
|
+
char str[IP_BUFFER_SIZE];
|
1761
2010
|
socklen_t size;
|
1762
2011
|
sctp_assoc_t assoc_id;
|
1763
2012
|
struct sctp_paddrparams paddr;
|
@@ -1864,11 +2113,9 @@ static VALUE rsctp_get_nodelay(VALUE self){
|
|
1864
2113
|
static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
1865
2114
|
int fileno;
|
1866
2115
|
socklen_t size;
|
1867
|
-
sctp_assoc_t assoc_id;
|
1868
2116
|
int value;
|
1869
2117
|
|
1870
2118
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1871
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1872
2119
|
size = sizeof(int);
|
1873
2120
|
|
1874
2121
|
if(NIL_P(v_bool) || v_bool == Qfalse)
|
@@ -1876,8 +2123,8 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
|
1876
2123
|
else
|
1877
2124
|
value = 1;
|
1878
2125
|
|
1879
|
-
if(
|
1880
|
-
rb_raise(rb_eSystemCallError, "
|
2126
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_NODELAY, &value, size) < 0)
|
2127
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1881
2128
|
|
1882
2129
|
if(value)
|
1883
2130
|
return Qtrue;
|
@@ -1888,7 +2135,7 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
|
1888
2135
|
/*
|
1889
2136
|
* call-seq:
|
1890
2137
|
* SCTP::Socket#disable_fragments=(bool)
|
1891
|
-
*
|
2138
|
+
*
|
1892
2139
|
* This option is a on/off flag and is passed an integer where a non-
|
1893
2140
|
* zero is on and a zero is off. If enabled no SCTP message
|
1894
2141
|
* fragmentation will be performed. Instead if a message being sent
|
@@ -1966,19 +2213,15 @@ static VALUE rsctp_get_autoclose(VALUE self){
|
|
1966
2213
|
*/
|
1967
2214
|
static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
|
1968
2215
|
int fileno;
|
1969
|
-
socklen_t size;
|
1970
|
-
sctp_assoc_t assoc_id;
|
1971
2216
|
int value;
|
1972
2217
|
|
1973
2218
|
value = NUM2INT(v_seconds);
|
1974
2219
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1975
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1976
|
-
size = sizeof(int);
|
1977
2220
|
|
1978
|
-
if(
|
1979
|
-
rb_raise(rb_eSystemCallError, "
|
2221
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTOCLOSE, &value, sizeof(value)) < 0)
|
2222
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1980
2223
|
|
1981
|
-
return
|
2224
|
+
return INT2NUM(value);
|
1982
2225
|
}
|
1983
2226
|
|
1984
2227
|
/*
|
@@ -2013,6 +2256,43 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
|
|
2013
2256
|
return self;
|
2014
2257
|
}
|
2015
2258
|
|
2259
|
+
/*
|
2260
|
+
* call-seq:
|
2261
|
+
* SCTP::Socket#auth_support?(association_id=nil)
|
2262
|
+
*
|
2263
|
+
* Returns whether or not authentication support is enabled for the association.
|
2264
|
+
* Returns true if auth support is enabled, false otherwise.
|
2265
|
+
*/
|
2266
|
+
static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
|
2267
|
+
int fileno;
|
2268
|
+
socklen_t size;
|
2269
|
+
sctp_assoc_t assoc_id;
|
2270
|
+
struct sctp_assoc_value assoc_value;
|
2271
|
+
VALUE v_assoc_id;
|
2272
|
+
|
2273
|
+
rb_scan_args(argc, argv, "01", &v_assoc_id);
|
2274
|
+
|
2275
|
+
CHECK_SOCKET_CLOSED(self);
|
2276
|
+
|
2277
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2278
|
+
size = sizeof(struct sctp_assoc_value);
|
2279
|
+
|
2280
|
+
if(NIL_P(v_assoc_id))
|
2281
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2282
|
+
else
|
2283
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2284
|
+
|
2285
|
+
assoc_value.assoc_id = assoc_id;
|
2286
|
+
|
2287
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
|
2288
|
+
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
2289
|
+
|
2290
|
+
if(assoc_value.assoc_value)
|
2291
|
+
return Qtrue;
|
2292
|
+
else
|
2293
|
+
return Qfalse;
|
2294
|
+
}
|
2295
|
+
|
2016
2296
|
/*
|
2017
2297
|
* call-seq:
|
2018
2298
|
* SCTP::Socket#set_shared_key(key, keynum, association_id=nil)
|
@@ -2076,7 +2356,7 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2076
2356
|
|
2077
2357
|
auth_key->sca_assoc_id = assoc_id;
|
2078
2358
|
auth_key->sca_keynumber = keynum;
|
2079
|
-
auth_key->sca_keylength = strlen(key);
|
2359
|
+
auth_key->sca_keylength = strlen(key);
|
2080
2360
|
memcpy(auth_key->sca_key, byte_array, sizeof(byte_array));
|
2081
2361
|
|
2082
2362
|
if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_KEY, (void*)auth_key, &size) < 0)
|
@@ -2239,22 +2519,228 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2239
2519
|
*/
|
2240
2520
|
static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
|
2241
2521
|
int fileno, boolean;
|
2242
|
-
sctp_assoc_t assoc_id;
|
2243
|
-
socklen_t size;
|
2244
2522
|
|
2245
2523
|
boolean = 0;
|
2246
2524
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2247
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2248
2525
|
|
2249
2526
|
if(v_bool == Qtrue)
|
2250
2527
|
boolean = 1;
|
2251
2528
|
|
2252
|
-
if(
|
2253
|
-
rb_raise(rb_eSystemCallError, "
|
2529
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&boolean, sizeof(boolean)) < 0)
|
2530
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2254
2531
|
|
2255
2532
|
return v_bool;
|
2256
2533
|
}
|
2257
2534
|
|
2535
|
+
/*
|
2536
|
+
* call-seq:
|
2537
|
+
* SCTP::Socket#map_ipv4?
|
2538
|
+
*
|
2539
|
+
* Returns whether or not IPv4 addresses will be mapped to V6 representation
|
2540
|
+
* for PF_INET6 sockets. Returns true if mapping is enabled, false otherwise.
|
2541
|
+
*/
|
2542
|
+
static VALUE rsctp_get_map_ipv4(VALUE self){
|
2543
|
+
int fileno;
|
2544
|
+
socklen_t size;
|
2545
|
+
sctp_assoc_t assoc_id;
|
2546
|
+
int value;
|
2547
|
+
|
2548
|
+
CHECK_SOCKET_CLOSED(self);
|
2549
|
+
|
2550
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2551
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2552
|
+
size = sizeof(int);
|
2553
|
+
|
2554
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&value, &size) < 0)
|
2555
|
+
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
2556
|
+
|
2557
|
+
if(value)
|
2558
|
+
return Qtrue;
|
2559
|
+
else
|
2560
|
+
return Qfalse;
|
2561
|
+
}
|
2562
|
+
|
2563
|
+
/*
|
2564
|
+
* call-seq:
|
2565
|
+
* SCTP::Socket#set_default_send_params(options)
|
2566
|
+
*
|
2567
|
+
* Sets the default parameters that will be used by the sendmsg() call
|
2568
|
+
* when it is invoked with a null parameter.
|
2569
|
+
*
|
2570
|
+
* The +options+ hash may contain the following keys:
|
2571
|
+
*
|
2572
|
+
* * stream: A number indicating the stream number within the association
|
2573
|
+
* * ssn: Not used by applications. Ignored for one-to-many style sockets.
|
2574
|
+
* * flags: Indicates various options for sending. See SCTP_* constants.
|
2575
|
+
* * ppid: The payload protocol identifier
|
2576
|
+
* * context: User-specified context information
|
2577
|
+
* * ttl: The time to live (in milliseconds)
|
2578
|
+
* * tsn: Not used by applications
|
2579
|
+
* * cumtsn: Not used by applications
|
2580
|
+
* * association_id: The association identification (ignored for one-to-one sockets)
|
2581
|
+
*
|
2582
|
+
* Example:
|
2583
|
+
*
|
2584
|
+
* socket.set_default_send_params(:stream => 1, :flags => SCTP::Socket::SCTP_UNORDERED)
|
2585
|
+
*/
|
2586
|
+
static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
|
2587
|
+
VALUE v_stream, v_ssn, v_flags, v_ppid, v_context, v_ttl, v_tsn, v_cumtsn, v_assoc_id;
|
2588
|
+
int fileno;
|
2589
|
+
sctp_assoc_t assoc_id;
|
2590
|
+
struct sctp_sndrcvinfo sndrcv;
|
2591
|
+
|
2592
|
+
if(!RB_TYPE_P(v_options, T_HASH))
|
2593
|
+
rb_raise(rb_eTypeError, "options must be a hash");
|
2594
|
+
|
2595
|
+
bzero(&sndrcv, sizeof(sndrcv));
|
2596
|
+
|
2597
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2598
|
+
|
2599
|
+
v_stream = rb_hash_aref2(v_options, "stream");
|
2600
|
+
v_ssn = rb_hash_aref2(v_options, "ssn");
|
2601
|
+
v_flags = rb_hash_aref2(v_options, "flags");
|
2602
|
+
v_ppid = rb_hash_aref2(v_options, "ppid");
|
2603
|
+
v_context = rb_hash_aref2(v_options, "context");
|
2604
|
+
v_ttl = rb_hash_aref2(v_options, "ttl");
|
2605
|
+
v_tsn = rb_hash_aref2(v_options, "tsn");
|
2606
|
+
v_cumtsn = rb_hash_aref2(v_options, "cumtsn");
|
2607
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
2608
|
+
|
2609
|
+
if(NIL_P(v_assoc_id))
|
2610
|
+
v_assoc_id = rb_iv_get(self, "@association_id");
|
2611
|
+
|
2612
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2613
|
+
sndrcv.sinfo_assoc_id = assoc_id;
|
2614
|
+
|
2615
|
+
if(!NIL_P(v_stream))
|
2616
|
+
sndrcv.sinfo_stream = NUM2INT(v_stream);
|
2617
|
+
|
2618
|
+
if(!NIL_P(v_ssn))
|
2619
|
+
sndrcv.sinfo_ssn = NUM2INT(v_ssn);
|
2620
|
+
|
2621
|
+
if(!NIL_P(v_flags))
|
2622
|
+
sndrcv.sinfo_flags = NUM2INT(v_flags);
|
2623
|
+
|
2624
|
+
if(!NIL_P(v_ppid))
|
2625
|
+
sndrcv.sinfo_ppid = NUM2INT(v_ppid);
|
2626
|
+
|
2627
|
+
if(!NIL_P(v_context))
|
2628
|
+
sndrcv.sinfo_context = NUM2INT(v_context);
|
2629
|
+
|
2630
|
+
if(!NIL_P(v_ttl))
|
2631
|
+
sndrcv.sinfo_timetolive = NUM2INT(v_ttl);
|
2632
|
+
|
2633
|
+
if(!NIL_P(v_tsn))
|
2634
|
+
sndrcv.sinfo_tsn = NUM2INT(v_tsn);
|
2635
|
+
|
2636
|
+
if(!NIL_P(v_cumtsn))
|
2637
|
+
sndrcv.sinfo_cumtsn = NUM2INT(v_cumtsn);
|
2638
|
+
|
2639
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, &sndrcv, sizeof(sndrcv)) < 0)
|
2640
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2641
|
+
|
2642
|
+
return rb_struct_new(
|
2643
|
+
v_sctp_default_send_params_struct,
|
2644
|
+
v_stream,
|
2645
|
+
v_ssn,
|
2646
|
+
v_flags,
|
2647
|
+
v_ppid,
|
2648
|
+
v_context,
|
2649
|
+
v_ttl,
|
2650
|
+
v_tsn,
|
2651
|
+
v_cumtsn,
|
2652
|
+
v_assoc_id
|
2653
|
+
);
|
2654
|
+
}
|
2655
|
+
|
2656
|
+
/*
|
2657
|
+
* call-seq:
|
2658
|
+
* SCTP::Socket#set_peer_address_params(options)
|
2659
|
+
*
|
2660
|
+
* Sets the peer address parameters. This allows applications to enable or
|
2661
|
+
* disable heartbeats for any peer address of an association, set the maximum
|
2662
|
+
* number of retransmissions to a destination address, and set the path MTU.
|
2663
|
+
*
|
2664
|
+
* The +options+ hash may contain the following keys:
|
2665
|
+
*
|
2666
|
+
* * association_id: The association identification
|
2667
|
+
* * address: The address of the remote peer
|
2668
|
+
* * hbinterval: The heartbeat interval (in milliseconds)
|
2669
|
+
* * pathmaxrxt: The maximum number of retransmissions
|
2670
|
+
* * pathmtu: The path MTU
|
2671
|
+
* * flags: Flags to control heartbeats, etc.
|
2672
|
+
* * ipv6_flowlabel: IPv6 flow label (only for IPv6 addresses)
|
2673
|
+
*
|
2674
|
+
* Example:
|
2675
|
+
*
|
2676
|
+
* socket.set_peer_address_params(:hbinterval => 5000, :pathmaxrxt => 5)
|
2677
|
+
*/
|
2678
|
+
static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
|
2679
|
+
VALUE v_assoc_id, v_address, v_hbinterval, v_pathmaxrxt, v_pathmtu, v_flags, v_ipv6_flowlabel;
|
2680
|
+
int fileno;
|
2681
|
+
sctp_assoc_t assoc_id;
|
2682
|
+
struct sctp_paddrparams paddr;
|
2683
|
+
struct sockaddr_in* sin;
|
2684
|
+
|
2685
|
+
if(!RB_TYPE_P(v_options, T_HASH))
|
2686
|
+
rb_raise(rb_eTypeError, "options must be a hash");
|
2687
|
+
|
2688
|
+
bzero(&paddr, sizeof(paddr));
|
2689
|
+
|
2690
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2691
|
+
|
2692
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
2693
|
+
v_address = rb_hash_aref2(v_options, "address");
|
2694
|
+
v_hbinterval = rb_hash_aref2(v_options, "hbinterval");
|
2695
|
+
v_pathmaxrxt = rb_hash_aref2(v_options, "pathmaxrxt");
|
2696
|
+
v_pathmtu = rb_hash_aref2(v_options, "pathmtu");
|
2697
|
+
v_flags = rb_hash_aref2(v_options, "flags");
|
2698
|
+
v_ipv6_flowlabel = rb_hash_aref2(v_options, "ipv6_flowlabel");
|
2699
|
+
|
2700
|
+
if(NIL_P(v_assoc_id))
|
2701
|
+
v_assoc_id = rb_iv_get(self, "@association_id");
|
2702
|
+
|
2703
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2704
|
+
paddr.spp_assoc_id = assoc_id;
|
2705
|
+
|
2706
|
+
// If address is provided, set up the sockaddr structure
|
2707
|
+
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");
|
2712
|
+
}
|
2713
|
+
|
2714
|
+
if(!NIL_P(v_hbinterval))
|
2715
|
+
paddr.spp_hbinterval = NUM2INT(v_hbinterval);
|
2716
|
+
|
2717
|
+
if(!NIL_P(v_pathmaxrxt))
|
2718
|
+
paddr.spp_pathmaxrxt = NUM2INT(v_pathmaxrxt);
|
2719
|
+
|
2720
|
+
if(!NIL_P(v_pathmtu))
|
2721
|
+
paddr.spp_pathmtu = NUM2INT(v_pathmtu);
|
2722
|
+
|
2723
|
+
if(!NIL_P(v_flags))
|
2724
|
+
paddr.spp_flags = NUM2INT(v_flags);
|
2725
|
+
|
2726
|
+
if(!NIL_P(v_ipv6_flowlabel))
|
2727
|
+
paddr.spp_ipv6_flowlabel = NUM2INT(v_ipv6_flowlabel);
|
2728
|
+
|
2729
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddr, sizeof(paddr)) < 0)
|
2730
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2731
|
+
|
2732
|
+
return rb_struct_new(
|
2733
|
+
v_sctp_peer_addr_params_struct,
|
2734
|
+
v_assoc_id,
|
2735
|
+
v_address,
|
2736
|
+
v_hbinterval,
|
2737
|
+
v_pathmaxrxt,
|
2738
|
+
v_pathmtu,
|
2739
|
+
v_flags,
|
2740
|
+
v_ipv6_flowlabel
|
2741
|
+
);
|
2742
|
+
}
|
2743
|
+
|
2258
2744
|
void Init_socket(void){
|
2259
2745
|
mSCTP = rb_define_module("SCTP");
|
2260
2746
|
cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
|
@@ -2358,23 +2844,26 @@ void Init_socket(void){
|
|
2358
2844
|
rb_define_method(cSocket, "autoclose=", rsctp_set_autoclose, 1);
|
2359
2845
|
rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
|
2360
2846
|
rb_define_method(cSocket, "close", rsctp_close, -1);
|
2847
|
+
rb_define_method(cSocket, "closed?", rsctp_closed_p, 0);
|
2361
2848
|
rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
|
2362
2849
|
rb_define_method(cSocket, "delete_shared_key", rsctp_delete_shared_key, -1);
|
2363
2850
|
rb_define_method(cSocket, "disable_fragments=", rsctp_disable_fragments, 1);
|
2364
2851
|
rb_define_method(cSocket, "enable_auth_support", rsctp_enable_auth_support, -1);
|
2852
|
+
rb_define_method(cSocket, "auth_support?", rsctp_get_auth_support, -1);
|
2365
2853
|
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1);
|
2366
2854
|
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1);
|
2367
2855
|
rb_define_method(cSocket, "get_active_shared_key", rsctp_get_active_shared_key, -1);
|
2368
2856
|
rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
|
2369
2857
|
rb_define_method(cSocket, "get_autoclose", rsctp_get_autoclose, 0);
|
2370
2858
|
rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
|
2371
|
-
rb_define_method(cSocket, "
|
2859
|
+
rb_define_method(cSocket, "get_init_msg", rsctp_get_init_msg, 0);
|
2372
2860
|
rb_define_method(cSocket, "get_peer_address_params", rsctp_get_peer_address_params, 0);
|
2373
2861
|
rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
|
2374
2862
|
rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
|
2375
2863
|
rb_define_method(cSocket, "get_subscriptions", rsctp_get_subscriptions, 0);
|
2376
2864
|
rb_define_method(cSocket, "listen", rsctp_listen, -1);
|
2377
2865
|
rb_define_method(cSocket, "map_ipv4=", rsctp_map_ipv4, 1);
|
2866
|
+
rb_define_method(cSocket, "map_ipv4?", rsctp_get_map_ipv4, 0);
|
2378
2867
|
rb_define_method(cSocket, "nodelay?", rsctp_get_nodelay, 0);
|
2379
2868
|
rb_define_method(cSocket, "nodelay=", rsctp_set_nodelay, 1);
|
2380
2869
|
rb_define_method(cSocket, "peeloff", rsctp_peeloff, 1);
|
@@ -2391,20 +2880,27 @@ void Init_socket(void){
|
|
2391
2880
|
|
2392
2881
|
rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
|
2393
2882
|
rb_define_method(cSocket, "set_active_shared_key", rsctp_set_active_shared_key, -1);
|
2883
|
+
rb_define_method(cSocket, "set_association_info", rsctp_set_association_info, 1);
|
2394
2884
|
rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
|
2395
|
-
|
2885
|
+
rb_define_method(cSocket, "set_retransmission_info", rsctp_set_retransmission_info, 1);
|
2886
|
+
rb_define_method(cSocket, "set_default_send_params", rsctp_set_default_send_params, 1);
|
2887
|
+
rb_define_method(cSocket, "set_peer_address_params", rsctp_set_peer_address_params, 1);
|
2396
2888
|
rb_define_method(cSocket, "set_shared_key", rsctp_set_shared_key, -1);
|
2397
2889
|
rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
|
2398
2890
|
rb_define_method(cSocket, "subscribe", rsctp_subscribe, 1);
|
2399
2891
|
|
2892
|
+
rb_define_alias(cSocket, "get_rto_info", "get_retransmission_info");
|
2893
|
+
rb_define_alias(cSocket, "set_rto_info", "set_retransmission_info");
|
2894
|
+
rb_define_alias(cSocket, "get_initmsg", "get_init_msg");
|
2895
|
+
|
2400
2896
|
rb_define_attr(cSocket, "domain", 1, 1);
|
2401
2897
|
rb_define_attr(cSocket, "type", 1, 1);
|
2402
2898
|
rb_define_attr(cSocket, "fileno", 1, 1);
|
2403
2899
|
rb_define_attr(cSocket, "association_id", 1, 1);
|
2404
2900
|
rb_define_attr(cSocket, "port", 1, 1);
|
2405
2901
|
|
2406
|
-
/* 0.1.
|
2407
|
-
rb_define_const(cSocket, "VERSION", rb_str_new2("0.
|
2902
|
+
/* 0.1.4: The version of this library */
|
2903
|
+
rb_define_const(cSocket, "VERSION", rb_str_new2("0.2.0"));
|
2408
2904
|
|
2409
2905
|
/* send flags */
|
2410
2906
|
|
@@ -2443,4 +2939,34 @@ void Init_socket(void){
|
|
2443
2939
|
|
2444
2940
|
rb_define_const(cSocket, "SCTP_BINDX_ADD_ADDR", INT2NUM(SCTP_BINDX_ADD_ADDR));
|
2445
2941
|
rb_define_const(cSocket, "SCTP_BINDX_REM_ADDR", INT2NUM(SCTP_BINDX_REM_ADDR));
|
2942
|
+
|
2943
|
+
// PEER ADDRESS PARAMETER FLAGS //
|
2944
|
+
|
2945
|
+
#ifdef SPP_HB_ENABLE
|
2946
|
+
rb_define_const(cSocket, "SPP_HB_ENABLE", INT2NUM(SPP_HB_ENABLE));
|
2947
|
+
#endif
|
2948
|
+
#ifdef SPP_HB_DISABLE
|
2949
|
+
rb_define_const(cSocket, "SPP_HB_DISABLE", INT2NUM(SPP_HB_DISABLE));
|
2950
|
+
#endif
|
2951
|
+
#ifdef SPP_HB_DEMAND
|
2952
|
+
rb_define_const(cSocket, "SPP_HB_DEMAND", INT2NUM(SPP_HB_DEMAND));
|
2953
|
+
#endif
|
2954
|
+
#ifdef SPP_PMTUD_ENABLE
|
2955
|
+
rb_define_const(cSocket, "SPP_PMTUD_ENABLE", INT2NUM(SPP_PMTUD_ENABLE));
|
2956
|
+
#endif
|
2957
|
+
#ifdef SPP_PMTUD_DISABLE
|
2958
|
+
rb_define_const(cSocket, "SPP_PMTUD_DISABLE", INT2NUM(SPP_PMTUD_DISABLE));
|
2959
|
+
#endif
|
2960
|
+
|
2961
|
+
// PARTIAL RELIABILITY SCTP POLICY CONSTANTS //
|
2962
|
+
|
2963
|
+
#ifdef SCTP_PR_SCTP_TTL
|
2964
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_TTL", INT2NUM(SCTP_PR_SCTP_TTL));
|
2965
|
+
#endif
|
2966
|
+
#ifdef SCTP_PR_SCTP_RTX
|
2967
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_RTX", INT2NUM(SCTP_PR_SCTP_RTX));
|
2968
|
+
#endif
|
2969
|
+
#ifdef SCTP_PR_SCTP_BUF
|
2970
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_BUF", INT2NUM(SCTP_PR_SCTP_BUF));
|
2971
|
+
#endif
|
2446
2972
|
}
|