sctp-socket 0.1.4 → 0.2.1
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/.gitignore +1 -0
- data/CHANGES.md +21 -0
- data/README.md +75 -0
- data/Rakefile +3 -1
- 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 +604 -115
- data/lib/sctp/server.rb +207 -0
- data/sctp-socket.gemspec +2 -2
- data.tar.gz.sig +0 -0
- metadata +6 -7
- metadata.gz.sig +0 -0
- data/.github/FUNDING.yml +0 -4
- data/.github/workflows/ruby.yml +0 -59
- 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,13 @@ 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);
|
853
|
+
|
854
|
+
CHECK_SOCKET_CLOSED(self);
|
735
855
|
|
736
856
|
if(!NIL_P(v_addresses)){
|
737
857
|
Check_Type(v_addresses, T_ARRAY);
|
@@ -807,24 +927,48 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
|
807
927
|
#endif
|
808
928
|
|
809
929
|
#ifdef HAVE_SCTP_RECVV
|
930
|
+
/*
|
931
|
+
* call-seq:
|
932
|
+
* SCTP::Socket#recvv(flags=0, buffer_size=1024)
|
933
|
+
*
|
934
|
+
* Receive a message using sctp_recvv from another SCTP endpoint.
|
935
|
+
*
|
936
|
+
* The optional buffer_size parameter specifies the size of the receive buffer
|
937
|
+
* in bytes. Defaults to 1024 bytes if not specified.
|
938
|
+
*
|
939
|
+
* Example:
|
940
|
+
*
|
941
|
+
* begin
|
942
|
+
* socket = SCTP::Socket.new
|
943
|
+
* socket.bind(:port => 62534, :addresses => ['10.0.4.5', '10.0.5.5'])
|
944
|
+
* socket.listen
|
945
|
+
*
|
946
|
+
* while true
|
947
|
+
* info = socket.recvv
|
948
|
+
* puts "Received message: #{info.message}"
|
949
|
+
*
|
950
|
+
* # Or with custom buffer size
|
951
|
+
* info = socket.recvv(0, 4096)
|
952
|
+
* puts "Received message: #{info.message}"
|
953
|
+
* end
|
954
|
+
* ensure
|
955
|
+
* socket.close
|
956
|
+
* end
|
957
|
+
*/
|
810
958
|
static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
811
|
-
VALUE v_flags;
|
812
|
-
int fileno, flags, on;
|
959
|
+
VALUE v_flags, v_buffer_size;
|
960
|
+
int fileno, flags, on, buffer_size;
|
813
961
|
ssize_t bytes;
|
814
962
|
uint infotype;
|
815
963
|
socklen_t infolen;
|
816
964
|
struct iovec iov[1];
|
817
965
|
struct sctp_rcvinfo info;
|
818
|
-
char buffer
|
966
|
+
char *buffer;
|
819
967
|
|
820
968
|
bzero(&iov, sizeof(iov));
|
821
969
|
bzero(&info, sizeof(info));
|
822
|
-
bzero(&buffer, sizeof(buffer));
|
823
|
-
|
824
|
-
iov->iov_base = buffer;
|
825
|
-
iov->iov_len = sizeof(buffer);
|
826
970
|
|
827
|
-
rb_scan_args(argc, argv, "
|
971
|
+
rb_scan_args(argc, argv, "02", &v_flags, &v_buffer_size);
|
828
972
|
|
829
973
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
830
974
|
|
@@ -833,9 +977,28 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
|
833
977
|
else
|
834
978
|
flags = NUM2INT(v_flags);
|
835
979
|
|
980
|
+
if(NIL_P(v_buffer_size))
|
981
|
+
buffer_size = 1024;
|
982
|
+
else
|
983
|
+
buffer_size = NUM2INT(v_buffer_size);
|
984
|
+
|
985
|
+
if(buffer_size <= 0)
|
986
|
+
rb_raise(rb_eArgError, "buffer size must be positive");
|
987
|
+
|
988
|
+
buffer = (char*)malloc(buffer_size);
|
989
|
+
if(buffer == NULL)
|
990
|
+
rb_raise(rb_eNoMemError, "failed to allocate buffer");
|
991
|
+
|
992
|
+
bzero(buffer, buffer_size);
|
993
|
+
|
994
|
+
iov->iov_base = buffer;
|
995
|
+
iov->iov_len = buffer_size;
|
996
|
+
|
836
997
|
on = 1;
|
837
|
-
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0)
|
998
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0){
|
999
|
+
free(buffer);
|
838
1000
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
1001
|
+
}
|
839
1002
|
|
840
1003
|
infolen = sizeof(struct sctp_rcvinfo);
|
841
1004
|
infotype = 0;
|
@@ -852,16 +1015,19 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
|
852
1015
|
&flags
|
853
1016
|
);
|
854
1017
|
|
855
|
-
if(bytes < 0)
|
1018
|
+
if(bytes < 0){
|
1019
|
+
free(buffer);
|
856
1020
|
rb_raise(rb_eSystemCallError, "sctp_recvv: %s", strerror(errno));
|
1021
|
+
}
|
857
1022
|
|
858
1023
|
if(infotype != SCTP_RECVV_RCVINFO){
|
1024
|
+
free(buffer);
|
859
1025
|
return Qnil;
|
860
1026
|
}
|
861
1027
|
else{
|
862
|
-
|
1028
|
+
VALUE result = rb_struct_new(
|
863
1029
|
v_sctp_receive_info_struct,
|
864
|
-
|
1030
|
+
rb_str_new(iov->iov_base, bytes),
|
865
1031
|
UINT2NUM(info.rcv_sid),
|
866
1032
|
UINT2NUM(info.rcv_ssn),
|
867
1033
|
UINT2NUM(info.rcv_flags),
|
@@ -871,6 +1037,8 @@ static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
|
871
1037
|
UINT2NUM(info.rcv_context),
|
872
1038
|
UINT2NUM(info.rcv_assoc_id)
|
873
1039
|
);
|
1040
|
+
free(buffer);
|
1041
|
+
return result;
|
874
1042
|
}
|
875
1043
|
}
|
876
1044
|
#endif
|
@@ -982,7 +1150,7 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
982
1150
|
* :stream -> The SCTP stream number you wish to send the message on.
|
983
1151
|
* :addresses -> An array of addresses to send the message to.
|
984
1152
|
* :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.
|
1153
|
+
* :ppid -> The payload protocol identifier that is passed to the peer endpoint.
|
986
1154
|
* :flags -> A bitwise integer that contain one or more values that control behavior.
|
987
1155
|
*
|
988
1156
|
* Note that the :addresses option is not mandatory in a one-to-one (SOCK_STREAM)
|
@@ -1008,7 +1176,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1008
1176
|
uint16_t stream;
|
1009
1177
|
uint32_t ppid, flags, ttl, context;
|
1010
1178
|
ssize_t num_bytes;
|
1011
|
-
struct sockaddr_in addrs[
|
1179
|
+
struct sockaddr_in addrs[MAX_IP_ADDRESSES];
|
1012
1180
|
int fileno, size, num_ip;
|
1013
1181
|
|
1014
1182
|
Check_Type(v_options, T_HASH);
|
@@ -1023,6 +1191,9 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1023
1191
|
v_ttl = rb_hash_aref2(v_options, "ttl");
|
1024
1192
|
v_addresses = rb_hash_aref2(v_options, "addresses");
|
1025
1193
|
|
1194
|
+
if(NIL_P(v_msg))
|
1195
|
+
rb_raise(rb_eArgError, "message parameter is required");
|
1196
|
+
|
1026
1197
|
if(NIL_P(v_stream))
|
1027
1198
|
stream = 0;
|
1028
1199
|
else
|
@@ -1055,6 +1226,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1055
1226
|
int i, port;
|
1056
1227
|
VALUE v_address, v_port;
|
1057
1228
|
|
1229
|
+
Check_Type(v_addresses, T_ARRAY);
|
1058
1230
|
num_ip = (int)RARRAY_LEN(v_addresses);
|
1059
1231
|
v_port = rb_hash_aref2(v_options, "port");
|
1060
1232
|
|
@@ -1142,10 +1314,13 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1142
1314
|
|
1143
1315
|
/*
|
1144
1316
|
* call-seq:
|
1145
|
-
* SCTP::Socket#recvmsg(flags=0)
|
1317
|
+
* SCTP::Socket#recvmsg(flags=0, buffer_size=1024)
|
1146
1318
|
*
|
1147
1319
|
* Receive a message from another SCTP endpoint.
|
1148
1320
|
*
|
1321
|
+
* The optional buffer_size parameter specifies the size of the receive buffer
|
1322
|
+
* in bytes. Defaults to 1024 bytes if not specified.
|
1323
|
+
*
|
1149
1324
|
* Example:
|
1150
1325
|
*
|
1151
1326
|
* begin
|
@@ -1157,46 +1332,64 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
1157
1332
|
* while true
|
1158
1333
|
* info = socket.recvmsg
|
1159
1334
|
* puts "Received message: #{info.message}"
|
1335
|
+
*
|
1336
|
+
* # Or with custom buffer size
|
1337
|
+
* info = socket.recvmsg(0, 4096)
|
1338
|
+
* puts "Received message: #{info.message}"
|
1160
1339
|
* end
|
1161
1340
|
* ensure
|
1162
1341
|
* socket.close
|
1163
1342
|
* end
|
1164
1343
|
*/
|
1165
1344
|
static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
1166
|
-
VALUE v_flags, v_notification, v_message;
|
1345
|
+
VALUE v_flags, v_buffer_size, v_notification, v_message;
|
1167
1346
|
struct sctp_sndrcvinfo sndrcvinfo;
|
1168
1347
|
struct sockaddr_in clientaddr;
|
1169
|
-
int flags, fileno;
|
1348
|
+
int flags, fileno, buffer_size;
|
1170
1349
|
ssize_t bytes;
|
1171
|
-
char buffer
|
1350
|
+
char *buffer;
|
1172
1351
|
socklen_t length;
|
1173
1352
|
|
1174
|
-
rb_scan_args(argc, argv, "
|
1353
|
+
rb_scan_args(argc, argv, "02", &v_flags, &v_buffer_size);
|
1175
1354
|
|
1176
1355
|
if(NIL_P(v_flags))
|
1177
1356
|
flags = 0;
|
1178
1357
|
else
|
1179
|
-
flags = NUM2INT(v_flags);
|
1358
|
+
flags = NUM2INT(v_flags);
|
1359
|
+
|
1360
|
+
if(NIL_P(v_buffer_size))
|
1361
|
+
buffer_size = 1024;
|
1362
|
+
else
|
1363
|
+
buffer_size = NUM2INT(v_buffer_size);
|
1364
|
+
|
1365
|
+
if(buffer_size <= 0)
|
1366
|
+
rb_raise(rb_eArgError, "buffer size must be positive");
|
1367
|
+
|
1368
|
+
buffer = (char*)malloc(buffer_size);
|
1369
|
+
if(buffer == NULL)
|
1370
|
+
rb_raise(rb_eNoMemError, "failed to allocate buffer");
|
1180
1371
|
|
1181
1372
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1182
1373
|
length = sizeof(struct sockaddr_in);
|
1183
1374
|
|
1184
|
-
bzero(buffer,
|
1375
|
+
bzero(buffer, buffer_size);
|
1185
1376
|
bzero(&clientaddr, sizeof(clientaddr));
|
1186
1377
|
bzero(&sndrcvinfo, sizeof(sndrcvinfo));
|
1187
1378
|
|
1188
1379
|
bytes = (ssize_t)sctp_recvmsg(
|
1189
1380
|
fileno,
|
1190
1381
|
buffer,
|
1191
|
-
|
1382
|
+
buffer_size,
|
1192
1383
|
(struct sockaddr*)&clientaddr,
|
1193
1384
|
&length,
|
1194
1385
|
&sndrcvinfo,
|
1195
1386
|
&flags
|
1196
1387
|
);
|
1197
1388
|
|
1198
|
-
if(bytes < 0)
|
1389
|
+
if(bytes < 0){
|
1390
|
+
free(buffer);
|
1199
1391
|
rb_raise(rb_eSystemCallError, "sctp_recvmsg: %s", strerror(errno));
|
1392
|
+
}
|
1200
1393
|
|
1201
1394
|
v_notification = Qnil;
|
1202
1395
|
|
@@ -1208,6 +1401,8 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
1208
1401
|
else
|
1209
1402
|
v_message = Qnil;
|
1210
1403
|
|
1404
|
+
free(buffer);
|
1405
|
+
|
1211
1406
|
return rb_struct_new(v_sndrcv_struct,
|
1212
1407
|
v_message,
|
1213
1408
|
UINT2NUM(sndrcvinfo.sinfo_stream),
|
@@ -1305,7 +1500,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
1305
1500
|
* :peer_error (aka remote error)
|
1306
1501
|
*
|
1307
1502
|
* Example:
|
1308
|
-
*
|
1503
|
+
*
|
1309
1504
|
* socket = SCTP::Socket.new
|
1310
1505
|
*
|
1311
1506
|
* socket.bind(:port => port, :addresses => ['127.0.0.1'])
|
@@ -1402,7 +1597,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
|
1402
1597
|
|
1403
1598
|
if(listen(fileno, backlog) < 0)
|
1404
1599
|
rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
|
1405
|
-
|
1600
|
+
|
1406
1601
|
return self;
|
1407
1602
|
}
|
1408
1603
|
|
@@ -1427,7 +1622,7 @@ static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
|
1427
1622
|
static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
|
1428
1623
|
int fileno, assoc_fileno;
|
1429
1624
|
sctp_assoc_t assoc_id;
|
1430
|
-
|
1625
|
+
|
1431
1626
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1432
1627
|
assoc_id = NUM2INT(v_assoc_id);
|
1433
1628
|
|
@@ -1884,7 +2079,7 @@ static VALUE rsctp_get_subscriptions(VALUE self){
|
|
1884
2079
|
*/
|
1885
2080
|
static VALUE rsctp_get_peer_address_params(VALUE self){
|
1886
2081
|
int fileno;
|
1887
|
-
char str[
|
2082
|
+
char str[IP_BUFFER_SIZE];
|
1888
2083
|
socklen_t size;
|
1889
2084
|
sctp_assoc_t assoc_id;
|
1890
2085
|
struct sctp_paddrparams paddr;
|
@@ -1991,11 +2186,9 @@ static VALUE rsctp_get_nodelay(VALUE self){
|
|
1991
2186
|
static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
1992
2187
|
int fileno;
|
1993
2188
|
socklen_t size;
|
1994
|
-
sctp_assoc_t assoc_id;
|
1995
2189
|
int value;
|
1996
2190
|
|
1997
2191
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1998
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1999
2192
|
size = sizeof(int);
|
2000
2193
|
|
2001
2194
|
if(NIL_P(v_bool) || v_bool == Qfalse)
|
@@ -2003,8 +2196,8 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
|
2003
2196
|
else
|
2004
2197
|
value = 1;
|
2005
2198
|
|
2006
|
-
if(
|
2007
|
-
rb_raise(rb_eSystemCallError, "
|
2199
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_NODELAY, &value, size) < 0)
|
2200
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2008
2201
|
|
2009
2202
|
if(value)
|
2010
2203
|
return Qtrue;
|
@@ -2015,7 +2208,7 @@ static VALUE rsctp_set_nodelay(VALUE self, VALUE v_bool){
|
|
2015
2208
|
/*
|
2016
2209
|
* call-seq:
|
2017
2210
|
* SCTP::Socket#disable_fragments=(bool)
|
2018
|
-
*
|
2211
|
+
*
|
2019
2212
|
* This option is a on/off flag and is passed an integer where a non-
|
2020
2213
|
* zero is on and a zero is off. If enabled no SCTP message
|
2021
2214
|
* fragmentation will be performed. Instead if a message being sent
|
@@ -2093,19 +2286,15 @@ static VALUE rsctp_get_autoclose(VALUE self){
|
|
2093
2286
|
*/
|
2094
2287
|
static VALUE rsctp_set_autoclose(VALUE self, VALUE v_seconds){
|
2095
2288
|
int fileno;
|
2096
|
-
socklen_t size;
|
2097
|
-
sctp_assoc_t assoc_id;
|
2098
2289
|
int value;
|
2099
2290
|
|
2100
2291
|
value = NUM2INT(v_seconds);
|
2101
2292
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2102
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2103
|
-
size = sizeof(int);
|
2104
2293
|
|
2105
|
-
if(
|
2106
|
-
rb_raise(rb_eSystemCallError, "
|
2294
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTOCLOSE, &value, sizeof(value)) < 0)
|
2295
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2107
2296
|
|
2108
|
-
return
|
2297
|
+
return INT2NUM(value);
|
2109
2298
|
}
|
2110
2299
|
|
2111
2300
|
/*
|
@@ -2123,6 +2312,8 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
|
|
2123
2312
|
|
2124
2313
|
rb_scan_args(argc, argv, "01", &v_assoc_id);
|
2125
2314
|
|
2315
|
+
CHECK_SOCKET_CLOSED(self);
|
2316
|
+
|
2126
2317
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2127
2318
|
size = sizeof(struct sctp_assoc_value);
|
2128
2319
|
|
@@ -2134,15 +2325,52 @@ static VALUE rsctp_enable_auth_support(int argc, VALUE* argv, VALUE self){
|
|
2134
2325
|
assoc_value.assoc_id = assoc_id;
|
2135
2326
|
assoc_value.assoc_value = 1;
|
2136
2327
|
|
2328
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, size) < 0)
|
2329
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2330
|
+
|
2331
|
+
return self;
|
2332
|
+
}
|
2333
|
+
|
2334
|
+
/*
|
2335
|
+
* call-seq:
|
2336
|
+
* SCTP::Socket#auth_support?(association_id=nil)
|
2337
|
+
*
|
2338
|
+
* Returns whether or not authentication support is enabled for the association.
|
2339
|
+
* Returns true if auth support is enabled, false otherwise.
|
2340
|
+
*/
|
2341
|
+
static VALUE rsctp_get_auth_support(int argc, VALUE* argv, VALUE self){
|
2342
|
+
int fileno;
|
2343
|
+
socklen_t size;
|
2344
|
+
sctp_assoc_t assoc_id;
|
2345
|
+
struct sctp_assoc_value assoc_value;
|
2346
|
+
VALUE v_assoc_id;
|
2347
|
+
|
2348
|
+
rb_scan_args(argc, argv, "01", &v_assoc_id);
|
2349
|
+
|
2350
|
+
CHECK_SOCKET_CLOSED(self);
|
2351
|
+
|
2352
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2353
|
+
size = sizeof(struct sctp_assoc_value);
|
2354
|
+
|
2355
|
+
if(NIL_P(v_assoc_id))
|
2356
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2357
|
+
else
|
2358
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2359
|
+
|
2360
|
+
assoc_value.assoc_id = assoc_id;
|
2361
|
+
|
2137
2362
|
if(sctp_opt_info(fileno, assoc_id, SCTP_AUTH_SUPPORTED, (void*)&assoc_value, &size) < 0)
|
2138
2363
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
2139
2364
|
|
2140
|
-
|
2365
|
+
if(assoc_value.assoc_value)
|
2366
|
+
return Qtrue;
|
2367
|
+
else
|
2368
|
+
return Qfalse;
|
2141
2369
|
}
|
2142
2370
|
|
2143
2371
|
/*
|
2144
2372
|
* call-seq:
|
2145
|
-
* SCTP::Socket#set_shared_key(key, keynum, association_id=nil)
|
2373
|
+
* SCTP::Socket#set_shared_key(key, keynum=1, association_id=nil)
|
2146
2374
|
*
|
2147
2375
|
* This option will set a shared secret key which is used to build an
|
2148
2376
|
* association shared key.
|
@@ -2178,18 +2406,11 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2178
2406
|
|
2179
2407
|
rb_scan_args(argc, argv, "12", &v_key, &v_keynumber, &v_assoc_id);
|
2180
2408
|
|
2409
|
+
CHECK_SOCKET_CLOSED(self);
|
2410
|
+
|
2181
2411
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2182
2412
|
key = StringValuePtr(v_key);
|
2183
|
-
len =
|
2184
|
-
unsigned char byte_array[len+1];
|
2185
|
-
|
2186
|
-
for(size_t i = 0; i < len; i++)
|
2187
|
-
byte_array[i] = key[i];
|
2188
|
-
|
2189
|
-
byte_array[len] = '\0';
|
2190
|
-
|
2191
|
-
auth_key = malloc(sizeof(auth_key) + sizeof(char[strlen(key)+1]));
|
2192
|
-
size = sizeof(auth_key);
|
2413
|
+
len = RSTRING_LEN(v_key); // Use Ruby's string length, not strlen
|
2193
2414
|
|
2194
2415
|
if(NIL_P(v_assoc_id))
|
2195
2416
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
@@ -2201,14 +2422,25 @@ static VALUE rsctp_set_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2201
2422
|
else
|
2202
2423
|
keynum = NUM2INT(v_keynumber);
|
2203
2424
|
|
2425
|
+
// Allocate the structure with space for the key
|
2426
|
+
size = sizeof(struct sctp_authkey) + len;
|
2427
|
+
auth_key = malloc(size);
|
2428
|
+
|
2429
|
+
if (auth_key == NULL)
|
2430
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for auth key");
|
2431
|
+
|
2204
2432
|
auth_key->sca_assoc_id = assoc_id;
|
2205
2433
|
auth_key->sca_keynumber = keynum;
|
2206
|
-
auth_key->sca_keylength =
|
2207
|
-
memcpy(auth_key->sca_key,
|
2434
|
+
auth_key->sca_keylength = len;
|
2435
|
+
memcpy(auth_key->sca_key, key, len);
|
2208
2436
|
|
2209
|
-
if(
|
2210
|
-
|
2437
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_KEY, (void*)auth_key, size) < 0) {
|
2438
|
+
int err = errno;
|
2439
|
+
free(auth_key);
|
2440
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(err));
|
2441
|
+
}
|
2211
2442
|
|
2443
|
+
free(auth_key);
|
2212
2444
|
return self;
|
2213
2445
|
}
|
2214
2446
|
|
@@ -2224,14 +2456,19 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2224
2456
|
struct sctp_authkeyid authkey;
|
2225
2457
|
sctp_assoc_t assoc_id;
|
2226
2458
|
VALUE v_assoc_id, v_keynum;
|
2227
|
-
|
2459
|
+
int keynum;
|
2228
2460
|
|
2229
2461
|
rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
|
2230
2462
|
|
2231
2463
|
bzero(&authkey, sizeof(authkey));
|
2232
2464
|
|
2465
|
+
// Cast it later, we want to force a validity check.
|
2466
|
+
keynum = FIX2INT(v_keynum);
|
2467
|
+
|
2468
|
+
if(keynum < 0)
|
2469
|
+
rb_raise(rb_eArgError, "invalid keynum value");
|
2470
|
+
|
2233
2471
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2234
|
-
keynum = NUM2UINT(v_keynum);
|
2235
2472
|
|
2236
2473
|
if(NIL_P(v_assoc_id))
|
2237
2474
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
@@ -2239,7 +2476,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2239
2476
|
assoc_id = NUM2INT(v_assoc_id);
|
2240
2477
|
|
2241
2478
|
authkey.scact_assoc_id = assoc_id;
|
2242
|
-
authkey.scact_keynumber = keynum;
|
2479
|
+
authkey.scact_keynumber = (uint)keynum;
|
2243
2480
|
|
2244
2481
|
size = sizeof(struct sctp_authkeyid);
|
2245
2482
|
|
@@ -2260,7 +2497,7 @@ static VALUE rsctp_get_active_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2260
2497
|
* authenticated chunks. The key identifier MUST correspond to an existing
|
2261
2498
|
* shared key. Note that shared key identifier '0' defaults to a null key.
|
2262
2499
|
*
|
2263
|
-
* The
|
2500
|
+
* The association_id parameter, if non-zero, indicates what association that
|
2264
2501
|
* the shared key identifier is being set active upon. If this element contains
|
2265
2502
|
* zero, then the activation applies to the endpoint and all future
|
2266
2503
|
* associations will use the specified shared key identifier.
|
@@ -2277,11 +2514,15 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2277
2514
|
struct sctp_authkeyid authkey;
|
2278
2515
|
sctp_assoc_t assoc_id;
|
2279
2516
|
VALUE v_assoc_id, v_keynum;
|
2280
|
-
|
2517
|
+
int keynum;
|
2281
2518
|
|
2282
2519
|
rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
|
2283
2520
|
|
2284
|
-
keynum =
|
2521
|
+
keynum = FIX2INT(v_keynum);
|
2522
|
+
|
2523
|
+
if(keynum < 0)
|
2524
|
+
rb_raise(rb_eArgError, "invalid keynum value");
|
2525
|
+
|
2285
2526
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2286
2527
|
|
2287
2528
|
if(NIL_P(v_assoc_id))
|
@@ -2290,11 +2531,11 @@ static VALUE rsctp_set_active_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2290
2531
|
assoc_id = NUM2INT(v_assoc_id);
|
2291
2532
|
|
2292
2533
|
authkey.scact_assoc_id = assoc_id;
|
2293
|
-
authkey.scact_keynumber = keynum;
|
2534
|
+
authkey.scact_keynumber = (uint)keynum;
|
2294
2535
|
size = sizeof(struct sctp_authkeyid);
|
2295
2536
|
|
2296
|
-
if(
|
2297
|
-
rb_raise(rb_eSystemCallError, "
|
2537
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, (void*)&authkey, size) < 0)
|
2538
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2298
2539
|
|
2299
2540
|
return self;
|
2300
2541
|
}
|
@@ -2334,6 +2575,8 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2334
2575
|
|
2335
2576
|
rb_scan_args(argc, argv, "11", &v_keynum, &v_assoc_id);
|
2336
2577
|
|
2578
|
+
CHECK_SOCKET_CLOSED(self);
|
2579
|
+
|
2337
2580
|
bzero(&authkey, sizeof(authkey));
|
2338
2581
|
|
2339
2582
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
@@ -2349,8 +2592,8 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2349
2592
|
|
2350
2593
|
size = sizeof(struct sctp_authkeyid);
|
2351
2594
|
|
2352
|
-
if(
|
2353
|
-
rb_raise(rb_eSystemCallError, "
|
2595
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, (void*)&authkey, size) < 0)
|
2596
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2354
2597
|
|
2355
2598
|
return INT2NUM(authkey.scact_keynumber);
|
2356
2599
|
}
|
@@ -2359,29 +2602,239 @@ static VALUE rsctp_delete_shared_key(int argc, VALUE* argv, VALUE self){
|
|
2359
2602
|
* call-seq:
|
2360
2603
|
* SCTP::Socket#map_ipv4=(bool)
|
2361
2604
|
*
|
2362
|
-
* If set to true and the socket is type
|
2605
|
+
* If set to true and the socket is type xF_INET6, then IPv4 addresses will be
|
2363
2606
|
* mapped to V6 representation. If set to false (the default), then no mapping
|
2364
|
-
* will be done of V4 addresses and a user will receive both
|
2365
|
-
*
|
2607
|
+
* will be done of V4 addresses and a user will receive both xF_INET6 and
|
2608
|
+
* xF_INET type addresses on the socket.
|
2609
|
+
*
|
2610
|
+
* Note that setting this to true on a socket that is not type xF_INET6 is
|
2611
|
+
* undefined behavior, and may raise an error on your platform. Otherwise it's
|
2612
|
+
* a no-op.
|
2366
2613
|
*/
|
2367
2614
|
static VALUE rsctp_map_ipv4(VALUE self, VALUE v_bool){
|
2368
2615
|
int fileno, boolean;
|
2369
|
-
sctp_assoc_t assoc_id;
|
2370
|
-
socklen_t size;
|
2371
2616
|
|
2372
2617
|
boolean = 0;
|
2373
2618
|
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2374
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2375
2619
|
|
2376
2620
|
if(v_bool == Qtrue)
|
2377
2621
|
boolean = 1;
|
2378
2622
|
|
2379
|
-
if(
|
2380
|
-
rb_raise(rb_eSystemCallError, "
|
2623
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&boolean, sizeof(boolean)) < 0)
|
2624
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2381
2625
|
|
2382
2626
|
return v_bool;
|
2383
2627
|
}
|
2384
2628
|
|
2629
|
+
/*
|
2630
|
+
* call-seq:
|
2631
|
+
* SCTP::Socket#map_ipv4?
|
2632
|
+
*
|
2633
|
+
* Returns whether or not IPv4 addresses will be mapped to V6 representation
|
2634
|
+
* for PF_INET6 sockets. Returns true if mapping is enabled, false otherwise.
|
2635
|
+
*/
|
2636
|
+
static VALUE rsctp_get_map_ipv4(VALUE self){
|
2637
|
+
int fileno;
|
2638
|
+
socklen_t size;
|
2639
|
+
sctp_assoc_t assoc_id;
|
2640
|
+
int value;
|
2641
|
+
|
2642
|
+
CHECK_SOCKET_CLOSED(self);
|
2643
|
+
|
2644
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2645
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
2646
|
+
size = sizeof(int);
|
2647
|
+
|
2648
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_I_WANT_MAPPED_V4_ADDR, (void*)&value, &size) < 0)
|
2649
|
+
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
2650
|
+
|
2651
|
+
if(value)
|
2652
|
+
return Qtrue;
|
2653
|
+
else
|
2654
|
+
return Qfalse;
|
2655
|
+
}
|
2656
|
+
|
2657
|
+
/*
|
2658
|
+
* call-seq:
|
2659
|
+
* SCTP::Socket#set_default_send_params(options)
|
2660
|
+
*
|
2661
|
+
* Sets the default parameters that will be used by the sendmsg() call
|
2662
|
+
* when it is invoked with a null parameter.
|
2663
|
+
*
|
2664
|
+
* The +options+ hash may contain the following keys:
|
2665
|
+
*
|
2666
|
+
* * stream: A number indicating the stream number within the association
|
2667
|
+
* * ssn: Not used by applications. Ignored for one-to-many style sockets.
|
2668
|
+
* * flags: Indicates various options for sending. See SCTP_* constants.
|
2669
|
+
* * ppid: The payload protocol identifier
|
2670
|
+
* * context: User-specified context information
|
2671
|
+
* * ttl: The time to live (in milliseconds)
|
2672
|
+
* * tsn: Not used by applications
|
2673
|
+
* * cumtsn: Not used by applications
|
2674
|
+
* * association_id: The association identification (ignored for one-to-one sockets)
|
2675
|
+
*
|
2676
|
+
* Example:
|
2677
|
+
*
|
2678
|
+
* socket.set_default_send_params(:stream => 1, :flags => SCTP::Socket::SCTP_UNORDERED)
|
2679
|
+
*/
|
2680
|
+
static VALUE rsctp_set_default_send_params(VALUE self, VALUE v_options){
|
2681
|
+
VALUE v_stream, v_ssn, v_flags, v_ppid, v_context, v_ttl, v_tsn, v_cumtsn, v_assoc_id;
|
2682
|
+
int fileno;
|
2683
|
+
sctp_assoc_t assoc_id;
|
2684
|
+
struct sctp_sndrcvinfo sndrcv;
|
2685
|
+
|
2686
|
+
if(!RB_TYPE_P(v_options, T_HASH))
|
2687
|
+
rb_raise(rb_eTypeError, "options must be a hash");
|
2688
|
+
|
2689
|
+
bzero(&sndrcv, sizeof(sndrcv));
|
2690
|
+
|
2691
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2692
|
+
|
2693
|
+
v_stream = rb_hash_aref2(v_options, "stream");
|
2694
|
+
v_ssn = rb_hash_aref2(v_options, "ssn");
|
2695
|
+
v_flags = rb_hash_aref2(v_options, "flags");
|
2696
|
+
v_ppid = rb_hash_aref2(v_options, "ppid");
|
2697
|
+
v_context = rb_hash_aref2(v_options, "context");
|
2698
|
+
v_ttl = rb_hash_aref2(v_options, "ttl");
|
2699
|
+
v_tsn = rb_hash_aref2(v_options, "tsn");
|
2700
|
+
v_cumtsn = rb_hash_aref2(v_options, "cumtsn");
|
2701
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
2702
|
+
|
2703
|
+
if(NIL_P(v_assoc_id))
|
2704
|
+
v_assoc_id = rb_iv_get(self, "@association_id");
|
2705
|
+
|
2706
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2707
|
+
sndrcv.sinfo_assoc_id = assoc_id;
|
2708
|
+
|
2709
|
+
if(!NIL_P(v_stream))
|
2710
|
+
sndrcv.sinfo_stream = NUM2INT(v_stream);
|
2711
|
+
|
2712
|
+
if(!NIL_P(v_ssn))
|
2713
|
+
sndrcv.sinfo_ssn = NUM2INT(v_ssn);
|
2714
|
+
|
2715
|
+
if(!NIL_P(v_flags))
|
2716
|
+
sndrcv.sinfo_flags = NUM2INT(v_flags);
|
2717
|
+
|
2718
|
+
if(!NIL_P(v_ppid))
|
2719
|
+
sndrcv.sinfo_ppid = NUM2INT(v_ppid);
|
2720
|
+
|
2721
|
+
if(!NIL_P(v_context))
|
2722
|
+
sndrcv.sinfo_context = NUM2INT(v_context);
|
2723
|
+
|
2724
|
+
if(!NIL_P(v_ttl))
|
2725
|
+
sndrcv.sinfo_timetolive = NUM2INT(v_ttl);
|
2726
|
+
|
2727
|
+
if(!NIL_P(v_tsn))
|
2728
|
+
sndrcv.sinfo_tsn = NUM2INT(v_tsn);
|
2729
|
+
|
2730
|
+
if(!NIL_P(v_cumtsn))
|
2731
|
+
sndrcv.sinfo_cumtsn = NUM2INT(v_cumtsn);
|
2732
|
+
|
2733
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_DEFAULT_SEND_PARAM, &sndrcv, sizeof(sndrcv)) < 0)
|
2734
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2735
|
+
|
2736
|
+
return rb_struct_new(
|
2737
|
+
v_sctp_default_send_params_struct,
|
2738
|
+
v_stream,
|
2739
|
+
v_ssn,
|
2740
|
+
v_flags,
|
2741
|
+
v_ppid,
|
2742
|
+
v_context,
|
2743
|
+
v_ttl,
|
2744
|
+
v_tsn,
|
2745
|
+
v_cumtsn,
|
2746
|
+
v_assoc_id
|
2747
|
+
);
|
2748
|
+
}
|
2749
|
+
|
2750
|
+
/*
|
2751
|
+
* call-seq:
|
2752
|
+
* SCTP::Socket#set_peer_address_params(options)
|
2753
|
+
*
|
2754
|
+
* Sets the peer address parameters. This allows applications to enable or
|
2755
|
+
* disable heartbeats for any peer address of an association, set the maximum
|
2756
|
+
* number of retransmissions to a destination address, and set the path MTU.
|
2757
|
+
*
|
2758
|
+
* The +options+ hash may contain the following keys:
|
2759
|
+
*
|
2760
|
+
* * association_id: The association identification
|
2761
|
+
* * address: The address of the remote peer
|
2762
|
+
* * hbinterval: The heartbeat interval (in milliseconds)
|
2763
|
+
* * pathmaxrxt: The maximum number of retransmissions
|
2764
|
+
* * pathmtu: The path MTU
|
2765
|
+
* * flags: Flags to control heartbeats, etc.
|
2766
|
+
* * ipv6_flowlabel: IPv6 flow label (only for IPv6 addresses)
|
2767
|
+
*
|
2768
|
+
* Example:
|
2769
|
+
*
|
2770
|
+
* socket.set_peer_address_params(:hbinterval => 5000, :pathmaxrxt => 5)
|
2771
|
+
*/
|
2772
|
+
static VALUE rsctp_set_peer_address_params(VALUE self, VALUE v_options){
|
2773
|
+
VALUE v_assoc_id, v_address, v_hbinterval, v_pathmaxrxt, v_pathmtu, v_flags, v_ipv6_flowlabel;
|
2774
|
+
int fileno;
|
2775
|
+
sctp_assoc_t assoc_id;
|
2776
|
+
struct sctp_paddrparams paddr;
|
2777
|
+
struct sockaddr_in* sin;
|
2778
|
+
|
2779
|
+
if(!RB_TYPE_P(v_options, T_HASH))
|
2780
|
+
rb_raise(rb_eTypeError, "options must be a hash");
|
2781
|
+
|
2782
|
+
bzero(&paddr, sizeof(paddr));
|
2783
|
+
|
2784
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
2785
|
+
|
2786
|
+
v_assoc_id = rb_hash_aref2(v_options, "association_id");
|
2787
|
+
v_address = rb_hash_aref2(v_options, "address");
|
2788
|
+
v_hbinterval = rb_hash_aref2(v_options, "hbinterval");
|
2789
|
+
v_pathmaxrxt = rb_hash_aref2(v_options, "pathmaxrxt");
|
2790
|
+
v_pathmtu = rb_hash_aref2(v_options, "pathmtu");
|
2791
|
+
v_flags = rb_hash_aref2(v_options, "flags");
|
2792
|
+
v_ipv6_flowlabel = rb_hash_aref2(v_options, "ipv6_flowlabel");
|
2793
|
+
|
2794
|
+
if(NIL_P(v_assoc_id))
|
2795
|
+
v_assoc_id = rb_iv_get(self, "@association_id");
|
2796
|
+
|
2797
|
+
assoc_id = NUM2INT(v_assoc_id);
|
2798
|
+
paddr.spp_assoc_id = assoc_id;
|
2799
|
+
|
2800
|
+
// If address is provided, set up the sockaddr structure
|
2801
|
+
if(!NIL_P(v_address)){
|
2802
|
+
sin = (struct sockaddr_in*)&paddr.spp_address;
|
2803
|
+
sin->sin_family = AF_INET;
|
2804
|
+
if(inet_pton(AF_INET, StringValueCStr(v_address), &sin->sin_addr) <= 0)
|
2805
|
+
rb_raise(rb_eArgError, "invalid IP address");
|
2806
|
+
}
|
2807
|
+
|
2808
|
+
if(!NIL_P(v_hbinterval))
|
2809
|
+
paddr.spp_hbinterval = NUM2INT(v_hbinterval);
|
2810
|
+
|
2811
|
+
if(!NIL_P(v_pathmaxrxt))
|
2812
|
+
paddr.spp_pathmaxrxt = NUM2INT(v_pathmaxrxt);
|
2813
|
+
|
2814
|
+
if(!NIL_P(v_pathmtu))
|
2815
|
+
paddr.spp_pathmtu = NUM2INT(v_pathmtu);
|
2816
|
+
|
2817
|
+
if(!NIL_P(v_flags))
|
2818
|
+
paddr.spp_flags = NUM2INT(v_flags);
|
2819
|
+
|
2820
|
+
if(!NIL_P(v_ipv6_flowlabel))
|
2821
|
+
paddr.spp_ipv6_flowlabel = NUM2INT(v_ipv6_flowlabel);
|
2822
|
+
|
2823
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &paddr, sizeof(paddr)) < 0)
|
2824
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
2825
|
+
|
2826
|
+
return rb_struct_new(
|
2827
|
+
v_sctp_peer_addr_params_struct,
|
2828
|
+
v_assoc_id,
|
2829
|
+
v_address,
|
2830
|
+
v_hbinterval,
|
2831
|
+
v_pathmaxrxt,
|
2832
|
+
v_pathmtu,
|
2833
|
+
v_flags,
|
2834
|
+
v_ipv6_flowlabel
|
2835
|
+
);
|
2836
|
+
}
|
2837
|
+
|
2385
2838
|
void Init_socket(void){
|
2386
2839
|
mSCTP = rb_define_module("SCTP");
|
2387
2840
|
cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
|
@@ -2485,23 +2938,26 @@ void Init_socket(void){
|
|
2485
2938
|
rb_define_method(cSocket, "autoclose=", rsctp_set_autoclose, 1);
|
2486
2939
|
rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
|
2487
2940
|
rb_define_method(cSocket, "close", rsctp_close, -1);
|
2941
|
+
rb_define_method(cSocket, "closed?", rsctp_closed_p, 0);
|
2488
2942
|
rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
|
2489
2943
|
rb_define_method(cSocket, "delete_shared_key", rsctp_delete_shared_key, -1);
|
2490
2944
|
rb_define_method(cSocket, "disable_fragments=", rsctp_disable_fragments, 1);
|
2491
2945
|
rb_define_method(cSocket, "enable_auth_support", rsctp_enable_auth_support, -1);
|
2946
|
+
rb_define_method(cSocket, "auth_support?", rsctp_get_auth_support, -1);
|
2492
2947
|
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1);
|
2493
2948
|
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1);
|
2494
2949
|
rb_define_method(cSocket, "get_active_shared_key", rsctp_get_active_shared_key, -1);
|
2495
2950
|
rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
|
2496
2951
|
rb_define_method(cSocket, "get_autoclose", rsctp_get_autoclose, 0);
|
2497
2952
|
rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
|
2498
|
-
rb_define_method(cSocket, "
|
2953
|
+
rb_define_method(cSocket, "get_init_msg", rsctp_get_init_msg, 0);
|
2499
2954
|
rb_define_method(cSocket, "get_peer_address_params", rsctp_get_peer_address_params, 0);
|
2500
2955
|
rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
|
2501
2956
|
rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
|
2502
2957
|
rb_define_method(cSocket, "get_subscriptions", rsctp_get_subscriptions, 0);
|
2503
2958
|
rb_define_method(cSocket, "listen", rsctp_listen, -1);
|
2504
2959
|
rb_define_method(cSocket, "map_ipv4=", rsctp_map_ipv4, 1);
|
2960
|
+
rb_define_method(cSocket, "map_ipv4?", rsctp_get_map_ipv4, 0);
|
2505
2961
|
rb_define_method(cSocket, "nodelay?", rsctp_get_nodelay, 0);
|
2506
2962
|
rb_define_method(cSocket, "nodelay=", rsctp_set_nodelay, 1);
|
2507
2963
|
rb_define_method(cSocket, "peeloff", rsctp_peeloff, 1);
|
@@ -2521,12 +2977,15 @@ void Init_socket(void){
|
|
2521
2977
|
rb_define_method(cSocket, "set_association_info", rsctp_set_association_info, 1);
|
2522
2978
|
rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
|
2523
2979
|
rb_define_method(cSocket, "set_retransmission_info", rsctp_set_retransmission_info, 1);
|
2980
|
+
rb_define_method(cSocket, "set_default_send_params", rsctp_set_default_send_params, 1);
|
2981
|
+
rb_define_method(cSocket, "set_peer_address_params", rsctp_set_peer_address_params, 1);
|
2524
2982
|
rb_define_method(cSocket, "set_shared_key", rsctp_set_shared_key, -1);
|
2525
2983
|
rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
|
2526
2984
|
rb_define_method(cSocket, "subscribe", rsctp_subscribe, 1);
|
2527
2985
|
|
2528
2986
|
rb_define_alias(cSocket, "get_rto_info", "get_retransmission_info");
|
2529
2987
|
rb_define_alias(cSocket, "set_rto_info", "set_retransmission_info");
|
2988
|
+
rb_define_alias(cSocket, "get_initmsg", "get_init_msg");
|
2530
2989
|
|
2531
2990
|
rb_define_attr(cSocket, "domain", 1, 1);
|
2532
2991
|
rb_define_attr(cSocket, "type", 1, 1);
|
@@ -2534,8 +2993,8 @@ void Init_socket(void){
|
|
2534
2993
|
rb_define_attr(cSocket, "association_id", 1, 1);
|
2535
2994
|
rb_define_attr(cSocket, "port", 1, 1);
|
2536
2995
|
|
2537
|
-
/* 0.
|
2538
|
-
rb_define_const(cSocket, "VERSION", rb_str_new2("0.1
|
2996
|
+
/* 0.2.0: The version of this library */
|
2997
|
+
rb_define_const(cSocket, "VERSION", rb_str_new2("0.2.1"));
|
2539
2998
|
|
2540
2999
|
/* send flags */
|
2541
3000
|
|
@@ -2574,4 +3033,34 @@ void Init_socket(void){
|
|
2574
3033
|
|
2575
3034
|
rb_define_const(cSocket, "SCTP_BINDX_ADD_ADDR", INT2NUM(SCTP_BINDX_ADD_ADDR));
|
2576
3035
|
rb_define_const(cSocket, "SCTP_BINDX_REM_ADDR", INT2NUM(SCTP_BINDX_REM_ADDR));
|
3036
|
+
|
3037
|
+
// PEER ADDRESS PARAMETER FLAGS //
|
3038
|
+
|
3039
|
+
#ifdef SPP_HB_ENABLE
|
3040
|
+
rb_define_const(cSocket, "SPP_HB_ENABLE", INT2NUM(SPP_HB_ENABLE));
|
3041
|
+
#endif
|
3042
|
+
#ifdef SPP_HB_DISABLE
|
3043
|
+
rb_define_const(cSocket, "SPP_HB_DISABLE", INT2NUM(SPP_HB_DISABLE));
|
3044
|
+
#endif
|
3045
|
+
#ifdef SPP_HB_DEMAND
|
3046
|
+
rb_define_const(cSocket, "SPP_HB_DEMAND", INT2NUM(SPP_HB_DEMAND));
|
3047
|
+
#endif
|
3048
|
+
#ifdef SPP_PMTUD_ENABLE
|
3049
|
+
rb_define_const(cSocket, "SPP_PMTUD_ENABLE", INT2NUM(SPP_PMTUD_ENABLE));
|
3050
|
+
#endif
|
3051
|
+
#ifdef SPP_PMTUD_DISABLE
|
3052
|
+
rb_define_const(cSocket, "SPP_PMTUD_DISABLE", INT2NUM(SPP_PMTUD_DISABLE));
|
3053
|
+
#endif
|
3054
|
+
|
3055
|
+
// PARTIAL RELIABILITY SCTP POLICY CONSTANTS //
|
3056
|
+
|
3057
|
+
#ifdef SCTP_PR_SCTP_TTL
|
3058
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_TTL", INT2NUM(SCTP_PR_SCTP_TTL));
|
3059
|
+
#endif
|
3060
|
+
#ifdef SCTP_PR_SCTP_RTX
|
3061
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_RTX", INT2NUM(SCTP_PR_SCTP_RTX));
|
3062
|
+
#endif
|
3063
|
+
#ifdef SCTP_PR_SCTP_BUF
|
3064
|
+
rb_define_const(cSocket, "SCTP_PR_SCTP_BUF", INT2NUM(SCTP_PR_SCTP_BUF));
|
3065
|
+
#endif
|
2577
3066
|
}
|