sctp-socket 0.0.5 → 0.0.7
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/FUNDING.yml +4 -0
- data/CHANGES.md +24 -0
- data/README.md +8 -7
- data/examples/client_example.rb +32 -2
- data/examples/server_example.rb +21 -1
- data/ext/sctp/extconf.rb +25 -1
- data/ext/sctp/socket.c +390 -132
- data/sctp-socket.gemspec +11 -1
- data.tar.gz.sig +0 -0
- metadata +12 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0475ccb484ff3e6e758c037edf11b16fdb833e49aee961a98532dfb67c84f799
|
4
|
+
data.tar.gz: 70f7add0defeeb84a1ab6bb38ed3aeabb5f643bb05dea06a00a11c1934f588ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5e40484afdf170570c38ab9331c99ae4a6f42ba217d97e91ecd5bfbf9296c2ef95f219498fba13b524ad08a1f00271de8be6f358f2982a4c5e45fdc190f0951
|
7
|
+
data.tar.gz: f9b9dac418aeae1c79916e732d7310049812c2456c0f4f1c578641f145c2c72b73fbceb655954ad99b03c3c69a890cab9a7455930199902a40aed9de239754a8
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/FUNDING.yml
ADDED
data/CHANGES.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
## 0.0.7 - 28-May-2024
|
2
|
+
* Added the recvv method.
|
3
|
+
* The getlocalnames and getpeernames methods now accept optional fileno and
|
4
|
+
association ID arguments.
|
5
|
+
* The peeloff method now returns the peeled off fileno and no longer modifies
|
6
|
+
the receiver, so I dropped the exclamation point from the method name.
|
7
|
+
* Added the get_subscriptions method.
|
8
|
+
* Changed bind method to bindx and connect method to connectx. I may try to
|
9
|
+
subclass Socket someday so I didn't want a conflict, and this more closely
|
10
|
+
matches the underlying function name anyway.
|
11
|
+
* Changed the sock_fd method to fileno.
|
12
|
+
* Changed the default backlog from 1024 to 128 for the listen method.
|
13
|
+
* Updated comments and documentation.
|
14
|
+
* Added more specs.
|
15
|
+
|
16
|
+
## 0.0.6 - 24-May-2024
|
17
|
+
* Fixup the sendv method and add some documentation.
|
18
|
+
* Added documentation to the get_status method.
|
19
|
+
* Update the example server and client code, including comments for how to
|
20
|
+
setup multiple dummy IP addresses locally for testing.
|
21
|
+
* Some warning cleanup and build improvements.
|
22
|
+
* Added SCTP_BINDX constants.
|
23
|
+
* Started adding some real specs.
|
24
|
+
|
1
25
|
## 0.0.5 - 15-Dec-2021
|
2
26
|
* Add handling for Linux platforms that don't support the sctp_sendv function
|
3
27
|
and/or the SCTP_SEND_FAILED_EVENT notification.
|
data/README.md
CHANGED
@@ -2,18 +2,20 @@
|
|
2
2
|
|
3
3
|
A Ruby interface for SCTP sockets.
|
4
4
|
|
5
|
-
WARNING: THIS IS CURRENTLY AN ALPHA PRODUCT. NOT RECOMMENDED FOR PRODUCTION USE AT THIS TIME.
|
6
|
-
|
7
5
|
## Prerequisites
|
8
6
|
|
9
7
|
You will need the sctp development headers installed.
|
10
8
|
|
11
|
-
On some systems, such as RHEL8, you may need to enable the sctp module.
|
9
|
+
On some systems, such as RHEL8 or later, you may need to enable the sctp module.
|
12
10
|
|
13
11
|
## Installation
|
14
12
|
|
15
13
|
`gem install sctp-socket`
|
16
14
|
|
15
|
+
## Installing the Trusted Cert
|
16
|
+
|
17
|
+
`gem cert --add <(curl -Ls https://raw.githubusercontent.com/djberg96/sctp-socket/main/certs/djberg96_pub.pem)`
|
18
|
+
|
17
19
|
## About SCTP
|
18
20
|
|
19
21
|
The Stream Control Transmission Protocol (SCTP) is a message oriented, reliable
|
@@ -37,7 +39,7 @@ require 'sctp/socket'
|
|
37
39
|
begin
|
38
40
|
port = 62324
|
39
41
|
socket = SCTP::Socket.new
|
40
|
-
socket.
|
42
|
+
socket.bindx(:port => port, :addresses => ['10.0.5.4', '10.0.6.4'])
|
41
43
|
socket.set_initmsg(:output_streams => 5, :input_streams => 5, :max_attempts => 4)
|
42
44
|
socket.subscribe(:data_io => true)
|
43
45
|
socket.listen
|
@@ -62,8 +64,7 @@ end
|
|
62
64
|
Currently this has only been developed and tested on Linux. Other platforms
|
63
65
|
will probably only be supported via community contributions.
|
64
66
|
|
65
|
-
|
66
|
-
available. Use the sendmsg method instead.
|
67
|
+
The sendv method is not available on some Linux variants. Use the sendmsg method instead.
|
67
68
|
|
68
69
|
Please report any issues on the github project page.
|
69
70
|
|
@@ -81,7 +82,7 @@ Apache-2.0
|
|
81
82
|
|
82
83
|
## Copyright
|
83
84
|
|
84
|
-
(C) 2020, Daniel J. Berger
|
85
|
+
(C) 2020-2024, Daniel J. Berger
|
85
86
|
Al Rights Reserved
|
86
87
|
|
87
88
|
## Author
|
data/examples/client_example.rb
CHANGED
@@ -1,11 +1,41 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'sctp/socket'
|
3
3
|
|
4
|
+
# Adjust as needed. Server server_example.rb for creating
|
5
|
+
# fake network interfaces for testing.
|
6
|
+
addresses = ['1.1.1.1', '1.1.1.2']
|
7
|
+
|
4
8
|
begin
|
5
9
|
port = 62324
|
6
10
|
socket = SCTP::Socket.new
|
7
|
-
|
8
|
-
|
11
|
+
|
12
|
+
# Optional, but could bind to a subset of available addresses
|
13
|
+
p socket.bindx(:addresses => addresses)
|
14
|
+
|
15
|
+
# Initial connection
|
16
|
+
p socket.connectx(:addresses => addresses, :port => port)
|
17
|
+
p socket.get_status
|
18
|
+
|
19
|
+
# Try a sendv
|
20
|
+
p socket.sendv(:message => ["Hello ", "World!"])
|
21
|
+
|
22
|
+
# Send messages on separate streams of the same connection
|
23
|
+
arr = []
|
24
|
+
|
25
|
+
0.upto(4) do |n|
|
26
|
+
arr << Thread.new do |t|
|
27
|
+
puts "Stream: #{n}"
|
28
|
+
bytes_sent = socket.sendmsg(
|
29
|
+
:message => "Hello World: #{n+1}",
|
30
|
+
:addresses => addresses.shuffle,
|
31
|
+
:stream => n,
|
32
|
+
:port => port
|
33
|
+
)
|
34
|
+
puts "Bytes Sent: #{bytes_sent}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
arr.map(&:join)
|
9
39
|
ensure
|
10
40
|
socket.close if socket
|
11
41
|
end
|
data/examples/server_example.rb
CHANGED
@@ -1,11 +1,31 @@
|
|
1
1
|
require 'sctp/socket'
|
2
2
|
|
3
|
+
# rake compile + ruby -Ilib to run local version
|
4
|
+
puts "VERSION: #{SCTP::Socket::VERSION}"
|
5
|
+
|
6
|
+
# To test multiple IP addresses locally:
|
7
|
+
#
|
8
|
+
# sudo apt install iproute2
|
9
|
+
# Add 'dummy' to /etc/modules
|
10
|
+
#
|
11
|
+
# sudo ip link add dummy1 type dummy
|
12
|
+
# sudo ip link add dummy2 type dummy
|
13
|
+
#
|
14
|
+
# sudo ip addr add 1.1.1.1/24 dev dummy1
|
15
|
+
# sudo ip addr add 1.1.1.2/24 dev dummy2
|
16
|
+
#
|
17
|
+
# sudo ip link set dummy1 up
|
18
|
+
# sudo ip link set dummy2 up
|
19
|
+
|
3
20
|
# Adjust IP addresses as needed
|
21
|
+
addresses = ['1.1.1.1', '1.1.1.2']
|
22
|
+
|
4
23
|
begin
|
5
24
|
port = 62324
|
6
25
|
socket = SCTP::Socket.new
|
7
|
-
socket.
|
26
|
+
socket.bindx(:port => port, :addresses => addresses)
|
8
27
|
socket.set_initmsg(:output_streams => 5, :input_streams => 5, :max_attempts => 4)
|
28
|
+
socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true, :partial_delivery => true)
|
9
29
|
socket.listen
|
10
30
|
|
11
31
|
while true
|
data/ext/sctp/extconf.rb
CHANGED
@@ -1,7 +1,31 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
|
3
|
+
dir_config('sctp')
|
4
|
+
|
5
|
+
unless have_header('netinet/sctp.h')
|
6
|
+
os = IO.readlines('/etc/os-release').first.split('=').last
|
7
|
+
msg = "\nSCTP HEADERS NOT FOUND. PLEASE INSTALL THEM FIRST LIKE SO:\n\n"
|
8
|
+
|
9
|
+
if os =~ /red|fedora|centos/i
|
10
|
+
msg << "#####################################################################################\n"
|
11
|
+
msg << "# dnf install lksctp-tools #\n"
|
12
|
+
msg << "# dnf install kernel-modules-extra #\n"
|
13
|
+
msg << "# #\n"
|
14
|
+
msg << "# sed -e '/blacklist sctp/s/^b/#b/g' -i /etc/modprobe.d/sctp-blacklist.conf #\n"
|
15
|
+
msg << "# sed -e '/blacklist sctp/s/^b/#b/g' -i /etc/modprobe.d/sctp_diag-blacklist.conf #\n"
|
16
|
+
msg << "# #\n"
|
17
|
+
msg << "# sudo systemctl restart systemd-modules-load.service #\n"
|
18
|
+
msg << "#####################################################################################\n"
|
19
|
+
else
|
20
|
+
msg << "sudo apt-get install libsctp-dev lksctp-tools\n\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
warn msg
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
|
4
27
|
have_library('sctp')
|
5
28
|
have_func('sctp_sendv', 'netinet/sctp.h')
|
29
|
+
have_func('sctp_recvv', 'netinet/sctp.h')
|
6
30
|
have_struct_member('struct sctp_event_subscribe', 'sctp_send_failure_event', 'netinet/sctp.h')
|
7
31
|
create_makefile('sctp/socket')
|
data/ext/sctp/socket.c
CHANGED
@@ -21,32 +21,17 @@ VALUE v_sctp_status_struct;
|
|
21
21
|
VALUE v_sctp_rtoinfo_struct;
|
22
22
|
VALUE v_sctp_associnfo_struct;
|
23
23
|
VALUE v_sctp_default_send_params_struct;
|
24
|
+
VALUE v_sctp_event_subscribe_struct;
|
25
|
+
VALUE v_sctp_receive_info_struct;
|
24
26
|
|
25
27
|
#if !defined(IOV_MAX)
|
26
28
|
#if defined(_SC_IOV_MAX)
|
27
29
|
#define IOV_MAX (sysconf(_SC_IOV_MAX))
|
28
30
|
#else
|
29
|
-
// Assume infinity, or let the syscall return with error
|
30
31
|
#define IOV_MAX INT_MAX
|
31
32
|
#endif
|
32
33
|
#endif
|
33
34
|
|
34
|
-
#define ARY2IOVEC(iov,ary) \
|
35
|
-
do { \
|
36
|
-
VALUE *cur; \
|
37
|
-
struct iovec *tmp; \
|
38
|
-
long n; \
|
39
|
-
cur = RARRAY_PTR(ary); \
|
40
|
-
n = RARRAY_LEN(ary); \
|
41
|
-
iov = tmp = alloca(sizeof(struct iovec) * n); \
|
42
|
-
for (; --n >= 0; tmp++, cur++) { \
|
43
|
-
if (TYPE(*cur) != T_STRING) \
|
44
|
-
rb_raise(rb_eArgError, "must be an array of strings"); \
|
45
|
-
tmp->iov_base = RSTRING_PTR(*cur); \
|
46
|
-
tmp->iov_len = RSTRING_LEN(*cur); \
|
47
|
-
} \
|
48
|
-
} while (0)
|
49
|
-
|
50
35
|
// TODO: Yes, I know I need to update the signature.
|
51
36
|
VALUE convert_sockaddr_in_to_struct(struct sockaddr_in* addr){
|
52
37
|
char ipbuf[INET6_ADDRSTRLEN];
|
@@ -94,7 +79,7 @@ VALUE rb_hash_aref2(VALUE v_hash, const char* key){
|
|
94
79
|
* socket2 = SCTP::Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
|
95
80
|
*/
|
96
81
|
static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
97
|
-
int
|
82
|
+
int fileno;
|
98
83
|
VALUE v_domain, v_type;
|
99
84
|
|
100
85
|
rb_scan_args(argc, argv, "02", &v_domain, &v_type);
|
@@ -105,14 +90,14 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
105
90
|
if(NIL_P(v_type))
|
106
91
|
v_type = INT2NUM(SOCK_SEQPACKET);
|
107
92
|
|
108
|
-
|
93
|
+
fileno = socket(NUM2INT(v_domain), NUM2INT(v_type), IPPROTO_SCTP);
|
109
94
|
|
110
|
-
if(
|
95
|
+
if(fileno < 0)
|
111
96
|
rb_raise(rb_eSystemCallError, "socket: %s", strerror(errno));
|
112
97
|
|
113
98
|
rb_iv_set(self, "@domain", v_domain);
|
114
99
|
rb_iv_set(self, "@type", v_type);
|
115
|
-
rb_iv_set(self, "@
|
100
|
+
rb_iv_set(self, "@fileno", INT2NUM(fileno));
|
116
101
|
rb_iv_set(self, "@association_id", INT2NUM(0));
|
117
102
|
|
118
103
|
return self;
|
@@ -131,19 +116,19 @@ static VALUE rsctp_init(int argc, VALUE* argv, VALUE self){
|
|
131
116
|
* socket = SCTP::Socket.new
|
132
117
|
*
|
133
118
|
* # Bind 2 addresses
|
134
|
-
* socket.
|
119
|
+
* socket.bindx(:port => 64325, :addresses => ['10.0.4.5', '10.0.5.5'])
|
135
120
|
*
|
136
121
|
* # Remove 1 later
|
137
|
-
* socket.
|
122
|
+
* socket.bindx(:addresses => ['10.0.4.5'], :flags => SCTP::Socket::BINDX_REM_ADDR)
|
138
123
|
*
|
139
124
|
* If no addresses are specified, then it will bind to all available interfaces. If
|
140
125
|
* no port is specified, then one will be assigned by the host.
|
141
126
|
*
|
142
127
|
* Returns the port that it was bound to.
|
143
128
|
*/
|
144
|
-
static VALUE
|
129
|
+
static VALUE rsctp_bindx(int argc, VALUE* argv, VALUE self){
|
145
130
|
struct sockaddr_in addrs[8];
|
146
|
-
int i,
|
131
|
+
int i, fileno, num_ip, flags, domain, port;
|
147
132
|
VALUE v_addresses, v_port, v_flags, v_address, v_options;
|
148
133
|
|
149
134
|
rb_scan_args(argc, argv, "01", &v_options);
|
@@ -173,7 +158,7 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
173
158
|
num_ip = RARRAY_LEN(v_addresses);
|
174
159
|
|
175
160
|
domain = NUM2INT(rb_iv_get(self, "@domain"));
|
176
|
-
|
161
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
177
162
|
|
178
163
|
if(num_ip > 1){
|
179
164
|
for(i = 0; i < num_ip; i++){
|
@@ -189,19 +174,21 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
189
174
|
addrs[0].sin_addr.s_addr = htonl(INADDR_ANY);
|
190
175
|
}
|
191
176
|
|
192
|
-
if(sctp_bindx(
|
177
|
+
if(sctp_bindx(fileno, (struct sockaddr *) addrs, num_ip, flags) != 0)
|
193
178
|
rb_raise(rb_eSystemCallError, "sctp_bindx: %s", strerror(errno));
|
194
179
|
|
195
180
|
if(port == 0){
|
196
181
|
struct sockaddr_in sin;
|
197
182
|
socklen_t len = sizeof(sin);
|
198
183
|
|
199
|
-
if(getsockname(
|
184
|
+
if(getsockname(fileno, (struct sockaddr *)&sin, &len) == -1)
|
200
185
|
rb_raise(rb_eSystemCallError, "getsockname: %s", strerror(errno));
|
201
186
|
|
202
187
|
port = sin.sin_port;
|
203
188
|
}
|
204
189
|
|
190
|
+
rb_iv_set(self, "@port", INT2NUM(port));
|
191
|
+
|
205
192
|
return INT2NUM(port);
|
206
193
|
}
|
207
194
|
|
@@ -212,13 +199,13 @@ static VALUE rsctp_bind(int argc, VALUE* argv, VALUE self){
|
|
212
199
|
* Example:
|
213
200
|
*
|
214
201
|
* socket = SCTP::Socket.new
|
215
|
-
* socket.
|
202
|
+
* socket.connectx(:port => 62354, :addresses => ['10.0.4.5', '10.0.5.5'])
|
216
203
|
*
|
217
204
|
* Note that this will also set/update the object's association_id.
|
218
205
|
*/
|
219
|
-
static VALUE
|
206
|
+
static VALUE rsctp_connectx(int argc, VALUE* argv, VALUE self){
|
220
207
|
struct sockaddr_in addrs[8];
|
221
|
-
int i, num_ip,
|
208
|
+
int i, num_ip, fileno;
|
222
209
|
sctp_assoc_t assoc;
|
223
210
|
VALUE v_address, v_domain, v_options, v_addresses, v_port;
|
224
211
|
|
@@ -250,9 +237,9 @@ static VALUE rsctp_connect(int argc, VALUE* argv, VALUE self){
|
|
250
237
|
addrs[i].sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
|
251
238
|
}
|
252
239
|
|
253
|
-
|
240
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
254
241
|
|
255
|
-
if(sctp_connectx(
|
242
|
+
if(sctp_connectx(fileno, (struct sockaddr *) addrs, num_ip, &assoc) < 0)
|
256
243
|
rb_raise(rb_eSystemCallError, "sctp_connectx: %s", strerror(errno));
|
257
244
|
|
258
245
|
rb_iv_set(self, "@association_id", INT2NUM(assoc));
|
@@ -269,30 +256,55 @@ static VALUE rsctp_connect(int argc, VALUE* argv, VALUE self){
|
|
269
256
|
* socket.close
|
270
257
|
*/
|
271
258
|
static VALUE rsctp_close(VALUE self){
|
272
|
-
VALUE
|
259
|
+
VALUE v_fileno = rb_iv_get(self, "@fileno");
|
273
260
|
|
274
|
-
if(close(NUM2INT(
|
261
|
+
if(close(NUM2INT(v_fileno)))
|
275
262
|
rb_raise(rb_eSystemCallError, "close: %s", strerror(errno));
|
276
263
|
|
277
264
|
return self;
|
278
265
|
}
|
279
266
|
|
280
267
|
/*
|
281
|
-
* Return an array of all addresses of a peer
|
268
|
+
* Return an array of all addresses of a peer of the current socket
|
269
|
+
* and association number.
|
270
|
+
*
|
271
|
+
* You may optionally pass a assocation fileno and association ID. Typically
|
272
|
+
* this information would come from the peeloff method.
|
273
|
+
*
|
274
|
+
* Example:
|
275
|
+
*
|
276
|
+
* socket = SCTP::Socket.new
|
277
|
+
* # ...
|
278
|
+
* p socket.getpeernames
|
279
|
+
*
|
280
|
+
* info = socket.recvmsg
|
281
|
+
* association_fileno = socket.peeloff(info.association_id)
|
282
|
+
*
|
283
|
+
* p socket.getpeernames(association_fileno, info.association_id)
|
282
284
|
*/
|
283
|
-
static VALUE rsctp_getpeernames(VALUE self){
|
285
|
+
static VALUE rsctp_getpeernames(int argc, VALUE* argv, VALUE self){
|
284
286
|
sctp_assoc_t assoc_id;
|
285
287
|
struct sockaddr* addrs;
|
286
|
-
int i,
|
288
|
+
int i, fileno, num_addrs;
|
287
289
|
char str[16];
|
290
|
+
VALUE v_fileno, v_association_id;
|
288
291
|
VALUE v_array = rb_ary_new();
|
289
292
|
|
290
293
|
bzero(&addrs, sizeof(addrs));
|
291
294
|
|
292
|
-
|
293
|
-
|
295
|
+
rb_scan_args(argc, argv, "02", &v_fileno, &v_association_id);
|
296
|
+
|
297
|
+
if(NIL_P(v_fileno))
|
298
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
299
|
+
else
|
300
|
+
fileno = NUM2INT(v_fileno);
|
294
301
|
|
295
|
-
|
302
|
+
if(NIL_P(v_association_id))
|
303
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
304
|
+
else
|
305
|
+
assoc_id = NUM2INT(v_association_id);
|
306
|
+
|
307
|
+
num_addrs = sctp_getpaddrs(fileno, assoc_id, &addrs);
|
296
308
|
|
297
309
|
if(num_addrs < 0){
|
298
310
|
sctp_freepaddrs(addrs);
|
@@ -318,20 +330,35 @@ static VALUE rsctp_getpeernames(VALUE self){
|
|
318
330
|
* socket = SCTP::Socket.new
|
319
331
|
* socket.bind(:addresses => ['10.0.4.5', '10.0.5.5'])
|
320
332
|
* socket.getlocalnames # => ['10.0.4.5', '10.0.5.5'])
|
333
|
+
*
|
334
|
+
* # or get info from a peeled off association...
|
335
|
+
*
|
336
|
+
* assoc_fileno = socket.peeloff(some_association_id)
|
337
|
+
* socket.getlocalnames(assoc_fileno, some_association_id)
|
321
338
|
*/
|
322
|
-
static VALUE rsctp_getlocalnames(VALUE self){
|
339
|
+
static VALUE rsctp_getlocalnames(int argc, VALUE* argv, VALUE self){
|
323
340
|
sctp_assoc_t assoc_id;
|
324
341
|
struct sockaddr* addrs;
|
325
|
-
int i,
|
342
|
+
int i, fileno, num_addrs;
|
326
343
|
char str[16];
|
344
|
+
VALUE v_assoc_fileno, v_assoc_id;
|
327
345
|
VALUE v_array = rb_ary_new();
|
328
346
|
|
329
347
|
bzero(&addrs, sizeof(addrs));
|
330
348
|
|
331
|
-
|
332
|
-
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
349
|
+
rb_scan_args(argc, argv, "02", &v_assoc_fileno, &v_assoc_id);
|
333
350
|
|
334
|
-
|
351
|
+
if(NIL_P(v_assoc_fileno))
|
352
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
353
|
+
else
|
354
|
+
fileno = NUM2INT(v_assoc_fileno);
|
355
|
+
|
356
|
+
if(NIL_P(v_assoc_id))
|
357
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
358
|
+
else
|
359
|
+
assoc_id = NUM2INT(v_assoc_id);
|
360
|
+
|
361
|
+
num_addrs = sctp_getladdrs(fileno, assoc_id, &addrs);
|
335
362
|
|
336
363
|
if(num_addrs < 0){
|
337
364
|
sctp_freeladdrs(addrs);
|
@@ -350,19 +377,58 @@ static VALUE rsctp_getlocalnames(VALUE self){
|
|
350
377
|
}
|
351
378
|
|
352
379
|
#ifdef HAVE_SCTP_SENDV
|
353
|
-
|
354
|
-
|
355
|
-
|
380
|
+
/*
|
381
|
+
* Transmit a message to an SCTP endpoint using a gather-write. The following
|
382
|
+
* hash of options is permitted:
|
383
|
+
*
|
384
|
+
* * message - An array of strings that will be joined into a single message.
|
385
|
+
* * addresses - An array of IP addresses to setup an association to send the message.
|
386
|
+
* * info_type - The type of information provided. The default is SCTP_SENDV_SNDINFO.
|
387
|
+
*
|
388
|
+
* Example:
|
389
|
+
*
|
390
|
+
* socket = SCTP::Socket.new
|
391
|
+
*
|
392
|
+
* socket.sendv
|
393
|
+
* :message => ['Hello ', 'World.'],
|
394
|
+
* :addresses => ['10.0.5.4', '10.0.6.4'],
|
395
|
+
* :info_type => SCTP::Socket:::SCTP_SENDV_SNDINFO
|
396
|
+
* )
|
397
|
+
*
|
398
|
+
* CAVEAT: Currently addresses does not work, and info_type is not yet supported.
|
399
|
+
*
|
400
|
+
* Returns the number of bytes sent.
|
401
|
+
*/
|
402
|
+
static VALUE rsctp_sendv(VALUE self, VALUE v_options){
|
403
|
+
VALUE v_msg, v_message, v_addresses;
|
404
|
+
struct iovec iov[IOV_MAX];
|
405
|
+
struct sockaddr_in* addrs;
|
356
406
|
struct sctp_sndinfo info;
|
357
|
-
int
|
407
|
+
int i, fileno, num_bytes, size, num_ip;
|
358
408
|
|
359
|
-
Check_Type(
|
360
|
-
|
409
|
+
Check_Type(v_options, T_HASH);
|
410
|
+
|
411
|
+
bzero(&iov, sizeof(iov));
|
412
|
+
bzero(&info, sizeof(info));
|
413
|
+
|
414
|
+
v_message = rb_hash_aref2(v_options, "message");
|
415
|
+
v_addresses = rb_hash_aref2(v_options, "addresses");
|
361
416
|
|
362
|
-
|
417
|
+
if(!NIL_P(v_message))
|
418
|
+
Check_Type(v_message, T_ARRAY);
|
419
|
+
|
420
|
+
if(!NIL_P(v_addresses)){
|
421
|
+
Check_Type(v_addresses, T_ARRAY);
|
422
|
+
num_ip = RARRAY_LEN(v_addresses);
|
423
|
+
addrs = (struct sockaddr_in*)alloca(sizeof(struct sockaddr_in) * num_ip);
|
424
|
+
}
|
425
|
+
else{
|
426
|
+
addrs = NULL;
|
427
|
+
num_ip = 0;
|
428
|
+
}
|
363
429
|
|
364
|
-
|
365
|
-
size = RARRAY_LEN(
|
430
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
431
|
+
size = RARRAY_LEN(v_message);
|
366
432
|
|
367
433
|
if(!size)
|
368
434
|
rb_raise(rb_eArgError, "Must contain at least one message");
|
@@ -370,17 +436,41 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_messages){
|
|
370
436
|
if(size > IOV_MAX)
|
371
437
|
rb_raise(rb_eArgError, "Array size is greater than IOV_MAX");
|
372
438
|
|
373
|
-
ARY2IOVEC(iov, v_messages);
|
374
|
-
|
375
439
|
info.snd_flags = SCTP_UNORDERED;
|
376
440
|
info.snd_assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
377
441
|
|
442
|
+
if(!NIL_P(v_addresses)){
|
443
|
+
int i, port;
|
444
|
+
VALUE v_address, v_port;
|
445
|
+
|
446
|
+
v_port = NUM2INT(rb_iv_get(self, "@port"));
|
447
|
+
|
448
|
+
if(NIL_P(v_port))
|
449
|
+
port = 0;
|
450
|
+
else
|
451
|
+
port = NUM2INT(v_port);
|
452
|
+
|
453
|
+
for(i = 0; i < num_ip; i++){
|
454
|
+
v_address = RARRAY_PTR(v_addresses)[i];
|
455
|
+
addrs->sin_family = NUM2INT(rb_iv_get(self, "@domain"));
|
456
|
+
addrs->sin_port = htons(port);
|
457
|
+
addrs->sin_addr.s_addr = inet_addr(StringValueCStr(v_address));
|
458
|
+
addrs += sizeof(struct sockaddr_in);
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
for(i = 0; i < size; i++){
|
463
|
+
v_msg = RARRAY_PTR(v_message)[i];
|
464
|
+
iov[i].iov_base = StringValueCStr(v_msg);
|
465
|
+
iov[i].iov_len = RSTRING_LEN(v_msg);
|
466
|
+
}
|
467
|
+
|
378
468
|
num_bytes = sctp_sendv(
|
379
|
-
|
469
|
+
fileno,
|
380
470
|
iov,
|
381
471
|
size,
|
382
|
-
|
383
|
-
|
472
|
+
(struct sockaddr*)addrs,
|
473
|
+
num_ip,
|
384
474
|
&info,
|
385
475
|
sizeof(info),
|
386
476
|
SCTP_SENDV_SNDINFO,
|
@@ -394,6 +484,74 @@ static VALUE rsctp_sendv(VALUE self, VALUE v_messages){
|
|
394
484
|
}
|
395
485
|
#endif
|
396
486
|
|
487
|
+
#ifdef HAVE_SCTP_RECVV
|
488
|
+
static VALUE rsctp_recvv(int argc, VALUE* argv, VALUE self){
|
489
|
+
VALUE v_flags;
|
490
|
+
int fileno, flags, bytes, on;
|
491
|
+
uint infotype;
|
492
|
+
socklen_t infolen;
|
493
|
+
struct iovec iov[1];
|
494
|
+
struct sctp_rcvinfo info;
|
495
|
+
char buffer[1024];
|
496
|
+
|
497
|
+
bzero(&iov, sizeof(iov));
|
498
|
+
bzero(&info, sizeof(info));
|
499
|
+
bzero(&buffer, sizeof(buffer));
|
500
|
+
|
501
|
+
iov->iov_base = buffer;
|
502
|
+
iov->iov_len = sizeof(buffer);
|
503
|
+
|
504
|
+
rb_scan_args(argc, argv, "01", &v_flags);
|
505
|
+
|
506
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
507
|
+
|
508
|
+
if(NIL_P(v_flags))
|
509
|
+
flags = 0;
|
510
|
+
else
|
511
|
+
flags = NUM2INT(v_flags);
|
512
|
+
|
513
|
+
on = 1;
|
514
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof(on)) < 0)
|
515
|
+
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
516
|
+
|
517
|
+
infolen = sizeof(struct sctp_rcvinfo);
|
518
|
+
infotype = 0;
|
519
|
+
|
520
|
+
bytes = sctp_recvv(
|
521
|
+
fileno,
|
522
|
+
iov,
|
523
|
+
1,
|
524
|
+
NULL,
|
525
|
+
NULL,
|
526
|
+
&info,
|
527
|
+
&infolen,
|
528
|
+
&infotype,
|
529
|
+
&flags
|
530
|
+
);
|
531
|
+
|
532
|
+
if(bytes < 0)
|
533
|
+
rb_raise(rb_eSystemCallError, "sctp_recvv: %s", strerror(errno));
|
534
|
+
|
535
|
+
if(infotype != SCTP_RECVV_RCVINFO){
|
536
|
+
return Qnil;
|
537
|
+
}
|
538
|
+
else{
|
539
|
+
return rb_struct_new(
|
540
|
+
v_sctp_receive_info_struct,
|
541
|
+
rb_str_new2(iov->iov_base),
|
542
|
+
UINT2NUM(info.rcv_sid),
|
543
|
+
UINT2NUM(info.rcv_ssn),
|
544
|
+
UINT2NUM(info.rcv_flags),
|
545
|
+
UINT2NUM(info.rcv_ppid),
|
546
|
+
UINT2NUM(info.rcv_tsn),
|
547
|
+
UINT2NUM(info.rcv_cumtsn),
|
548
|
+
UINT2NUM(info.rcv_context),
|
549
|
+
UINT2NUM(info.rcv_assoc_id)
|
550
|
+
);
|
551
|
+
}
|
552
|
+
}
|
553
|
+
#endif
|
554
|
+
|
397
555
|
/*
|
398
556
|
* Send a message on an already-connected socket to a specific association.
|
399
557
|
*
|
@@ -410,7 +568,7 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
410
568
|
uint16_t stream;
|
411
569
|
uint32_t ppid, send_flags, ctrl_flags, ttl, context;
|
412
570
|
ssize_t num_bytes;
|
413
|
-
int
|
571
|
+
int fileno;
|
414
572
|
sctp_assoc_t assoc_id;
|
415
573
|
struct sctp_sndrcvinfo info;
|
416
574
|
VALUE v_msg, v_stream, v_ppid, v_context, v_send_flags, v_ctrl_flags, v_ttl, v_assoc_id;
|
@@ -471,10 +629,10 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
471
629
|
info.sinfo_timetolive = ttl;
|
472
630
|
info.sinfo_assoc_id = assoc_id;
|
473
631
|
|
474
|
-
|
632
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
475
633
|
|
476
634
|
num_bytes = sctp_send(
|
477
|
-
|
635
|
+
fileno,
|
478
636
|
StringValueCStr(v_msg),
|
479
637
|
RSTRING_LEN(v_msg),
|
480
638
|
&info,
|
@@ -491,14 +649,14 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
491
649
|
* Transmit a message to an SCTP endpoint. The following hash of options
|
492
650
|
* is permitted:
|
493
651
|
*
|
494
|
-
* :message
|
495
|
-
* :stream
|
496
|
-
* :
|
497
|
-
* :context
|
498
|
-
* :ppid
|
499
|
-
* :flags
|
652
|
+
* :message -> The message to send to the endpoint. Mandatory.
|
653
|
+
* :stream -> The SCTP stream number you wish to send the message on.
|
654
|
+
* :addresses -> An array of addresses to send the message to.
|
655
|
+
* :context -> The default context used for the sendmsg call if the send fails.
|
656
|
+
* :ppid -> The payload protocol identifier that is passed to the peer endpoint.
|
657
|
+
* :flags -> A bitwise integer that contain one or more values that control behavior.
|
500
658
|
*
|
501
|
-
* Note that the :
|
659
|
+
* Note that the :addresses option is not mandatory in a one-to-one (SOCK_STREAM)
|
502
660
|
* socket connection. However, it must have been set previously via the
|
503
661
|
* connect method.
|
504
662
|
*
|
@@ -507,12 +665,14 @@ static VALUE rsctp_send(VALUE self, VALUE v_options){
|
|
507
665
|
* socket = SCTP::Socket.new
|
508
666
|
*
|
509
667
|
* socket.sendmsg(
|
510
|
-
* :message
|
511
|
-
* :stream
|
512
|
-
* :flags
|
513
|
-
* :ttl
|
514
|
-
* :
|
668
|
+
* :message => "Hello World!",
|
669
|
+
* :stream => 3,
|
670
|
+
* :flags => SCTP::Socket::SCTP_UNORDERED | SCTP::Socket::SCTP_SENDALL,
|
671
|
+
* :ttl => 100,
|
672
|
+
* :addresses => ['10.0.5.4', '10.0.6.4']
|
515
673
|
* )
|
674
|
+
*
|
675
|
+
* Returns the number of bytes sent.
|
516
676
|
*/
|
517
677
|
static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
518
678
|
VALUE v_msg, v_ppid, v_flags, v_stream, v_ttl, v_context, v_addresses;
|
@@ -520,7 +680,7 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
520
680
|
uint32_t ppid, flags, ttl, context;
|
521
681
|
ssize_t num_bytes;
|
522
682
|
struct sockaddr_in addrs[8];
|
523
|
-
int
|
683
|
+
int fileno, size;
|
524
684
|
|
525
685
|
Check_Type(v_options, T_HASH);
|
526
686
|
|
@@ -587,10 +747,10 @@ static VALUE rsctp_sendmsg(VALUE self, VALUE v_options){
|
|
587
747
|
size = 0;
|
588
748
|
}
|
589
749
|
|
590
|
-
|
750
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
591
751
|
|
592
752
|
num_bytes = sctp_sendmsg(
|
593
|
-
|
753
|
+
fileno,
|
594
754
|
StringValueCStr(v_msg),
|
595
755
|
RSTRING_LEN(v_msg),
|
596
756
|
(struct sockaddr*)addrs,
|
@@ -631,7 +791,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
631
791
|
VALUE v_flags, v_notification, v_message;
|
632
792
|
struct sctp_sndrcvinfo sndrcvinfo;
|
633
793
|
struct sockaddr_in clientaddr;
|
634
|
-
int flags, bytes,
|
794
|
+
int flags, bytes, fileno;
|
635
795
|
char buffer[1024]; // TODO: Let this be configurable?
|
636
796
|
socklen_t length;
|
637
797
|
|
@@ -642,12 +802,15 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
642
802
|
else
|
643
803
|
flags = NUM2INT(v_flags);
|
644
804
|
|
645
|
-
|
805
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
646
806
|
length = sizeof(struct sockaddr_in);
|
807
|
+
|
647
808
|
bzero(buffer, sizeof(buffer));
|
809
|
+
bzero(&clientaddr, sizeof(clientaddr));
|
810
|
+
bzero(&sndrcvinfo, sizeof(sndrcvinfo));
|
648
811
|
|
649
812
|
bytes = sctp_recvmsg(
|
650
|
-
|
813
|
+
fileno,
|
651
814
|
buffer,
|
652
815
|
sizeof(buffer),
|
653
816
|
(struct sockaddr*)&clientaddr,
|
@@ -870,7 +1033,7 @@ static VALUE rsctp_recvmsg(int argc, VALUE* argv, VALUE self){
|
|
870
1033
|
* By default these values are set to zero (i.e. ignored).
|
871
1034
|
*/
|
872
1035
|
static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
873
|
-
int
|
1036
|
+
int fileno;
|
874
1037
|
struct sctp_initmsg initmsg;
|
875
1038
|
VALUE v_output, v_input, v_attempts, v_timeout;
|
876
1039
|
|
@@ -881,7 +1044,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
881
1044
|
v_attempts = rb_hash_aref2(v_options, "max_attempts");
|
882
1045
|
v_timeout = rb_hash_aref2(v_options, "timeout");
|
883
1046
|
|
884
|
-
|
1047
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
885
1048
|
|
886
1049
|
if(!NIL_P(v_output))
|
887
1050
|
initmsg.sinit_num_ostreams = NUM2INT(v_output);
|
@@ -895,15 +1058,15 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
895
1058
|
if(!NIL_P(v_timeout))
|
896
1059
|
initmsg.sinit_max_init_timeo = NUM2INT(v_timeout);
|
897
1060
|
|
898
|
-
if(setsockopt(
|
1061
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)) < 0)
|
899
1062
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
900
1063
|
|
901
1064
|
return self;
|
902
1065
|
}
|
903
1066
|
|
904
1067
|
/*
|
905
|
-
* Subscribe to various notification
|
906
|
-
* data that the socket may receive. The possible notification
|
1068
|
+
* Subscribe to various notification type events, which will generate additional
|
1069
|
+
* data that the socket may receive. The possible notification type events are
|
907
1070
|
* as follows:
|
908
1071
|
*
|
909
1072
|
* :association
|
@@ -919,7 +1082,7 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
919
1082
|
* - The peer has sent a shutdown to the local endpoint.
|
920
1083
|
*
|
921
1084
|
* :data_io
|
922
|
-
* - Message data was received.
|
1085
|
+
* - Message data was received. You will want to subscribe to this in most cases.
|
923
1086
|
*
|
924
1087
|
* Others:
|
925
1088
|
*
|
@@ -932,21 +1095,21 @@ static VALUE rsctp_set_initmsg(VALUE self, VALUE v_options){
|
|
932
1095
|
* :sender_dry
|
933
1096
|
* :peer_error
|
934
1097
|
*
|
935
|
-
* By default only data_io is subscribed to.
|
936
|
-
*
|
937
1098
|
* Example:
|
938
1099
|
*
|
939
1100
|
* socket = SCTP::Socket.new
|
940
1101
|
*
|
941
1102
|
* socket.bind(:port => port, :addresses => ['127.0.0.1'])
|
942
|
-
* socket.subscribe(:shutdown => true, :send_failure => true)
|
1103
|
+
* socket.subscribe(:data_io => true, :shutdown => true, :send_failure => true)
|
943
1104
|
*/
|
944
1105
|
static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
945
|
-
int
|
1106
|
+
int fileno;
|
946
1107
|
struct sctp_event_subscribe events;
|
947
1108
|
|
948
1109
|
bzero(&events, sizeof(events));
|
949
|
-
|
1110
|
+
Check_Type(v_options, T_HASH);
|
1111
|
+
|
1112
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
950
1113
|
|
951
1114
|
if(RTEST(rb_hash_aref2(v_options, "data_io")))
|
952
1115
|
events.sctp_data_io_event = 1;
|
@@ -982,7 +1145,7 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
|
982
1145
|
if(RTEST(rb_hash_aref2(v_options, "sender_dry")))
|
983
1146
|
events.sctp_sender_dry_event = 1;
|
984
1147
|
|
985
|
-
if(setsockopt(
|
1148
|
+
if(setsockopt(fileno, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)) < 0)
|
986
1149
|
rb_raise(rb_eSystemCallError, "setsockopt: %s", strerror(errno));
|
987
1150
|
|
988
1151
|
return self;
|
@@ -993,68 +1156,87 @@ static VALUE rsctp_subscribe(VALUE self, VALUE v_options){
|
|
993
1156
|
* will be used to accept incoming connection requests.
|
994
1157
|
*
|
995
1158
|
* The backlog argument defines the maximum length to which the queue of
|
996
|
-
* pending connections for sockfd may grow. The default is
|
1159
|
+
* pending connections for sockfd may grow. The default value is 128. The
|
1160
|
+
* maximum value is Socket::SOMAXCONN.
|
1161
|
+
*
|
1162
|
+
* Why a default of 128? The answer is a "best guess" compromise between
|
1163
|
+
* handling server load versus avoiding SYN flood attacks. I leave it as an
|
1164
|
+
* exercise to the programmer to adjust as desired.
|
1165
|
+
*
|
1166
|
+
* See https://tangentsoft.com/wskfaq/advanced.html#backlog if you want
|
1167
|
+
* more details on the advantages and drawbacks of various values.
|
997
1168
|
*
|
998
1169
|
* Example:
|
999
1170
|
*
|
1000
1171
|
* socket = SCTP::Socket.new
|
1001
1172
|
* socket.bind(:port => 62534, :addresses => ['127.0.0.1'])
|
1002
1173
|
* socket.listen
|
1003
|
-
*
|
1004
1174
|
*/
|
1005
1175
|
static VALUE rsctp_listen(int argc, VALUE* argv, VALUE self){
|
1006
1176
|
VALUE v_backlog;
|
1007
|
-
int backlog,
|
1177
|
+
int backlog, fileno;
|
1008
1178
|
|
1009
1179
|
rb_scan_args(argc, argv, "01", &v_backlog);
|
1010
1180
|
|
1011
1181
|
if(NIL_P(v_backlog))
|
1012
|
-
backlog =
|
1182
|
+
backlog = 128;
|
1013
1183
|
else
|
1014
1184
|
backlog = NUM2INT(v_backlog);
|
1015
1185
|
|
1016
|
-
|
1186
|
+
if(backlog > SOMAXCONN)
|
1187
|
+
rb_raise(rb_eArgError, "backlog value exceeds maximum value of: %i", SOMAXCONN);
|
1017
1188
|
|
1018
|
-
|
1019
|
-
|
1189
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1190
|
+
|
1191
|
+
if(listen(fileno, backlog) < 0)
|
1192
|
+
rb_raise(rb_eSystemCallError, "listen: %s", strerror(errno));
|
1020
1193
|
|
1021
1194
|
return self;
|
1022
1195
|
}
|
1023
1196
|
|
1024
1197
|
/*
|
1025
1198
|
* Extracts an association contained by a one-to-many socket connection into
|
1026
|
-
* a one-to-one style socket.
|
1199
|
+
* a one-to-one style socket. Returns the socket descriptor (fileno).
|
1200
|
+
*
|
1201
|
+
* Example:
|
1202
|
+
*
|
1203
|
+
* socket = SCTP::Socket.new
|
1204
|
+
* # etc...
|
1205
|
+
*
|
1206
|
+
* while true
|
1207
|
+
* info = socket.recvmsg
|
1208
|
+
* assoc_fileno = socket.peeloff(info.association_id)
|
1209
|
+
* # ... Do something with this new
|
1210
|
+
* end
|
1027
1211
|
*/
|
1028
1212
|
static VALUE rsctp_peeloff(VALUE self, VALUE v_assoc_id){
|
1029
|
-
int
|
1213
|
+
int fileno, assoc_fileno;
|
1030
1214
|
sctp_assoc_t assoc_id;
|
1031
1215
|
|
1032
|
-
|
1216
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1033
1217
|
assoc_id = NUM2INT(v_assoc_id);
|
1034
1218
|
|
1035
|
-
|
1219
|
+
assoc_fileno = sctp_peeloff(fileno, assoc_id);
|
1036
1220
|
|
1037
|
-
if(
|
1221
|
+
if(assoc_fileno < 0)
|
1038
1222
|
rb_raise(rb_eSystemCallError, "sctp_peeloff: %s", strerror(errno));
|
1039
1223
|
|
1040
|
-
|
1041
|
-
|
1042
|
-
return self;
|
1224
|
+
return INT2NUM(assoc_fileno);
|
1043
1225
|
}
|
1044
1226
|
|
1045
1227
|
static VALUE rsctp_get_default_send_params(VALUE self){
|
1046
|
-
int
|
1228
|
+
int fileno;
|
1047
1229
|
socklen_t size;
|
1048
1230
|
sctp_assoc_t assoc_id;
|
1049
1231
|
struct sctp_sndrcvinfo sndrcv;
|
1050
1232
|
|
1051
1233
|
bzero(&sndrcv, sizeof(sndrcv));
|
1052
1234
|
|
1053
|
-
|
1235
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1054
1236
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1055
1237
|
size = sizeof(struct sctp_sndrcvinfo);
|
1056
1238
|
|
1057
|
-
if(sctp_opt_info(
|
1239
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_DEFAULT_SEND_PARAM, (void*)&sndrcv, &size) < 0)
|
1058
1240
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1059
1241
|
|
1060
1242
|
return rb_struct_new(
|
@@ -1072,18 +1254,18 @@ static VALUE rsctp_get_default_send_params(VALUE self){
|
|
1072
1254
|
}
|
1073
1255
|
|
1074
1256
|
static VALUE rsctp_get_association_info(VALUE self){
|
1075
|
-
int
|
1257
|
+
int fileno;
|
1076
1258
|
socklen_t size;
|
1077
1259
|
sctp_assoc_t assoc_id;
|
1078
1260
|
struct sctp_assocparams assoc;
|
1079
1261
|
|
1080
1262
|
bzero(&assoc, sizeof(assoc));
|
1081
1263
|
|
1082
|
-
|
1264
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1083
1265
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1084
1266
|
size = sizeof(struct sctp_assocparams);
|
1085
1267
|
|
1086
|
-
if(sctp_opt_info(
|
1268
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_ASSOCINFO, (void*)&assoc, &size) < 0)
|
1087
1269
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1088
1270
|
|
1089
1271
|
return rb_struct_new(
|
@@ -1098,10 +1280,10 @@ static VALUE rsctp_get_association_info(VALUE self){
|
|
1098
1280
|
}
|
1099
1281
|
|
1100
1282
|
static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
|
1101
|
-
int how,
|
1283
|
+
int how, fileno;
|
1102
1284
|
VALUE v_how;
|
1103
1285
|
|
1104
|
-
|
1286
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1105
1287
|
|
1106
1288
|
rb_scan_args(argc, argv, "01", &v_how);
|
1107
1289
|
|
@@ -1113,25 +1295,25 @@ static VALUE rsctp_shutdown(int argc, VALUE* argv, VALUE self){
|
|
1113
1295
|
how = NUM2INT(v_how);
|
1114
1296
|
}
|
1115
1297
|
|
1116
|
-
if(shutdown(
|
1298
|
+
if(shutdown(fileno, how) < 0)
|
1117
1299
|
rb_raise(rb_eSystemCallError, "shutdown: %s", strerror(errno));
|
1118
1300
|
|
1119
1301
|
return self;
|
1120
1302
|
}
|
1121
1303
|
|
1122
1304
|
static VALUE rsctp_get_retransmission_info(VALUE self){
|
1123
|
-
int
|
1305
|
+
int fileno;
|
1124
1306
|
socklen_t size;
|
1125
1307
|
sctp_assoc_t assoc_id;
|
1126
1308
|
struct sctp_rtoinfo rto;
|
1127
1309
|
|
1128
1310
|
bzero(&rto, sizeof(rto));
|
1129
1311
|
|
1130
|
-
|
1312
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1131
1313
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1132
1314
|
size = sizeof(struct sctp_rtoinfo);
|
1133
1315
|
|
1134
|
-
if(sctp_opt_info(
|
1316
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_RTOINFO, (void*)&rto, &size) < 0)
|
1135
1317
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1136
1318
|
|
1137
1319
|
return rb_struct_new(
|
@@ -1143,8 +1325,29 @@ static VALUE rsctp_get_retransmission_info(VALUE self){
|
|
1143
1325
|
);
|
1144
1326
|
}
|
1145
1327
|
|
1328
|
+
/*
|
1329
|
+
* Get the status of a connected socket.
|
1330
|
+
*
|
1331
|
+
* Example:
|
1332
|
+
*
|
1333
|
+
* socket = SCTP::Socket.new
|
1334
|
+
* socket.connect(...)
|
1335
|
+
* socket.get_status
|
1336
|
+
*
|
1337
|
+
* Returns a Struct::Status object, which contains the following fields:
|
1338
|
+
*
|
1339
|
+
* * association_id
|
1340
|
+
* * state
|
1341
|
+
* * receive_window
|
1342
|
+
* * unacknowledged_data
|
1343
|
+
* * pending_data
|
1344
|
+
* * inbound_streams
|
1345
|
+
* * outbound_streams
|
1346
|
+
* * fragmentation_point
|
1347
|
+
* * primary (IP)
|
1348
|
+
*/
|
1146
1349
|
static VALUE rsctp_get_status(VALUE self){
|
1147
|
-
int
|
1350
|
+
int fileno;
|
1148
1351
|
socklen_t size;
|
1149
1352
|
sctp_assoc_t assoc_id;
|
1150
1353
|
struct sctp_status status;
|
@@ -1153,11 +1356,11 @@ static VALUE rsctp_get_status(VALUE self){
|
|
1153
1356
|
|
1154
1357
|
bzero(&status, sizeof(status));
|
1155
1358
|
|
1156
|
-
|
1359
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1157
1360
|
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1158
1361
|
size = sizeof(struct sctp_status);
|
1159
1362
|
|
1160
|
-
if(sctp_opt_info(
|
1363
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_STATUS, (void*)&status, &size) < 0)
|
1161
1364
|
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1162
1365
|
|
1163
1366
|
spinfo = &status.sstat_primary;
|
@@ -1186,7 +1389,40 @@ static VALUE rsctp_get_status(VALUE self){
|
|
1186
1389
|
);
|
1187
1390
|
}
|
1188
1391
|
|
1189
|
-
|
1392
|
+
static VALUE rsctp_get_subscriptions(VALUE self){
|
1393
|
+
int fileno;
|
1394
|
+
socklen_t size;
|
1395
|
+
sctp_assoc_t assoc_id;
|
1396
|
+
struct sctp_event_subscribe events;
|
1397
|
+
|
1398
|
+
bzero(&events, sizeof(events));
|
1399
|
+
|
1400
|
+
fileno = NUM2INT(rb_iv_get(self, "@fileno"));
|
1401
|
+
assoc_id = NUM2INT(rb_iv_get(self, "@association_id"));
|
1402
|
+
size = sizeof(struct sctp_event_subscribe);
|
1403
|
+
|
1404
|
+
if(sctp_opt_info(fileno, assoc_id, SCTP_EVENTS, (void*)&events, &size) < 0)
|
1405
|
+
rb_raise(rb_eSystemCallError, "sctp_opt_info: %s", strerror(errno));
|
1406
|
+
|
1407
|
+
return rb_struct_new(v_sctp_event_subscribe_struct,
|
1408
|
+
(events.sctp_data_io_event ? Qtrue : Qfalse),
|
1409
|
+
(events.sctp_association_event ? Qtrue : Qfalse),
|
1410
|
+
(events.sctp_address_event ? Qtrue : Qfalse),
|
1411
|
+
(events.sctp_send_failure_event ? Qtrue : Qfalse),
|
1412
|
+
(events.sctp_peer_error_event ? Qtrue : Qfalse),
|
1413
|
+
(events.sctp_shutdown_event ? Qtrue : Qfalse),
|
1414
|
+
(events.sctp_partial_delivery_event ? Qtrue : Qfalse),
|
1415
|
+
(events.sctp_adaptation_layer_event ? Qtrue : Qfalse),
|
1416
|
+
(events.sctp_authentication_event ? Qtrue : Qfalse),
|
1417
|
+
(events.sctp_sender_dry_event ? Qtrue : Qfalse),
|
1418
|
+
(events.sctp_stream_reset_event ? Qtrue : Qfalse),
|
1419
|
+
(events.sctp_assoc_reset_event ? Qtrue : Qfalse),
|
1420
|
+
(events.sctp_stream_change_event ? Qtrue : Qfalse),
|
1421
|
+
(events.sctp_send_failure_event_event ? Qtrue : Qfalse)
|
1422
|
+
);
|
1423
|
+
}
|
1424
|
+
|
1425
|
+
void Init_socket(void){
|
1190
1426
|
mSCTP = rb_define_module("SCTP");
|
1191
1427
|
cSocket = rb_define_class_under(mSCTP, "Socket", rb_cObject);
|
1192
1428
|
|
@@ -1258,19 +1494,32 @@ void Init_socket(){
|
|
1258
1494
|
"ttl", "tsn", "cumtsn", "association_id", NULL
|
1259
1495
|
);
|
1260
1496
|
|
1497
|
+
v_sctp_event_subscribe_struct = rb_struct_define(
|
1498
|
+
"EventSubscriptions", "data_io", "association", "address", "send_failure",
|
1499
|
+
"peer_error", "shutdown", "partial_delivery", "adaptation_layer",
|
1500
|
+
"authentication", "sender_dry", "stream_reset", "assoc_reset",
|
1501
|
+
"stream_change", "send_failure_event", NULL
|
1502
|
+
);
|
1503
|
+
|
1504
|
+
v_sctp_receive_info_struct = rb_struct_define(
|
1505
|
+
"ReceiveInfo", "message", "sid", "ssn", "flags", "ppid", "tsn",
|
1506
|
+
"cumtsn", "context", "assocation_id", NULL
|
1507
|
+
);
|
1508
|
+
|
1261
1509
|
rb_define_method(cSocket, "initialize", rsctp_init, -1);
|
1262
1510
|
|
1263
|
-
rb_define_method(cSocket, "
|
1511
|
+
rb_define_method(cSocket, "bindx", rsctp_bindx, -1);
|
1264
1512
|
rb_define_method(cSocket, "close", rsctp_close, 0);
|
1265
|
-
rb_define_method(cSocket, "
|
1266
|
-
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames,
|
1267
|
-
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames,
|
1513
|
+
rb_define_method(cSocket, "connectx", rsctp_connectx, -1);
|
1514
|
+
rb_define_method(cSocket, "getpeernames", rsctp_getpeernames, -1);
|
1515
|
+
rb_define_method(cSocket, "getlocalnames", rsctp_getlocalnames, -1);
|
1268
1516
|
rb_define_method(cSocket, "get_status", rsctp_get_status, 0);
|
1269
1517
|
rb_define_method(cSocket, "get_default_send_params", rsctp_get_default_send_params, 0);
|
1270
1518
|
rb_define_method(cSocket, "get_retransmission_info", rsctp_get_retransmission_info, 0);
|
1271
1519
|
rb_define_method(cSocket, "get_association_info", rsctp_get_association_info, 0);
|
1520
|
+
rb_define_method(cSocket, "get_subscriptions", rsctp_get_subscriptions, 0);
|
1272
1521
|
rb_define_method(cSocket, "listen", rsctp_listen, -1);
|
1273
|
-
rb_define_method(cSocket, "peeloff
|
1522
|
+
rb_define_method(cSocket, "peeloff", rsctp_peeloff, 1);
|
1274
1523
|
rb_define_method(cSocket, "recvmsg", rsctp_recvmsg, -1);
|
1275
1524
|
rb_define_method(cSocket, "send", rsctp_send, 1);
|
1276
1525
|
|
@@ -1278,6 +1527,10 @@ void Init_socket(){
|
|
1278
1527
|
rb_define_method(cSocket, "sendv", rsctp_sendv, 1);
|
1279
1528
|
#endif
|
1280
1529
|
|
1530
|
+
#ifdef HAVE_SCTP_RECVV
|
1531
|
+
rb_define_method(cSocket, "recvv", rsctp_recvv, -1);
|
1532
|
+
#endif
|
1533
|
+
|
1281
1534
|
rb_define_method(cSocket, "sendmsg", rsctp_sendmsg, 1);
|
1282
1535
|
rb_define_method(cSocket, "set_initmsg", rsctp_set_initmsg, 1);
|
1283
1536
|
rb_define_method(cSocket, "shutdown", rsctp_shutdown, -1);
|
@@ -1285,12 +1538,12 @@ void Init_socket(){
|
|
1285
1538
|
|
1286
1539
|
rb_define_attr(cSocket, "domain", 1, 1);
|
1287
1540
|
rb_define_attr(cSocket, "type", 1, 1);
|
1288
|
-
rb_define_attr(cSocket, "
|
1541
|
+
rb_define_attr(cSocket, "fileno", 1, 1);
|
1289
1542
|
rb_define_attr(cSocket, "association_id", 1, 1);
|
1290
1543
|
rb_define_attr(cSocket, "port", 1, 1);
|
1291
1544
|
|
1292
|
-
/* 0.0.
|
1293
|
-
rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.
|
1545
|
+
/* 0.0.7: The version of this library */
|
1546
|
+
rb_define_const(cSocket, "VERSION", rb_str_new2("0.0.7"));
|
1294
1547
|
|
1295
1548
|
/* send flags */
|
1296
1549
|
|
@@ -1322,4 +1575,9 @@ void Init_socket(){
|
|
1322
1575
|
rb_define_const(cSocket, "SCTP_SHUTDOWN_SENT", INT2NUM(SCTP_SHUTDOWN_SENT));
|
1323
1576
|
rb_define_const(cSocket, "SCTP_SHUTDOWN_RECEIVED", INT2NUM(SCTP_SHUTDOWN_RECEIVED));
|
1324
1577
|
rb_define_const(cSocket, "SCTP_SHUTDOWN_ACK_SENT", INT2NUM(SCTP_SHUTDOWN_ACK_SENT));
|
1578
|
+
|
1579
|
+
// BINDING //
|
1580
|
+
|
1581
|
+
rb_define_const(cSocket, "SCTP_BINDX_ADD_ADDR", INT2NUM(SCTP_BINDX_ADD_ADDR));
|
1582
|
+
rb_define_const(cSocket, "SCTP_BINDX_REM_ADDR", INT2NUM(SCTP_BINDX_REM_ADDR));
|
1325
1583
|
}
|
data/sctp-socket.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = 'sctp-socket'
|
3
|
-
spec.version = '0.0.
|
3
|
+
spec.version = '0.0.7'
|
4
4
|
spec.author = 'Daniel Berger'
|
5
5
|
spec.email = 'djberg96@gmail.com'
|
6
6
|
spec.summary = 'Ruby bindings for SCTP sockets'
|
@@ -19,6 +19,16 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.add_development_dependency 'rake-compiler', '~> 1.1'
|
20
20
|
spec.add_development_dependency 'rspec', '~> 3.9'
|
21
21
|
|
22
|
+
spec.metadata = {
|
23
|
+
'homepage_uri' => 'https://github.com/djberg96/sctp-socket',
|
24
|
+
'bug_tracker_uri' => 'https://github.com/djberg96/sctp-socket/issues',
|
25
|
+
'changelog_uri' => 'https://github.com/djberg96/sctp-socket/blob/main/CHANGES.md',
|
26
|
+
'documentation_uri' => 'https://github.com/djberg96/sctp-socket/wiki',
|
27
|
+
'source_code_uri' => 'https://github.com/djberg96/sctp-socket',
|
28
|
+
'wiki_uri' => 'https://github.com/djberg96/sctp-socket/wiki',
|
29
|
+
'rubygems_mfa_required' => 'true'
|
30
|
+
}
|
31
|
+
|
22
32
|
spec.description = <<-EOF
|
23
33
|
The sctp-socket library provides Ruby bindings for SCTP sockets. is a
|
24
34
|
message oriented, reliable transport protocol with direct support for
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sctp-socket
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Berger
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
|
36
36
|
WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date:
|
38
|
+
date: 2024-05-28 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: bundler
|
@@ -103,6 +103,7 @@ extensions:
|
|
103
103
|
- ext/sctp/extconf.rb
|
104
104
|
extra_rdoc_files: []
|
105
105
|
files:
|
106
|
+
- ".github/FUNDING.yml"
|
106
107
|
- ".gitignore"
|
107
108
|
- CHANGES.md
|
108
109
|
- Gemfile
|
@@ -122,7 +123,14 @@ files:
|
|
122
123
|
homepage: https://github.com/djberg96/sctp-socket
|
123
124
|
licenses:
|
124
125
|
- Apache-2.0
|
125
|
-
metadata:
|
126
|
+
metadata:
|
127
|
+
homepage_uri: https://github.com/djberg96/sctp-socket
|
128
|
+
bug_tracker_uri: https://github.com/djberg96/sctp-socket/issues
|
129
|
+
changelog_uri: https://github.com/djberg96/sctp-socket/blob/main/CHANGES.md
|
130
|
+
documentation_uri: https://github.com/djberg96/sctp-socket/wiki
|
131
|
+
source_code_uri: https://github.com/djberg96/sctp-socket
|
132
|
+
wiki_uri: https://github.com/djberg96/sctp-socket/wiki
|
133
|
+
rubygems_mfa_required: 'true'
|
126
134
|
post_install_message:
|
127
135
|
rdoc_options: []
|
128
136
|
require_paths:
|
@@ -138,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
146
|
- !ruby/object:Gem::Version
|
139
147
|
version: '0'
|
140
148
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
149
|
+
rubygems_version: 3.4.19
|
142
150
|
signing_key:
|
143
151
|
specification_version: 4
|
144
152
|
summary: Ruby bindings for SCTP sockets
|
metadata.gz.sig
CHANGED
Binary file
|